From 212f67be889fce426f747352932b10be729e4823 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 24 Aug 2023 10:53:31 +0200 Subject: [PATCH 01/33] Setup fabricexample app --- fabricexample/.bundle/config | 2 + fabricexample/.eslintrc.js | 4 + fabricexample/.gitignore | 68 ++ fabricexample/.prettierrc.js | 7 + fabricexample/App.tsx | 35 + fabricexample/README.md | 79 ++ fabricexample/__tests__/App.test.tsx | 17 + fabricexample/android/app/build.gradle | 123 +++ fabricexample/android/app/debug.keystore | Bin 0 -> 2257 bytes fabricexample/android/app/proguard-rules.pro | 10 + .../android/app/src/debug/AndroidManifest.xml | 13 + .../com/fabricexample/ReactNativeFlipper.java | 75 ++ .../android/app/src/main/AndroidManifest.xml | 25 + .../java/com/fabricexample/MainActivity.java | 32 + .../com/fabricexample/MainApplication.java | 62 ++ .../res/drawable/rn_edit_text_material.xml | 36 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/styles.xml | 9 + .../com/fabricexample/ReactNativeFlipper.java | 20 + fabricexample/android/build.gradle | 43 + fabricexample/android/gradle.properties | 44 ++ .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + fabricexample/android/gradlew | 244 ++++++ fabricexample/android/gradlew.bat | 92 +++ fabricexample/android/settings.gradle | 4 + fabricexample/app.json | 4 + fabricexample/babel.config.js | 4 + fabricexample/index.js | 9 + fabricexample/ios/.xcode.env | 1 + fabricexample/ios/Podfile | 64 ++ fabricexample/ios/Podfile.lock | 748 ++++++++++++++++++ fabricexample/ios/_xcode.env | 11 + .../fabricexample.xcodeproj/project.pbxproj | 706 +++++++++++++++++ .../xcschemes/fabricexample.xcscheme | 88 +++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + fabricexample/ios/fabricexample/AppDelegate.h | 6 + .../ios/fabricexample/AppDelegate.mm | 26 + .../AppIcon.appiconset/Contents.json | 53 ++ .../Images.xcassets/Contents.json | 6 + fabricexample/ios/fabricexample/Info.plist | 55 ++ .../ios/fabricexample/LaunchScreen.storyboard | 47 ++ fabricexample/ios/fabricexample/main.m | 10 + .../ios/fabricexampleTests/Info.plist | 24 + .../fabricexampleTests/fabricexampleTests.m | 66 ++ fabricexample/jest.config.js | 3 + fabricexample/metro.config.js | 37 + fabricexample/package.json | 38 + fabricexample/tsconfig.json | 3 + 60 files changed, 3080 insertions(+) create mode 100644 fabricexample/.bundle/config create mode 100644 fabricexample/.eslintrc.js create mode 100644 fabricexample/.gitignore create mode 100644 fabricexample/.prettierrc.js create mode 100644 fabricexample/App.tsx create mode 100644 fabricexample/README.md create mode 100644 fabricexample/__tests__/App.test.tsx create mode 100644 fabricexample/android/app/build.gradle create mode 100644 fabricexample/android/app/debug.keystore create mode 100644 fabricexample/android/app/proguard-rules.pro create mode 100644 fabricexample/android/app/src/debug/AndroidManifest.xml create mode 100644 fabricexample/android/app/src/debug/java/com/fabricexample/ReactNativeFlipper.java create mode 100644 fabricexample/android/app/src/main/AndroidManifest.xml create mode 100644 fabricexample/android/app/src/main/java/com/fabricexample/MainActivity.java create mode 100644 fabricexample/android/app/src/main/java/com/fabricexample/MainApplication.java create mode 100644 fabricexample/android/app/src/main/res/drawable/rn_edit_text_material.xml create mode 100644 fabricexample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 fabricexample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 fabricexample/android/app/src/main/res/values/strings.xml create mode 100644 fabricexample/android/app/src/main/res/values/styles.xml create mode 100644 fabricexample/android/app/src/release/java/com/fabricexample/ReactNativeFlipper.java create mode 100644 fabricexample/android/build.gradle create mode 100644 fabricexample/android/gradle.properties create mode 100644 fabricexample/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 fabricexample/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 fabricexample/android/gradlew create mode 100644 fabricexample/android/gradlew.bat create mode 100644 fabricexample/android/settings.gradle create mode 100644 fabricexample/app.json create mode 100644 fabricexample/babel.config.js create mode 100644 fabricexample/index.js create mode 100644 fabricexample/ios/.xcode.env create mode 100644 fabricexample/ios/Podfile create mode 100644 fabricexample/ios/Podfile.lock create mode 100644 fabricexample/ios/_xcode.env create mode 100644 fabricexample/ios/fabricexample.xcodeproj/project.pbxproj create mode 100644 fabricexample/ios/fabricexample.xcodeproj/xcshareddata/xcschemes/fabricexample.xcscheme create mode 100644 fabricexample/ios/fabricexample.xcworkspace/contents.xcworkspacedata create mode 100644 fabricexample/ios/fabricexample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 fabricexample/ios/fabricexample/AppDelegate.h create mode 100644 fabricexample/ios/fabricexample/AppDelegate.mm create mode 100644 fabricexample/ios/fabricexample/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 fabricexample/ios/fabricexample/Images.xcassets/Contents.json create mode 100644 fabricexample/ios/fabricexample/Info.plist create mode 100644 fabricexample/ios/fabricexample/LaunchScreen.storyboard create mode 100644 fabricexample/ios/fabricexample/main.m create mode 100644 fabricexample/ios/fabricexampleTests/Info.plist create mode 100644 fabricexample/ios/fabricexampleTests/fabricexampleTests.m create mode 100644 fabricexample/jest.config.js create mode 100644 fabricexample/metro.config.js create mode 100644 fabricexample/package.json create mode 100644 fabricexample/tsconfig.json diff --git a/fabricexample/.bundle/config b/fabricexample/.bundle/config new file mode 100644 index 000000000..848943bb5 --- /dev/null +++ b/fabricexample/.bundle/config @@ -0,0 +1,2 @@ +BUNDLE_PATH: "vendor/bundle" +BUNDLE_FORCE_RUBY_PLATFORM: 1 diff --git a/fabricexample/.eslintrc.js b/fabricexample/.eslintrc.js new file mode 100644 index 000000000..187894b6a --- /dev/null +++ b/fabricexample/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: '@react-native', +}; diff --git a/fabricexample/.gitignore b/fabricexample/.gitignore new file mode 100644 index 000000000..e2209bbae --- /dev/null +++ b/fabricexample/.gitignore @@ -0,0 +1,68 @@ +# OSX +# +.DS_Store + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +ios/.xcode.env.local + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ +*.keystore +!debug.keystore + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/ + +**/fastlane/report.xml +**/fastlane/Preview.html +**/fastlane/screenshots +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +/ios/Pods/ +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* + +# testing +/coverage + +.env \ No newline at end of file diff --git a/fabricexample/.prettierrc.js b/fabricexample/.prettierrc.js new file mode 100644 index 000000000..2b540746a --- /dev/null +++ b/fabricexample/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + arrowParens: 'avoid', + bracketSameLine: true, + bracketSpacing: false, + singleQuote: true, + trailingComma: 'all', +}; diff --git a/fabricexample/App.tsx b/fabricexample/App.tsx new file mode 100644 index 000000000..aacf879ba --- /dev/null +++ b/fabricexample/App.tsx @@ -0,0 +1,35 @@ +// @ts-ignore +import {ACCESS_TOKEN} from '@env'; + +import React from 'react'; +import {StyleSheet, View} from 'react-native'; +import Mapbox from '@rnmapbox/maps'; + +Mapbox.setAccessToken(ACCESS_TOKEN); + +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, + }, +}); diff --git a/fabricexample/README.md b/fabricexample/README.md new file mode 100644 index 000000000..12470c30e --- /dev/null +++ b/fabricexample/README.md @@ -0,0 +1,79 @@ +This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). + +# Getting Started + +>**Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. + +## Step 1: Start the Metro Server + +First, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native. + +To start Metro, run the following command from the _root_ of your React Native project: + +```bash +# using npm +npm start + +# OR using Yarn +yarn start +``` + +## Step 2: Start your Application + +Let Metro Bundler run in its _own_ terminal. Open a _new_ terminal from the _root_ of your React Native project. Run the following command to start your _Android_ or _iOS_ app: + +### For Android + +```bash +# using npm +npm run android + +# OR using Yarn +yarn android +``` + +### For iOS + +```bash +# using npm +npm run ios + +# OR using Yarn +yarn ios +``` + +If everything is set up _correctly_, you should see your new app running in your _Android Emulator_ or _iOS Simulator_ shortly provided you have set up your emulator/simulator correctly. + +This is one way to run your app — you can also run it directly from within Android Studio and Xcode respectively. + +## Step 3: Modifying your App + +Now that you have successfully run the app, let's modify it. + +1. Open `App.tsx` in your text editor of choice and edit some lines. +2. For **Android**: Press the R key twice or select **"Reload"** from the **Developer Menu** (Ctrl + M (on Window and Linux) or Cmd ⌘ + M (on macOS)) to see your changes! + + For **iOS**: Hit Cmd ⌘ + R in your iOS Simulator to reload the app and see your changes! + +## Congratulations! :tada: + +You've successfully run and modified your React Native App. :partying_face: + +### Now what? + +- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). +- If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started). + +# Troubleshooting + +If you can't get this to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. + +# Learn More + +To learn more about React Native, take a look at the following resources: + +- [React Native Website](https://reactnative.dev) - learn more about React Native. +- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. +- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. +- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. +- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. diff --git a/fabricexample/__tests__/App.test.tsx b/fabricexample/__tests__/App.test.tsx new file mode 100644 index 000000000..3413ac1c4 --- /dev/null +++ b/fabricexample/__tests__/App.test.tsx @@ -0,0 +1,17 @@ +/** + * @format + */ + +import 'react-native'; +import React from 'react'; +import App from '../App'; + +// Note: import explicitly to use the types shiped with jest. +import {it} from '@jest/globals'; + +// Note: test renderer must be required after react-native. +import renderer from 'react-test-renderer'; + +it('renders correctly', () => { + renderer.create(); +}); diff --git a/fabricexample/android/app/build.gradle b/fabricexample/android/app/build.gradle new file mode 100644 index 000000000..61ea4648a --- /dev/null +++ b/fabricexample/android/app/build.gradle @@ -0,0 +1,123 @@ +apply plugin: "com.android.application" +apply plugin: "com.facebook.react" + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '..' + // root = file("../") + // The folder where the react-native NPM package is. Default is ../node_modules/react-native + // reactNativeDir = file("../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen + // codegenDir = file("../node_modules/@react-native/codegen") + // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js + // cliFile = file("../node_modules/react-native/cli.js") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + // + // The command to run when bundling. By default is 'bundle' + // bundleCommand = "ram-bundle" + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] +} + +/** + * Set this to true to Run Proguard on Release builds to minify the Java bytecode. + */ +def enableProguardInReleaseBuilds = false + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'org.webkit:android-jsc:+' + +android { + ndkVersion rootProject.ext.ndkVersion + + compileSdkVersion rootProject.ext.compileSdkVersion + + namespace "com.fabricexample" + defaultConfig { + applicationId "com.fabricexample" + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + minifyEnabled enableProguardInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") + debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { + exclude group:'com.squareup.okhttp3', module:'okhttp' + } + + debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} + +apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/fabricexample/android/app/debug.keystore b/fabricexample/android/app/debug.keystore new file mode 100644 index 0000000000000000000000000000000000000000..364e105ed39fbfd62001429a68140672b06ec0de GIT binary patch literal 2257 zcmchYXEfYt8;7T1^dLH$VOTZ%2NOdOH5j5LYLtZ0q7x-V8_6gU5)#7dkq{HTmsfNq zB3ZqcAxeY^G10@?efK?Q&)M(qInVv!xjx+IKEL}p*K@LYvIzo#AZG>st5|P)KF1_Z;y){W{<7K{nl!CPuE z_^(!C(Ol0n8 zK13*rzAtW>(wULKPRYLd7G18F8#1P`V*9`(Poj26eOXYyBVZPno~Cvvhx7vPjAuZo zF?VD!zB~QG(!zbw#qsxT8%BSpqMZ4f70ZPn-3y$L8{EVbbN9$H`B&Z1quk9tgp5FM zuxp3pJ0b8u|3+#5bkJ4SRnCF2l7#DyLYXYY8*?OuAwK4E6J{0N=O3QNVzQ$L#FKkR zi-c@&!nDvezOV$i$Lr}iF$XEcwnybQ6WZrMKuw8gCL^U#D;q3t&HpTbqyD%vG=TeDlzCT~MXUPC|Leb-Uk+ z=vnMd(|>ld?Fh>V8poP;q;;nc@en$|rnP0ytzD&fFkCeUE^kG9Kx4wUh!!rpjwKDP zyw_e|a^x_w3E zP}}@$g>*LLJ4i0`Gx)qltL}@;mDv}D*xR^oeWcWdPkW@Uu)B^X&4W1$p6}ze!zudJ zyiLg@uggoMIArBr*27EZV7djDg@W1MaL+rcZ-lrANJQ%%>u8)ZMWU@R2qtnmG(acP z0d_^!t>}5W zpT`*2NR+0+SpTHb+6Js4b;%LJB;B_-ChhnU5py}iJtku*hm5F0!iql8Hrpcy1aYbT z1*dKC5ua6pMX@@iONI?Hpr%h;&YaXp9n!ND7-=a%BD7v&g zOO41M6EbE24mJ#S$Ui0-brR5ML%@|ndz^)YLMMV1atna{Fw<;TF@>d&F|!Z>8eg>>hkFrV)W+uv=`^F9^e zzzM2*oOjT9%gLoub%(R57p-`TXFe#oh1_{&N-YN z<}artH|m=d8TQuKSWE)Z%puU|g|^^NFwC#N=@dPhasyYjoy(fdEVfKR@cXKHZV-`06HsP`|Ftx;8(YD$fFXumLWbGnu$GMqRncXYY9mwz9$ap zQtfZB^_BeNYITh^hA7+(XNFox5WMeG_LtJ%*Q}$8VKDI_p8^pqX)}NMb`0e|wgF7D zuQACY_Ua<1ri{;Jwt@_1sW9zzdgnyh_O#8y+C;LcZq6=4e^cs6KvmK@$vVpKFGbQ= z$)Eux5C|Fx;Gtmv9^#Y-g@7Rt7*eLp5n!gJmn7&B_L$G?NCN`AP>cXQEz}%F%K;vUs{+l4Q{}eWW;ATe2 zqvXzxoIDy(u;F2q1JH7Sf;{jy_j})F+cKlIOmNfjBGHoG^CN zM|Ho&&X|L-36f}Q-obEACz`sI%2f&k>z5c$2TyTSj~vmO)BW~+N^kt`Jt@R|s!){H ze1_eCrlNaPkJQhL$WG&iRvF*YG=gXd1IyYQ9ew|iYn7r~g!wOnw;@n42>enAxBv*A zEmV*N#sxdicyNM=A4|yaOC5MByts}s_Hpfj|y<6G=o=!3S@eIFKDdpR7|FY>L&Wat&oW&cm&X~ z5Bt>Fcq(fgnvlvLSYg&o6>&fY`ODg4`V^lWWD=%oJ#Kbad2u~! zLECFS*??>|vDsNR&pH=Ze0Eo`sC_G`OjoEKVHY|wmwlX&(XBE<@sx3Hd^gtd-fNwUHsylg06p`U2y_={u}Bc + + + + + + + + diff --git a/fabricexample/android/app/src/debug/java/com/fabricexample/ReactNativeFlipper.java b/fabricexample/android/app/src/debug/java/com/fabricexample/ReactNativeFlipper.java new file mode 100644 index 000000000..e828f79dd --- /dev/null +++ b/fabricexample/android/app/src/debug/java/com/fabricexample/ReactNativeFlipper.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.fabricexample; + +import android.content.Context; +import com.facebook.flipper.android.AndroidFlipperClient; +import com.facebook.flipper.android.utils.FlipperUtils; +import com.facebook.flipper.core.FlipperClient; +import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; +import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; +import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; +import com.facebook.flipper.plugins.inspector.DescriptorMapping; +import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; +import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; +import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; +import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; +import com.facebook.react.ReactInstanceEventListener; +import com.facebook.react.ReactInstanceManager; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.modules.network.NetworkingModule; +import okhttp3.OkHttpClient; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the debug + * flavor of it. Here you can add your own plugins and customize the Flipper setup. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + if (FlipperUtils.shouldEnableFlipper(context)) { + final FlipperClient client = AndroidFlipperClient.getInstance(context); + + client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); + client.addPlugin(new DatabasesFlipperPlugin(context)); + client.addPlugin(new SharedPreferencesFlipperPlugin(context)); + client.addPlugin(CrashReporterPlugin.getInstance()); + + NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); + NetworkingModule.setCustomClientBuilder( + new NetworkingModule.CustomClientBuilder() { + @Override + public void apply(OkHttpClient.Builder builder) { + builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); + } + }); + client.addPlugin(networkFlipperPlugin); + client.start(); + + // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized + // Hence we run if after all native modules have been initialized + ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); + if (reactContext == null) { + reactInstanceManager.addReactInstanceEventListener( + new ReactInstanceEventListener() { + @Override + public void onReactContextInitialized(ReactContext reactContext) { + reactInstanceManager.removeReactInstanceEventListener(this); + reactContext.runOnNativeModulesQueueThread( + new Runnable() { + @Override + public void run() { + client.addPlugin(new FrescoFlipperPlugin()); + } + }); + } + }); + } else { + client.addPlugin(new FrescoFlipperPlugin()); + } + } + } +} diff --git a/fabricexample/android/app/src/main/AndroidManifest.xml b/fabricexample/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..4122f36a5 --- /dev/null +++ b/fabricexample/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + diff --git a/fabricexample/android/app/src/main/java/com/fabricexample/MainActivity.java b/fabricexample/android/app/src/main/java/com/fabricexample/MainActivity.java new file mode 100644 index 000000000..e3c1bb42e --- /dev/null +++ b/fabricexample/android/app/src/main/java/com/fabricexample/MainActivity.java @@ -0,0 +1,32 @@ +package com.fabricexample; + +import com.facebook.react.ReactActivity; +import com.facebook.react.ReactActivityDelegate; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactActivityDelegate; + +public class MainActivity extends ReactActivity { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + @Override + protected String getMainComponentName() { + return "fabricexample"; + } + + /** + * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link + * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React + * (aka React 18) with two boolean flags. + */ + @Override + protected ReactActivityDelegate createReactActivityDelegate() { + return new DefaultReactActivityDelegate( + this, + getMainComponentName(), + // If you opted-in for the New Architecture, we enable the Fabric Renderer. + DefaultNewArchitectureEntryPoint.getFabricEnabled()); + } +} diff --git a/fabricexample/android/app/src/main/java/com/fabricexample/MainApplication.java b/fabricexample/android/app/src/main/java/com/fabricexample/MainApplication.java new file mode 100644 index 000000000..8c188bd8c --- /dev/null +++ b/fabricexample/android/app/src/main/java/com/fabricexample/MainApplication.java @@ -0,0 +1,62 @@ +package com.fabricexample; + +import android.app.Application; +import com.facebook.react.PackageList; +import com.facebook.react.ReactApplication; +import com.facebook.react.ReactNativeHost; +import com.facebook.react.ReactPackage; +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; +import com.facebook.react.defaults.DefaultReactNativeHost; +import com.facebook.soloader.SoLoader; +import java.util.List; + +public class MainApplication extends Application implements ReactApplication { + + private final ReactNativeHost mReactNativeHost = + new DefaultReactNativeHost(this) { + @Override + public boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; + } + + @Override + protected List getPackages() { + @SuppressWarnings("UnnecessaryLocalVariable") + List packages = new PackageList(this).getPackages(); + // Packages that cannot be autolinked yet can be added manually here, for example: + // packages.add(new MyReactNativePackage()); + return packages; + } + + @Override + protected String getJSMainModuleName() { + return "index"; + } + + @Override + protected boolean isNewArchEnabled() { + return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + } + + @Override + protected Boolean isHermesEnabled() { + return BuildConfig.IS_HERMES_ENABLED; + } + }; + + @Override + public ReactNativeHost getReactNativeHost() { + return mReactNativeHost; + } + + @Override + public void onCreate() { + super.onCreate(); + SoLoader.init(this, /* native exopackage */ false); + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + DefaultNewArchitectureEntryPoint.load(); + } + ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); + } +} diff --git a/fabricexample/android/app/src/main/res/drawable/rn_edit_text_material.xml b/fabricexample/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 000000000..73b37e4d9 --- /dev/null +++ b/fabricexample/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + diff --git a/fabricexample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/fabricexample/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a2f5908281d070150700378b64a84c7db1f97aa1 GIT binary patch literal 3056 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 axPAxe%7rDusX+w*00006jj zwslyNbxW4-gAj;v!J{u#G1>?8h`uw{1?o<0nB+tYjKOW@kQM}bUbgE7^CRD4K zgurXDRXWsX-Q$uVZ0o5KpKdOl5?!YGV|1Cict&~YiG*r%TU43m2Hf99&})mPEvepe z0_$L1e8*kL@h2~YPCajw6Kkw%Bh1Pp)6B|t06|1rR3xRYjBxjSEUmZk@7wX+2&-~! z!V&EdUw!o7hqZI=T4a)^N1D|a=2scW6oZU|Q=}_)gz4pu#43{muRW1cW2WC&m-ik? zskL0dHaVZ5X4PN*v4ZEAB9m;^6r-#eJH?TnU#SN&MO`Aj%)ybFYE+Pf8Vg^T3ybTl zu50EU=3Q60vA7xg@YQ$UKD-7(jf%}8gWS$_9%)wD1O2xB!_VxzcJdN!_qQ9j8#o^Kb$2+XTKxM8p>Ve{O8LcI(e2O zeg{tPSvIFaM+_Ivk&^FEk!WiV^;s?v8fmLglKG<7EO3ezShZ_0J-`(fM;C#i5~B@w zzx;4Hu{-SKq1{ftxbjc(dX3rj46zWzu02-kR>tAoFYDaylWMJ`>FO2QR%cfi+*^9A z54;@nFhVJEQ{88Q7n&mUvLn33icX`a355bQ=TDRS4Uud|cnpZ?a5X|cXgeBhYN7btgj zfrwP+iKdz4?L7PUDFA_HqCI~GMy`trF@g!KZ#+y6U%p5#-nm5{bUh>vhr^77p~ zq~UTK6@uhDVAQcL4g#8p-`vS4CnD9M_USvfi(M-;7nXjlk)~pr>zOI`{;$VXt;?VTNcCePv4 zgZm`^)VCx8{D=H2c!%Y*Sj3qbx z3Bcvv7qRAl|BGZCts{+>FZrE;#w(Yo2zD#>s3a*Bm!6{}vF_;i)6sl_+)pUj?b%BL!T1ELx|Q*Gi=7{Z_>n0I(uv>N^kh|~nJfab z-B6Q6i-x>YYa_42Hv&m>NNuPj31wOaHZ2`_8f~BtbXc@`9CZpHzaE@9sme%_D-HH! z_+C&VZ5tjE65?}X&u-D4AHRJ|7M{hR!}PYPpANP?7wnur`Z(&LFwzUmDz}m6%m#_` zN1ihq8f|zZ&zTL92M2b-hMpPyjp;j(qwgP9x)qI?EZx@<$g#>i7(MC}@*J1VGXm6J ztz1=RK@?%Qz^vmWNydd0K7oyrXw`TLb`z;fP6eV|NZ@9kKH zIyMqzZ9Y_)PZnC#UgW6&o7RiGXSCtSQvnrvJ07P9WCuE5TE27za*L6r1qX7pIDFiP znSaHYJF8sl^n0|3j!i{?fD%?fpQ8-}VX4%STy1t@8)G-8??Fy}j}~2_iJ79Y<9BW~ z!~)T{3Y|lwcVD5s4z^GP5M=~t`V?*Wng7gTvC9%p>ErZpM)pQVx57>AIcf1j4QFg^w>YYB%MypIj2syoXw9$K!N8%s=iPIw!LE-+6v6*Rm zvCqdN&kwI+@pEX0FTb&P)ujD9Td-sLBVV=A$;?RiFOROnT^LC^+PZR*u<3yl z7b%>viF-e48L=c`4Yhgb^U=+w7snP$R-gzx379%&q-0#fsMgvQlo>14~`1YOv{?^ z*^VYyiSJO8fE65P0FORgqSz#mi#9@40VO@TaPOT7pJq3WTK9*n;Niogu+4zte1FUa zyN7rIFbaQxeK{^RC3Iu@_J~ii&CvyWn^W}4wpexHwV9>GKO$zR3a&*L9&AgL=QfA$ z+G-YMq;1D{;N38`jTdN}Pw77sDCR|$2s+->;9gh-ObE_muwxq>sEpX)ywtgCHKIATY}p&%F4bRV>R9rYpeWbT(xnE7}?(HDXFgNDdC^@gUdK& zk=MolYT3>rpR*$Ell2!`c zjrIZftl&PUxlH2EgV+3VfQy&FjhL&5*Zg&R8xrSx?WgB?YuLO-JDaP3jr*I~qiywy z`-52AwB_6L#X ztms{{yRkRfQLbsb#Ov%`)acN(OCewI3Ex__xed17hg#g4c1blx?sK}UQg%PM@N;5d zsg{y6(|`H1Xfbz@5x{1688tu7TGkzFEBhOPDdFK(H_NQIFf|(>)ltFd!WdnkrY&mp z0y@5yU2;u1_enx%+U9tyY-LNWrd4^Wi?x<^r`QbaLBngWL`HzX@G550 zrdyNjhPTknrrJn#jT0WD0Z)WJRi&3FKJ#Sa&|883%QxM-?S%4niK{~k81<(c11sLk|!_7%s zH>c$`*nP-wA8Dx-K(HE~JG_@Yxxa;J+2yr+*iVlh;2Eiw?e`D1vu6*qY1+XTe8RVu z?RV%L|Mk!wO}j^S)p4H%?G37StD0Rx{_Y00%3a+V^SyOkfV@ZuFlEc;vR9r-D>cYU&plUkXL|M%1AYBQ3DI;;hF%_X@m*cTQAMZ4+FO74@AQB{A*_HtoXT@}l=8awaa7{RHC>07s?E%G{iSeRbh z?h#NM)bP`z`zdp5lij!N*df;4+sgz&U_JEr?N9#1{+UG3^11oQUOvU4W%tD1Cie3; z4zcz0SIrK-PG0(mp9gTYr(4ngx;ieH{NLq{* z;Pd=vS6KZYPV?DLbo^)~2dTpiKVBOh?|v2XNA)li)4V6B6PA!iq#XV5eO{{vL%OmU z0z3ZE2kcEkZ`kK(g^#s)#&#Zn5zw!R93cW^4+g0D=ydf&j4o_ti<@2WbzC>{(QhCL z(=%Zb;Ax8U=sdec9pkk|cW)1Ko;gK{-575HsDZ!w@WOQ^Up)GGorc38cGxe<$8O!6 zmQ`=@;TG{FjWq(s0eBn5I~vVgoE}un8+#YuR$Asq?lobvVAO-`SBs3!&;QEKT>gZ0T)jG^Foo~J2YkV&mi-axlvC}-(J4S2 z;opuO)+FIV#}&4;wwisb>{XU+FJ~tyK7UaG@ZD^C1^brazu7Xkh5Od}&P)GufW=u# zMxOwfWJ3a^MZha>9OmQ)@!Y;v*4@+dg~s~NQ;q@hV~l>lw`P)d`4XF9rE?aEFe(JV zI>11}Ny%^CkO=VN>wCV?P!-?VdT3vWe4zBLV*?6XPqsC%n93bQXvydh0Mo+tXHO4^ zxQ{x0?CG{fmToCyYny7>*-tNh;Sh9=THLzkS~lBiV9)IKa^C~_p8MVZWAUb)Btjt< zVZ;l7?_KnLHelj>)M1|Q_%pk5b?Bod_&86o-#36xIEag%b+8JqlDy@B^*YS*1; zGYT`@5nPgt)S^6Ap@b160C4d9do0iE;wYdn_Tr(vY{MS!ja!t*Z7G=Vz-=j5Z⁣ zwiG+x#%j}{0gU~J8;<|!B1@-XaB@{KORFwrYg_8rOv({b0EO#DbeQRm;B6_9=mXGf z-x|VL{zd`)#@yN}HkCSJbjbNlE|zL3Wm9Q8HY`sV)}3%pgN>cL^67{Z;PPL(*wT8N zUjXU{@|*hvm}({wsAC=x0^ok0%UAz0;sogW{B!nDqk|JJ5x~4NfTDgP49^zeu`csl?5mY@JdQdISc zFs!E{^grmkLnUk9 zny~m)1vws@5BFI<-0Tuo2JWX(0v`W|t(wg;s--L47WTvTMz-8l#TL^=OJNRS2?_Qj z3AKT+gvbyBi#H*-tJ%tWD|>EV3wy|8qxfzS!5RW;Jpl5*zo&^UBU=fG#2}UvRyNkK zA06Dy9;K1ca@r2T>yThYgI!ont$(G{6q#2QT+00r_x0(b)gsE`lBB?2gr55gq^D3Fi&p%E(p9>U%bv zkg1Jco(RbyTX7FDHOnl7-O@ zI$AaIl?9NJKPm(WiBP`1-#CB1QzU>&hKm)fpa5DKE{2$X0hGz-0uZ?cyTk(YC!Y&| zL=1VrNERSA5NA2jq7FACfX4JfPyj5XXl1yv0>~s;eF7L2$>&oMqeTFT2m$y7FlkON z_yurD1yIOvA;5C6016pyxBznGUt0kJ&k5r#;&>Jow`r)sp9R~PmK~lz$3xH%LT*1U zJdOyABZ3!FvNoR*vN$5ykHS8f`jA4zV+|L}i1C4`B2c{R0;UdYxaU|H)2avz@ z=mEYc|2S<+(B2Tj+FkX+2D+yFI!k9lWMA61DJ{)e;lum$(;O87?vGJJe!KtK04+N_ zI*P~t@dUb>9Xh{dbyl{-ZQ(UMgz7$|QfL5XSPkskt^NgctYC#;4WcZB1@%@wy@2t3 z2z0DI7&%b$*Aw~abe?GxE`ez@+6hOh-6*8fHRV{1os$EL@}uUZeG4h1&Be`98q*7j z=3-v+lhIjfWVo12!<>%V^a6lTgW3+_#W6n|p*~==zOH7z$0{LSZk(Tpd7EaD04hnA zL;#fxS0aD{`5^&D`}>0Uq?byDD-l2=!wm_bLcUl4gc(% za1p|itVANvFF>hghAS07Im1;IK;|b*W)}VDyI;BIp2=K*yu2a)j?B|f<44NI$NbmJ z#dE0>jI$fMr&@>4kN8MLFb4&2O9fEKaQg%(QO$4_1rVQywG^CmBLh#}_7gKW3vd?| z2?1^&KWq8}8I^_S0|)MowU_pw$q@nl@Nkn$z>BQq_KA^9yaR`(R3u{{Ig;cwt z@AJ^{ODQCm^neroM9nKNUAXi9RCK`OsP_LuR0PUR(YZCCX5dNF6VzcoK&=b^r`W?ltt|*F zpkoae%ZT{C1h~EcFui~b7fF`vb<<~j_VquuUA$}QqIKYELPp#;{u?q8Dz}WAG-(3; zjrm$i%7UbyZMM(Y{>!uJ#vNB?R~B{6Htp=>e*<{fQQ5W7V(1coCWlOON!MzZxhum| ztZBQpGR z;~#ur^&PockKdV{Q6R>o`Pl{0x!DEbpZ7y9Y;*ZvE!*gU`V1W3znva{f=?WO5I&>B z&hw6}tjECtaghm5z|C#%M;Yf_*pI^};h}Vl=^r9EN=tVDj86D;C$jIJ?K7VP+00000NkvXXu0mjf D5i!M* literal 0 HcmV?d00001 diff --git a/fabricexample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/fabricexample/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..459ca609d3ae0d3943ab44cdc27feef9256dc6d7 GIT binary patch literal 7098 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 literal 0 HcmV?d00001 diff --git a/fabricexample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/fabricexample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca12fe024be86e868d14e91120a6902f8e88ac6 GIT binary patch literal 6464 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 B0*L?s literal 0 HcmV?d00001 diff --git a/fabricexample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/fabricexample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..8e19b410a1b15ff180f3dacac19395fe3046cdec GIT binary patch literal 10676 zcmV;lDNELgP)um}xpNhCM7m0FQ}4}N1loz9~lvx)@N$zJd<6*u{W9aHJztU)8d8y;?3WdPz&A7QJeFUv+{E$_OFb457DPov zKYK{O^DFs{ApSuA{FLNz6?vik@>8e5x#1eBfU?k4&SP;lt`%BTxnkw{sDSls^$yvr#7NA*&s?gZVd_>Rv*NEb*6Zkcn zTpQm5+>7kJN$=MTQ_~#;5b!%>j&UU=HX-HtFNaj*ZO3v3%R?+kD&@Hn5iL5pzkc<} z!}Vjz^MoN~xma>UAg`3?HmDQH_r$-+6~29-ynfB8BlXkvm55}{k7TadH<~V$bhW)OZXK@1)CrIKcRnSY`tG*oX}4YC&HgKz~^u7 zD?#%P?L~p~dt3#y(89y}P;ij|-Z#KC;98PvlJCjf6TQbsznsL8#78n~B_kaQl}nsm zLHr7z%-FAGd=-!e?C{q62x5i4g4hNuh)LeqTa4ynfC4h(k*e>okrBlLv;YG%yf8!6 zcN)a^5>rp^4L+myO70z(0m`D}$C(eqfV1GpzM+%$6s6$?xF>~%Gzx|$BUZ$=;f)B8 zoQUrc!zB4kT!wqSvJ=ywY-W)3364w!`U>J+49ZE`H~+{!gaM)zFV!?!H+)k8BnOj3 zGvU93auN}g?X^8c`+PFv|EH=R%m)iUN7gssWyTD~uv7prl1iRfRaCFeJUuA@$(p&K z?D+cmhxf`n9B~!?S#d*TeLb^(q~VYS$3KhjfwfMWtZx&PlTZ(i@5HJ?of_Q)0YX99 z35b?W>?=vlb6gtK1ydcF4<@aH|Hgj8r?~QNOPx(YoKT^Xn=?Q%=1uA&-G(}mXdtsT zQuKACS|@G@uBW(SY(cH%% zq+xr%bpGqOGHyw3=8K7;J&hp^g1UsyG zYT24BGeGQukP?&TlOBE2H$2oH>U#E>GtI-fmc)17uc`7FRxJ3A!c%ADN^Z^oi6tYp zjzE+a{r&jt6z^scbd(feWPVEE!lV1I4lfdLhQ|yLdx&1IEV%l1erB&H8X}3=8lIcc zCNPUis-KRbCC z20@WYl&vVEZo!fLXxXs?{|<|Z=>0^-iX;y6{DT$lSo8b|@FZM3U$+W37(A_9<)fnq zP~11?(AKlHI-Lh(`?-@S?(1{t16bc7ESX->9twFP@t8_XK$XxuSFF#R(g7H(U%XvWa zm}J>%4-suYL=gX7-_MsjD27o?I!G888fxV$koLCfOv+Da&OVTG*@(aC9lz_e>*UGS zrX6f-45hd55ya-p_O{FbHEG%Ee9~i(H-B3RZkv`0ZDn$!>MigMZX06&y3RSk-WnL-{cM1 z1TZr|rc*Xaf|_^y&YLc4KK3<@aWfge2jARbRRg1DfJ~%pV9L_@$UADw3EXC_n%p0v zQO*{=88K@W{T?$wCR#S!M!e+R$aDL~EzovN7pbOBvrk&&ASS=Z43No|jrc>}aXXO5 zrd1<|Qypq-h#J*iORN@8YRc&`17u=lqo&L&YV%p#hL%P*WfIfH%ZUC^o#`?IWWr?w zQ^?EgP7!lqlq}ZM}d*sSVz(mqeQrA_huV@M4iwXa>k+%O-ZHW44JrRxLJy zLoHTuEqw(sMcO38n*lQ6ve97<&+Y50NNmVpW{hed@5EgrWfI~ITFJ0D(<|k)ag-~cV z0@-#S9z8&EUfBL7C_53YJ$)2ix^)vhsH;Q&KDdwe{q{2oJ#~b@#Qr?YGHrh;`rz<> z)F&rNr}J@}p8^N(8hLRH`=jpeT@y z2v7WETpnG{qixxkWWyK7(3QJ)RF-$=`O^k3+oY;O;rNnl^kVc*(j(Jb_99(Dw1w;T z4K8fsKDzn|epoWT|5{~*3bCC1>nd5;@=5lApq%3>^U_gQD>5j-O@WH;uEG+4MSBjJkdgtP;JG2`S&&Sa#_w33(yyAux~lnp7>wMXzD4yy_2#Vh+7&WMkWFl9Ohq06ifTiMWIC(|1Fe(3n}U_0(+jGC_(1c@X4vzk6y`)qzH+WXtj>dhI3=)~1Oi0Omh z^vp^i61ge1rO8;F~ncj_=tk zIvnwqFB-?)jER5LdQ?Hi=Kv5dgPZx%XSjc8VLCd4yYK4E88pIi4AGWzwdmrFf6&AF zI-`N3cpnf!Klj%)afJEC-x{^po?kDKD0@>6(}1f2xkCOMS49E?+5^EenLUrqK%EANgiQdAy8BW0e}Fvw`>)CTcvBeX6ZgjWC~(KdFE9hv+M6*t z?loxF7N3yv+}r*v(>9DX;0V1TP3G)L5r}m~e)RO*pc zv#tyehrK*U7ilRPA zk!aAmm9v3`z|hH7+WJ41!*h~g<2G1sUubFoL9b?dbp>%)pHzUZ-n)Z)W(6jh>jY-3 zUq&n%9=y?`ajN7rr3`t68sL^H^MG_rUDQw2$gj4Jb8MXgAW99^EbKmu9*Pv4Rh3=;vUVF30sUrdj!_n0*+m?WCbo^8q2fo|;?vH3OFh4__< zyaqNQdP4&Q+6R)%gv|^b#b|oW*XMMKLhEgy7(3D!poW*Tk`Qn4f*HUBD@U4+eOL|4 zh+hT+hl`Hx6+v(dZi=hGf|lF9JV};bs&Bm{THmunMOu))>8UdnTYV%TFdKB!dzN+?+5S+WYI><_z_6eDC z+WvMv78tB-j%G_;_de;{^Q7!t>Khj7gp^izaCK?7PmUiHevBXbk=s8{114AjWHDj{ z_(0ZvDUl`5mu8_cWw}Ba6$W+4RbZ4H97I^qQrq9Yd$5A!1wSqDNaUXf_sQ%GF7*wX zXFhfrz!d7zZiDhtgk#HcP(aukNVacB**=V7u3*Xwp&aR_R8vnbd1PGG6$}j(F_VMA?KUK~Jd?J)TjC!h3~KL|i&IYtL40AFtv zb_DC5Vt8aT6JhF5fEI0_FM#^zCX2>a=A#}FVOKjnH_(#+q}Ggy0kU*_?=3Ifjr+H$ z0D{~ZO<8+Sll*k^U-Y6DvsCpBP|v8XH*H@U(US~mumH%)dBJRde1f|G&@1J+MvVi( zla}?vMV%}C?xRQOryKvG8`v3bs)mPaL*v7}=z1;z?uq)tAg6HwY9Ihbhu^awAJU&S zK#m{H4)PVmJ!}eqpy%MRP$Pe(&D;?N7($!Oz=8uTxRyl1Wg*V=gE z5PBge1q~I%qmY6Ol#1^O?u~P=44?CDh*GEXjSmoi`y;!_V+I2o>H!jms@u4HII9l^ z=&`W@f)v#1KQ8O!bY@+=fC3VBA@A7jQt^q~fz}*7i0(grY=jujW3=vAHS&qyN!B3* z;l=MjJrW~O7Sz5xp2Z?EtA`naLM239gw8Ub=%IHPY<00fb5 zozf%j+(s|urpUn~5r5pE7yi0taDcx4`#K81u*kwAk(cvQ$vx_F{wd}8h=eKDCE$M(iD9_QGJh zr0e(Z>QuRZ+`ff^GZPu%;bA#_^$&vsboSa6V!jmN0SV4dBKN4v`C)aESBtZV7J~U( zOc3e47Zx3Ux67y(o?#7;!=y1jxEueEF#$^c_PoxG_pq)GZLU2`d>%!3rdJjkrAK!2 z!2>jNPceo_9v)xpmu)_EgxsU9*GT^QoERVik+LSzH$Z{Ax7_GFY+!HA0MSfDyXT(k z?vob%yRiU**{7No8PKK&w77Z?8j#9IJ#hv1O^!lS%kt0n7@x79#}+R-TuINbiBfotv)O^y=kD0AkUNhrP$U_@qXE zYpkIR$Zgi=#6Os0^$m7rt1kV3&R~;r&xn%>8xzDHk!yob^vyrl^*R$4R_u5eYdHc> zk}^bkAIjLe{t{-Q8+D@9&dz9Q;o$+RGT7l8sx<~c5IBs*Dp_bAwqQRM2olfEe}Vk4 zc9Vt3hx$Z%0|;xNF=aW(Z*%CEmg_ z-riR#1Wjb9t+D^_K$%|E`_m#&XHzQ*&~vzFCzYIJB6Ieap%urgb=%UsC<9^hC4{(B z(3+*N>|JNdhT54KE$HT~okqq-teADE3Vn9^sA!>%+fb|98XIO zePvP!J8>9Ao~cC(u@>UqZhO(v+C!ob_m!fdtCwsACbR*lqtAwwQ@{hCy1%pm)*>|2 z*4U}vUNFO;Lw9~?Rw9)osm$D4f)?XmUvN$e8eWjjsm+Gr-@$~6iMgqWH+%YAV1gAu z7NbW)FU+RvtZ75ADtlW83vAW@YkP-BMr{8tV}A+L9?({@=u8(K9O&F z4CiS*&nHDa>J}36GR;VAs~I41Kfit308jVeg0#zIVj;(cr8EHqE6<OP0C9kbOl`)daY)$O<0J;;?A%Ve z&#H!_rNfB84*1o6aD2oLL(Ywd^#ZTmyK9Dlqg=at2TjDGCcH@qymjUqbf4FvGxc*ap|#6x@}Ug@+NK z6j_PV43T(wmxf+(J5kT~r++|VKw>6X0o1~R#{);Yll!>QeP1cfzTvOK0-Ndpf;nGz znqZirxrk&)Llzz-fKnnEL_I{Lt#O<8-0}IX?!m#sfdv{wY{3p7aF*=sI^w@wUdl;1 zOaQ`8mA(OjeI_2&*O_79989c3v-g+F!6OGyYBVD}5>W|JMvMsd5c6BV0+zUQBP_6V zpc@@&KR+A%>NFy5N0^}idafWHEjUnt=I<|KC5!NPqrW(T!j9Ll{*5Zxa^f&K*Ftjr zawS=CfJrKpWc85)DE8bbv=YBAz#5gkRLaSR_+g6q@-*6f>L^-JT`4CEtE*JX@Z1zF z0E&{AR0fE|??ogjZqfU3(3!I1@j9|~pd0<5UcI0vX5Z_hd1HMA@j|Yv)N2|G^GS;q zXYi@WB9s-#b)He4kH+MtvHHF`8K0kl-oxkemC0RJl}RX;os2R(GXc%6Dn>&D@rZ}- zPb!J(Btl-2B2W+9n6vkmpjV4Bl?F&viUK%NfXXmH_#u%8D2iDWAcFW0m@khVp9{N9 z7&DbP(1Gk7XhlD$GZqiugk2XTu>nJ*bAY;J1CcQR(gq#?Wq4+yGC*3wqY5A{@Bl2z z0I7yYB2tLJe5Lb|+h?DCkK5jdFd$~3g?0d0ShVgG6l4p2kXQKH?S=$M3{jLui1Y>! zz77*W+QP#K5C?de0OAUdGC-Q)A%ZOd%_kz}%W2+>L}>etfq`~pMyi$o5kJUY><4vq zdT;7z-}KnW2H$K&gE`X+Kok~5fVjY;1Q17f6amr&9##OQG7B#?nzXIwwheWiM!)a| zv^^L9r_m3B3^W^?E?~yI`Qf!(wU9Ow3)Pu3odJ?DRk8qag@-*r>fw?ty;X?M?5GeGW6VdRS@X}kbfC>Ph0tSHC!=o7> zcJP1%;)e#h-i!cg0S|z}2#|Ws1LjKvukP!X{cY{zF$mh+!rtD7tND^MV;y)-ur`c4 zFKkU>&&+tOw*1y*YwVu5X8==z0UVItNs(wyMIoAiwTI+0%@V;VuNP&ZIh92y2&-(k zMi0;exUrZe67@)CmgjR)(0ttRFy~A9c}gUif~+K|%mVQAO^-$M_Lq|w4!my^J_<}z zA?b<|Lu5*2A)0rv67|lAMLqF*s7KWjivr(f4{^A5$f4qjg zmxyepp;Y!W2-Y|f2|IZNMV_rib8+3xIZ#3BP@Ul4G|a88M6V}A)%k~vnh0%eYirwy zYwt@rDs5q5-M(vANBrvba>DMCi52-;ZT+q5*4X2*N*nu4*&?uY&0IEM1_>fN{*6zdU!wDfFIgPxZWn<9+^rhhu0i5u{>8eHa7)5yJ`s} z&wJ6fw${~r$vM*&uCCxryLOp0cDzs0u6k{{^!ivQ8f-O~8dg3KgU_SbRiA)C08Qiv zzKj+=kD{M5JWJLGV(;@P`ZkfJkBl^sz+u>GVaJz7K;+rg z!o@{r=UEY;R%DelCy0#G3URLBevOL)`* zqy;>(0F74#5KDMKCSwZ$ri&3ES$H7!lg1Z%!6v&4XYGNurEM%p9@7gz5@*`VqGLzU zLT+15_Xc^?TikPBx22wj=^SZ zs}Z0G&hW4Wh|SoR5uCl&CJhu&k`der5ui5sCU4Xu6TeIXd)x3=z%U;RBc ztv*7s+cIP7jSY}0h}ev6NdZcX;0%u}Krp$FD?Ca7=>U&BKrt%d;n#!acKLYTY21bZ zv@JUu!uL_#BXe+Yf|!Brh+$)}DSJRnnTjC}Ljoio_TWn)VmmNO0IF00kQSrrFee?R z7Bc~)&8WJ1fTFY-RVM%)WCnDP(H}A& zhBl&Y)kS8&w1q_z9gU_85|G-ofg9`TvUE|dcg!}aDQgOV5Q)DNUCuQ)WYLDoh0la$WgJ4Rotv zl73SGB!!5ft4;u_0)Tewlu1aIlv4$e7NhEr2*wDImhcdODhmiee(7;S&)u7m^TJuj zaGUfdZDVciLfWbcO&60EYDq)jov~-{4mK7`pYEYc&w@icvLv$}mP~63fQaCyo2Ss* zQVo!HDH$pO(lRB35g-omfawMe^nP_^y$^poa`|Z9SFjm3X%lhVbe0*eXklR@hpazj z*S1q9FNjjxxVQ}d->$7c!mNdD=TFtot*O#!`|xS|OHuf_lO(fI+uy#9pUO$a*#sOA z$Rylwv>Hv8d{!)xY^h8tQ6spaLFVi$MVo35lV#;3pFwgMqm(I19?9JSfizUeB!pxz zcn=V0Ex3&Ey6Qwt{o0znXyk^^eztLT9tLee+r-Wk{2opI5JWWXJ32UktqpML9XRs6 z#MobUojQtE)E=tWWgF@baOJ{w)?sH(aQZ!{b=ZagG!MYD6E_&Z4eyD-|6~MGQ5j`# z30VOQ`vMH%@f}La~!CD6da+o0vbz|)znwna{EC?cc;6-Qy+!o+g*weOYZHn;7XD^B!GzUq~%s$X>)e$w?x< z)Z{%y9JjKLLjf7F$S-*}(L4YTB*B9jlapkLL@J3tktnH*$W0;n%wWo3O+r{wMM+Xs z312FZ01r9LkcJA*uaczmNv}$!;O~IX;}g9Njo7gI5`{<7<8q*FVrk0oC=PXy=|H#u zKz|QgXXl|oYge50=7$rDoC!A zwmuJZ)k$wFA`CfyIQN20w{F8JJU+C?)xnrU75an-ynV+u_V&K`HPF)1vY*SRA5?qo z4wJ-*MB1#|r!Rm&z+V6}B?l0Pe4bzc2%Dl|*~vO(62cT4m?6OkkScgmqa{JY29NC< zP`3p$kKj5U0CjC6u5(A)29~DgG_&oQS$!%!~kOnUbLrAa(Fytpgg!eRC*soc&G_uG_vu^N8!(Nuj&` z#K5BpB1am;3cv;J?KETBHutTeLYRx~!*UT%eFH@HlYnR~Xd#ZtV2l89$md}MNCP~) z#NEhk{c@q>)Yl@QPDyT$xQ-p4baOh=17y<6kArSxF%WmxdX1ad1CA`8-MhaZCnN0!T$BAvIYd$Ypk2y6B4Si@|dVJW!`?+j>!lxq~SM z3ias|wWr-lH!C{=QINH>!!YMh<{ktaPS&W&jIB2|K;l(L3bab7U{MCX3JClZr|>x|SL)ShO73*>(Um3?TLG`qsoXZfidM1G@Xto|+)Gp=VaS;Q^9D6v=9A zD>#=4Ano&cVAicz1Lcqje*g}Ec0HrKfAs*ZXNAq1<|_lpmo==DKZL81tN)a z-G$7_Zqvrk!pe$hqqYtX!@JFyp6HMtm!DR zlY%zt)46}pc&GU@O5HcDdK3`1gJ_^hRfR&SkCYK(7=R>uMx>}8RhI`yOL*WM)W?DK zd0>f^Fa5DbD2!_Kr?c<^^IC=K{kB<@x5 zk$1vQb~leE3UKtFT;Jvph*;*-lWW8bLCF!qLW$cXy+TXr@ad&Qi)bp0anoS zpc={A)@G=~8PB3aVN#6)WyEEr;5gAbX#X_(I$X6; zYpSX{&_t+i#6PmJ^0%_Jm6*0ZSo(JyIABWG_ol_VE?acLZPV(9(0h|=CK;f}D(n=h zH}=5R*n3cbAWn;2{Pym{R zy1w&fY{!B9--3Im@f>2Rti&3}gO=5fmc5Nk_uLGR9zYUnB;q6423g?ViKSTj!bo(N z;35C#KI82u-qJ4{Gf19eyVUlUW%|^ zZnCIfP7;y+_-`g5|IbPi^%ca4`U?_-{WBAUA;nq3Pmb&tjVjJW{j(BKKdjOErbeS) zu{%)Dotu!~`sIJ|mMlEx{_fPMF3&yt4!*}{=)Lxad&l5N;yDtHBLSza865qC)RtDR zEzNTQ$I=Twxjl$hva*tBC1{|2c0A9QyeEzMpx1&~aRXK^t{J*{-KFPtZ@v9|LL_>( zFq5pc7*d#lFa&5!Sq>Ugk%wTXYPEvD6H=0eMi-=`m$Q@5wh937R(}&TIUbMRpz@FH=p^muMS&k8rPW&v5Uw3|(oN%o@i?AX(9{eMj0e z=|;zbye%X!HEJd)P*|Sr9279#aqQ@Y0n?{$9=Lcxs@J0TE4-I}RLfhl^rG*&<(K_F zUwy@Y^V+`y!q?sCv2DYDAOYd)Z}@Ln_qX4s&#w5cTltGm=(3C6OBdC;FPKx|J8x!c z@AsyKx#Dxexm&kxJ(ymrFTJ)z(*WQ-$UTbhwHv+nPP8mmW^jxPQY+dck!Yn(GBCl| zkS7UDcIeQPG+ujYNI(&)epEv|1C8I--hO0z57$xcyu3ne{CQ(R;BWX0{zm~B2aNYrwV0HSx8{J;1$)?@1OKiJ7vbWif-(1RyDDC0Urd(C)7@ec}NqAJW4iP}%mf zbm-iNbeE}?u#}fR3L^cV^!xa?mYqBIAtni6fpfz(#K5@GYdg|=k%dN4+nB*IQJC7% zz*}ePoH|fP)rD#VciPxq#I!);i-%JJsPv!`K;iJCfOym2c+zupr{{E{*RZ44w4wK4 zhUN){sTFNBOX{3j)0j#J>OV=q>OxJ619fN}DGajWNdM=ZG3C0HJC*5|F-luRx+T-!eR#IDS=86u9ga*$qLhV6wmY2 a9sdtN6eHRrdyqB&0000AvglfA9NypXa{#=A1b*&&-_9nK?6&dOB)k#LUD105bLa$_BV6=HEq#kGmWEawY(P zYgJuY!N_}RGo8TO$oTXsB$&89>#C*cCdYLmNX~ke#Hv9KA93kET{$`$PbI2&f<=QO zbYEuG&fq#8;U|Hp%+iMX($XltD84sh%`HcA9=yrw*x5Rd?dw|aj_wW|b=kga#C;uk zY)LO?99@%_7kX6dzR(&*!tnq4;>`zco!?9(Az&zTo|L_j^WL&gF7wJuI**)H&y&sO z9l;NhRvPV@eM$C25(Y1oLfTY%Qu06J{1!LY%l6`?e{u8in|(1@!4MJk2$1+uIsPqnf+k()k8h#rg7tMJHVtWaqYT zq|_R>T}xsUyk)<9e2b1o1pB702Pc9ve?7kQpF2}x}2=dBPVaUdm7-ZjF+bUL0vak))KQnKW)qx!vgbJE?)QXqi+7Po!iYjGEI9xeX+3}trhX=ZOA z6m<4$ajUa5?TbuamQOsfYFx!_%v5Pca-z3$eHCN9QVeZN0(`DY*CwYcn=Z{IwS{|W zMVA?tHKL`t<(1kV)n+5idi^{`iXLpvnO=;Rx{T4}wriDGR@79T*3GDl#qU(VPNH?_ z+WNh=8;jQwV zM#imv9eB3r+LQaLX%UgUmS$Q-V|+Ygp>ovUbJ{jiX~_q+go2a38CD$M(o|A(oS*f( zh?L!-@KukR?4c%)OIZBg${L2g5L6Pa=XF(yBP@&9b|agsWh)uYDy{MN@*W9zbE^QG zPZ8wOAg?zDskn|*wf&j@!i7Pbw6fw_Jr}n|+l>O-_8a2*TEQA7y+XU@NUD_gnXUKG z2}$1=_w*$M6~;^rw4#*yT22U!%e#`&t(A(xyf|-T(y3T1sVLvn_}AGKzdo!w)-*Uq z)`#%}qna5)jZjh2p>&4DK;ogEbdo#F?UZ%H>ljUbLLNV;50EQ$-zmX5OZ~Oiu>6ZIQR6g&! zPTyC(E=$qrR?zuYogtRne89+%HynZlT2P=QPE)k~RavpYct9<_leX;S(cUYWmJ%5i zw<#|0L;Epc1diZ!djsOtxXCrexN0iPy+W$%xrf_3!-ktsYsF?BfO_-+rz;1%p|X0Z z`xS4h<)pP{yf5Y2%`K?M%L1lRyQRhGg2R@R1BO$0TUeSMPUR$cJ)j;QyWQ-2SYJ1? z%~^ILTzh8y5rPT)29-&Qo@%PiVei|f)aGz{7xO>5>77{OmMi}>lo?rwpOta_aN2a} zZ_L3$CVhl%C4|)F%yc_!V?s)E@;~94fP)o1CTwgW@3F@BcS<{+x8_h1m|gj-8eT8~ z{P{;v_nE3QwfJ#=Vz7jq`qgMV1n|+2J0HNKgTY17#cGz07^gpi;87-UU+o*XC;A3g zg??@@etFPbu_%d$CSm+feh%;vd6_sgJ6ydmIB8OZ2ObCNBuk-&Tg}J-dX|>uJe}kmEmBH)Q7uAac~6f=i$joy zJK0c6OM9t_Ef1k*Ry3>%RVQV4P_zwS5s^T+u`MbCH zd6?wSSFRIE`|C9((s}H4ZYxc^RT{P)UbYCc^d0IW&aSPITSpqAIQF6g6&D^@VVnrOzTa^&s3buD4Zh79z^>7JLQH+- zqYS8QcLF8+03Y|4eD30R)L9O+_7gvyxH&uXehWGsGF8ox(YPKFj0 zeO}1^(}~=Cb++)WmDI6QeKp!MtupG%f{wZCy1$n!&RIBjUrS~HF0dp*p%w3uW|XYcuU?@&lSpJS-nf;@|F$`Umi_6zQo)P* zAN?|yXKv+GF@wL}{Z@+e2fPCrPyKWP%8JnsD4{x0N4};B4)_O}kwrPV3fK?Wi2^1> z9|==dt|saLUjuoB-9|amKlwXh1UO#${B=k&OyF9&!@HCh^(P1Z!t`T$%9BxBE^)o# zrb+Lsi5i*!ebE*rcxuhl)knhZ#ON)wO$oi@$3X1Yo6{S=udP&GmK4bkq;tb{^J~U4q82PKlFy7~0oQfA>1ZE&nMwI&x>vEc6U6l>WUM9Dh&x=`RU*Gbxx! zkNtRQF;b=RUB91-eD(xJv`D~Lmt+aUbpk*|itL0+z!SP00+|E6y z`uA#y)}Obo8;y%<&n3om?p6xzZJ%th-0j>wzfmi#6_%M|?B;=zSIm6DyAoM_apC>I zXM6D8M09ojEP0;(Tm6=+iv(2Opx(Oj#^^AOYqkBr2bn&rSZqFl_g%UyrartZl7oXX z-sf{fs&@{EPIHwb9qDY_<^%-#3soQ%QDuSy?jsU+(Fip2|+_ zGrN|zd*<~MKX{Lbhj???lU_IhSOdz4)6#L*Ah zm&9^`M`a&%BRsm}7gG3v#DiB;WAYz|2o$)P`>;wKw>@5~1xl# znaLk1Gsg9W+FM2frk6^A_#Vca3W3`Oq!4wV08%sw2(tG4QPdzk%6LE|<#%m44u|qJ zyU?M#nQ?*VpSqw3iYXL4`rl88NPi0HtH8TIb5i9co;}~0@H+On_0OFWps8>3b*XNL zROE5^A`ad4h3;CKVSt1Kz|T<$S=!5XFZ%6Vi5u+l>6fg(<F3On}Towx%MlobtMeV$xN86aA@wyIsb zpySR3MZYr<`22Zdh0P(}B+{cDNL&Y~SPHU}if;!Las3k+eLw;apzg$Cn=31tX!;`8 zY=|5HvpA^g-d!i?nHGr%`~;Flh)u-a91db%jAcig`GW_KWahiTTh z{}^LvD}yhSsCAb|MoLE2G})=@*?##ViZEif4M<3V`i@tM!^>(*Rgr=M9E%|@2gR-B zJV|}j_)t9!JI+t<`3J6z`iNgqpaz#UNv`wl%dOPql&jUOM&>{9=QR^_l&7V4>`hsJ z^G|jS@;l#xw>et_W*DeS$UNv7$Yq?LHspOA%H3LWvgs9kgq*9fx_t)_w4AYf&erE; zoUk${(?)h)eonZuyEw`pl=f#;ELYvr!4*#ks>oM})C*(SuXf}-zfb9s0fYSo3g&C* zV=nfhl#iZHZ8A?c#4g7pM_Rrg?|bjeon~Ou(U2Voz^zl1+IZQ!G&%DZFh62aK+ek- zIo}{Z&X;+Mut%Mj>T@fUL(+){SDfT6!du|ddt5){zl^BJmNK30o-LWDrxIFSRRt+6 z!mYbqyWs;|mm8gb++|aKrJtx9R=#Vi=s69%I$3gH4DJ(vBFLcl7y^(vnPL2npvJ^j?o{T3??tCz0EKI&uu8tndn zkP*E{3i=Q?WeHe^H6*-O16$ApV$=)$Nqz3J%o|%deE091F8ElmB!tV*#0J2#d^I^`4ktA5yK?Q)z|RG`a?V z6vH1jHr#*xxAsihWpi)FEq@|s`QcppDIGpfxROKBu0<7Fy{apE5|3#IrOxK5OZfiT zjAMJ0KGV~$kv@fkjt4!>L}(9#^U%fwjj7Soc36XR)nDkQ3%8O)y;4K2VSi!6N4Mh@ zw62zp(^}TOjuhC^j`!miC0|X$=v@bbB+t5$f4<4>B;>4L-dJnDu>0!J6a6@}jJN&h z5e^#-V!s9Wub&ovQDiBRQH|Uc+sDm4EBsD^hoLp{bH0m|`La@aQ;Ug8XOExRXK|8f z^?z9pD!y^tS<2~MSIn4a7XMfypgzG#m*nQ%dM@^@iK_bUx$*elFco$VW}e6F=)=J* z3o<(tO11GJCk*0owwI(!QK`Ukf9T;Pd{7*GdM=q|Klu8W#Ibn*K754KV1q`FWw!Tu zep>9~)rzk~X|!cCM0wh46KQ1GO>+TU8SrsBIj*FPcmY7D$cXZ;q6s*Vh)z%o(t;vn zx!K|qj$8j0+q9$yyXv#dz}`dy+B*;=H54B~0IEX%s9R#o6}K@lXi@`Zn-ymH++KpSwT zEpq>t59b$ORT?+07%Qzh8*}&0C2m>=7z55P?UqIjx=Nd z5_RT#G>kXWDMf$`cv#^@V6=CmHr$UfeA!pUv;qQtHbiC6i2y8QN z_e#fn4t6ytGgXu;d7vVGdnkco*$$)h)0U9bYF(y!vQMeBp4HNebA$vCuS3f%VZdk< zA0N@-iIRCci*VNggbxTXO(${yjlZp>R|r93&dmU$WQz=7>t!z_gTUtPbjoj2-X{Rs zrTA$5Jtrt~@cao#5|vM$p+l3M_HC0Ykiw9@7935K_wf*-^|GKh$%+opV7&;?rh9&P zh@9}XUqp-`JNnPs3e9~OrZBIJ1eel)hsimyfZSIAKa-_e!~q3^y@G=z;FN<65|y#S zIBWtzFv3n-*Aa|5F3Z9=zMs!RG6&8j!J;3)knD|vHy=yM(L#G}?m=jXNQ08rzG{Q? z03L8v^?3q`cxQdd42Z9RVo{e%Ga$C`=^7nqlxSf^lZhCTfwJB*!vD&M6QLv2g3NcE zlLNNSl;_UR5*{d}Kf!uIIF!i1cJDS7fMI##KSPmi=TR$DWZKb=cLBWJrF7#XGuhG7 zjcL@fyIHYDII3IRrCBTavFc^BM=uYdvN&GWBrcfogytsZ#mNX@9K+}pNp_= zk9AV-B>m?U~{NIbky_m^|J@%P=#HgBe^ zDfz`6g|`gOJpKE@q~4TH!vrHVNVb%n^e@&ALm85qj|xaBT5I90Ycp`;(u*rwGoyp? zo42?p->1XHi@SD&m=D5+6}|bUFWFw^Ue~(Ns1WQdWg=ux{zyH+AM91|XPZ%d*fiP0agmU%;tlV*!A{7y5(|3pSIw`dLqLknHv_PQBq$*|@+K4(r z(nO>@f;?%pkIO4xr70*Nk#eL*y7x+_=)8hsToX389#3w1KYRW> z*jT10YzQG%=Q$~Vd?jE*NFJ3Q_1xC`bl#coS5x4+(w)Pk{J+G z!)n>NlV4dtbN2@K)QdPtA{jC87jPU@hGv_JS3`DM&#QrL5o|v9pZ!u|C7l8Y!06X} zo>&23nPdehmmoN^p|A!0tiUTr`CHa7lrfP~sQnxYB!UG1e(yGzf9ed??k|R+753Jl z7|p%-Z;}uZWB`691Y{;z%fht0EQ5I=Q=xM!$55sB}?14LLaJP!Sh9=o6Ct`HH&OJAVuCgBpm0G_>L zLgPblVMON9`^+|EfPcuK*NO!3l?TlBFPGtQ7{6XmmBfL}Lk{{Mr*gyq842232l)y! z&EGfE9#VdjQO(a$U8DtYD6#;quA5M_q9pjqqG3-3XgR=iH5haYfFOE#7*m*WlW+;p z?*(QB<`&=?VN8b*zDdAXk|0u&ChUKnuK~u}^00YLP@tffpKM40h@>0qAv>J$ zJrJO6LoW6nQ;Lt_8TqG$3|&uIySi8pIQWB_=t1;Ew5BRl7J?W_#P#Q!jsiS1)t)R& zBm=TT1+G!Pc}xbIpGmNXV5B}zM2aE|pbfY#^zg<53DRF@)}T12BMzF0(fIJ0A+3Z) zF(FCSsFO`ljPqMasO-{OJsw6GD$89qiidf9!om$onI10;i?xPp_7Zxa02^=nHJfV2 zo}1Yu%99UK)~|dQR05$flJ_LP@??KD=@6^q3rd&zl=sq`D155z=wL0%C|=Gl`rS`{ zw-3XN{PCKN>`Mx4Uux^yLNOaIrkrs#Bqr1f%w1cG$Fdo;T7H<^$r|;|#mdi$cevZ* zdUc9(`eHt8@K+4=->Qr*HrT(({2Uj)Bl+GPr7ru{us3&!JKUzXmE_(`3UuU4d?;JL zc1X3KSL^U^==r@m)sd2}-$!fwYMO+)%E6|CLIK_ z##nHbe&&rMSDpx}2%+?FJ^shJ8yjE97(vftaucYh>*)KEqRD9|NrLKH=hV$e9A!~^ z4bADay5RL!GXeJ2_zHiwLYIYD#U!gVUX?0lWn6r52N(6LN{Xi9iK=_HO>X!U%Sq@l zh^!p)kHb1d(Ot9To5AfPe}~eD)OZ0MoXW((BIk$hb?gir611I2@D$KJ^VOg zT4fSfiCU#LYYL*CDCFNS4@bFDJa-HD&yA+x-IPQdMe7%+($&f?mC=n) z%&EO|+G#XLeHlo%(5I?7ol`ugo-_s0FL0#nkfTIT>6E9z50T3{?rk#sL>rRnNM~|9 zbq!>`l)R){K{#)v-}J)R27GTgA_f4XfzXn2${0y<*>7Svs39Rgf5ulzf}LmgT3Eqn z8G!%JRL1Gwj7k#Zh=Le=U`Dd4zH#;|o}L#6L-c(Lz=^Dm0-V6?8-?W5q)|w-V8|R@XK0f;$q`9@OmGmQp4JO_0Zgzau^3zjqT)q;CKx|;eNzuf>j1twm zQVhYEF@QgguW{CYFS%U=FfSW|H*CE2A+vuEH66-Q#2iU|Hp8DbO&^njfDi(!U@PIK z7gKGe-eQ+t4rUUtOnfvN87~ND%ab5b!x8Kexv=DeQHV%lmmMLXSRR33V1Aty75xeT&9+VL0)Pz zHpe~F;-a3{`62`|2n#wq#ktiRT;Lh?1diJGf-G(W%QRhQ=!Jr8$ZYk3OReu(4&Gvg zpl?-6>j!|kPL7>&DkSoxD|)&8W{jZ2fm<;ybWp=h-n|lrVTDs2KpsZq8Q@_M%r>_G z6KCrGAXxq8UNzXk`cExGjmaZsNdrw!&Z+iI)D|i}mo;laGQ-M%`}Lv&JJzx${Fd2` zs~^QJGpsDcGk=sm8SeA2z~=GbR9j%8fE@kpnk59Gk8>W2JHBvC&t8y~%f9?sa~*MT zzP9Q8+4`#QlH>2jX$MYd!H45&7r$Jq^`E!@tm|Bu+=?c(yux?!x_X7iET(66!RFDJ zzB?@ffQNcw6D-yOq*Rav4dB9dVs+0RBr5E*p3whI*rE4%-H25JcTOP^)Sh)#sZzJ+ z$IbOD+T^K=`N6CDCpfKHwv%aj}rTaikoks1a4O*+M}j{W)R#K&nzKm zPg7psVmbDEy1VO-r#xCjVwX&}+zKNECBJ!QguJUSSN_kOkv4T&}pz(^z6}X zGCV=1#|a(xlOI`HtWV8dgfuF4s$*LghD`Amxfcq5mblTfRr+m0tzen&#b|xUxLu~H zK~RBt!`&v4%R?`#kjuBJ$opo+D?{Uaa{a2hC;Ka(&ON7#V0K>#_J%#LVtBRt)u}`s z=j4Xe0jY2@p+RHv*#26?%g93kteo0Q@0;`x2ZCw zUn4`&W-e{5P}Q($ccv`W$#ILg_$6+&?B*0cJk#%;d`QzBB`qy)(UxZZ&Ov}Yokd3N zj~ERapEhGwAMEX1`=zw)*qz1io2i_F)DBjWB|*PHvd4MRPX+%d*|}3CF{@tXNmMe6 zAljfg2r$`|z9qsViLaWuOHk$mb2UHh%?~=#HPf2CPQh;AUrYWW~ zvTV9=)lS#UB-`B5)Kb!Ylg0RA){o3e`19Jl&hb@~zS>>vrFR-^youk^@6>0S` zToim7wzkY|Yt*;aGUy!o{yxd8=*L;orYQC!H#=|pjn&hO>o9B$tJu8TBHmxPPsm-) zM#T(;Z9_uvy1xq;yeeWQV6|}+=O;1%) zGZyIq}2>crU3z2ri)(ut%F~+%S>FR4^Xw()Y-+~&Xp*Ns z$?%1aydpzNIz2aN98}oth>3boYSifQ)J81Of>6k)!`WQWrB;xxXccBzrWe5V*>oMh zon)MEw$@-*!>L`CK}u@x^9-4gfvepI0b8q5QYVXr96{4Q#s2ZelHXxHv~G{GymRer zqyj7m)3yn3z5i4koiIJ!-u=p6QeL|BN+pWd>}TOFOVi01q839$NZ&I_quqb(n~9Wk id-{KKnnu*>l46e`&P3zgUlQEeAE2(Hqg<+p4E|raIYd(c literal 0 HcmV?d00001 diff --git a/fabricexample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/fabricexample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..4c19a13c239cb67b8a2134ddd5f325db1d2d5bee GIT binary patch literal 15523 zcmZu&byQSev_3Py&@gnDfPjP`DLFJqiULXtibx~fLnvK>bPOP+(%nO&(%r2fA>H-( zz4z~1>*iYL?tRWZ_k8=?-?=ADTT_`3j}{LAK&YyspmTRd|F`47?v6Thw%7njTB|C^ zKKGc}$-p)u@1g1$=G5ziQhGf`pecnFHQK@{)H)R`NQF;K%92o17K-93yUfN21$b29 zQwz1oFs@r6GO|&!sP_4*_5J}y@1EmX38MLHp9O5Oe0Nc6{^^wzO4l(d z;mtZ_YZu`gPyE@_DZic*_^gGkxh<(}XliiFNpj1&`$dYO3scX$PHr^OPt}D-`w9aR z4}a$o1nmaz>bV)|i2j5($CXJ<=V0%{^_5JXJ2~-Q=5u(R41}kRaj^33P50Hg*ot1f z?w;RDqu}t{QQ%88FhO3t>0-Sy@ck7!K1c53XC+HJeY@B0BH+W}BTA1!ueRG49Clr? z+R!2Jlc`n)zZ?XWaZO0BnqvRN#k{$*;dYA4UO&o_-b>h3>@8fgSjOUsv0wVwlxy0h z{E1|}P_3K!kMbGZt_qQIF~jd+Km4P8D0dwO{+jQ1;}@_Weti;`V}a_?BkaNJA?PXD zNGH$uRwng<4o9{nk4gW z3E-`-*MB=(J%0*&SA1UclA>pLfP4H?eSsQV$G$t!uXTEio7TY9E35&?0M-ERfX4he z{_Hb&AE`T%j8hIZEp@yBVycpvW2!bHrfxbuu6>_i<^9@?ak)9gHU*#bS~}$sGY*Fi z=%P&i3aH%N`b;I~s8{&6uGo$>-`ukQ<8ri(6aH6p_F`Fhdi6HuacwfQn10HVL7Om1 z4aZpjatkbgjp$L5Mceab#G#C)Hr{^W|TJX~?B3@2buj0;kfuNTf4c3*Au~O^aj=W2$j^4okeCxh#lwexN@eam-u4dNz zN2NIuIM4566{T&^k%4ftShcPk#=im-zXm>QWqH^0>A@?MqlDZCZ@8Wi*@tvhn5p<} zRwFm@gz|WZp91S5Z{}tB^e9|FBg(~Ik+?&_53J6ye_QQOSJ*846~H%s#LD}|O9v9H z1fLrrgoPo_&bs}eqEr}2en3iqAcP^>YsKiez$5-6m6(#3ZZ$@M5Ck=_Vv`QA>1A*v z3w-nJ_;5Nc(0_%`kG91#sotIlhO!*5#|yg+Gx{V;0ty`*=Y9=jCh$l*=fE(~t}%R# zc}iNpO)OZX`P=leQY^?^DF1w%FJh>Dkp}-o5Ig|2!6^E>|W|zc~W7gF;MtxX7 zV~UjQNsUC$EYXpN?~o{83D2c*0~7;Tm~%FRTAnnt3ln{?DcLZ=NsBY|JxwUA-6K3V zP&#|9t#a}Q4{Sg{6v-OmjJBkCh>m)8vLNm4lStMUT$)FZeJG05A)px&o3H)5oAl9= z31@?HyCriHcCDnt628BFN+T;U69Wl#itfvqIDBydMvOJO0Zl?go$cfG5>TK75CMj3 zakLaH3=&J0e}Xmqlav$S0>E@_Yo_V~3SiiXrw)$&!XhrHCDQ%P1BHPusuKr0LthAB zg)mDrLy>2*yevMMOQe6fZ|)%PEb!lC^*9yaX9UMy7-v!fSICssTR|wML0Ic2BhKAq z3I1X~ z7^_!M&;6Z9?br3#HU_&kfJ~%botXQkC1v<}ZZxN5q-T)|Sb2cW3WYUBbDZ`TH{!*^ zrmAeRM+(QI>D+?}guZ+dH*X)@^!O|oL69&Avbtw2^M3HP(+2kV{O$^3BN1RLfrC8nwz7=VhBR%>!;7WR<~;34B_j3A{>^@e@H+Q! zL=UNr1(JvKAQLKT0b}EMn|QUWtY>!>8-t@fVj_&`~gGd{_aPy5W>0u5L$zrsU^rBO=i$`#Xd*>kh)lPf}A znNXSEl`+HlhXtylgS9(#N02A=zVV?#OF?)Gr>(HszVa+1*2VG@qYttJuXaBlzP`Pb zX)ueu?s&}R>xI#^*r4gR?tMFi!_eeKlIM5g)Nk)Y^h=ZCR**xY>$E5knctRrq!zw? zX{2|hwR9LXTY1)pTlKg7U4_ej{dcj2{!+1sZ6<@9^?mn)=37V)DIAvS(}S`IgFO!6 zn({?nYw`Z-@jvt@!q|5z?TI3(dx^1szSn%azAwp>N#fk^kt|=MejKtacAs@Rdku#zT>9$s z=m7ek)`=O7hO2n+2Uj$QUs&2EIqycF{(L9Y#^IyxXA%R@ z&j`VAprIV~d!pH-7~zA+bjwVn3kOB3;rlg{nr&wHV12N}g^i>Upls~=z`VX>9HQ#= zTu&luVb@_Lkz63&&^_M!6(-2^0?GCAX9XKp{O={pd|AlIMGriX6s_Jy8_q9|{5jLc zxd1aj_ucE7Vcti#$r!s~w~W=XpaLQ}#mX`apR7^n9-d3?O+adJYr*L;{c)x@REewM@vZN0njS3iE$88KHPWAkWt((OUMherUnPm?i&8@!9E@ zUW^$%CpdruZR0ohzUq-XQ$KEIB8Sjgs1+wKSUH&Y;=ee%E&O$X18{&979d~K2uJW` zd*8awHCXb;Q>4z$B|sPNv+Zd__f6&@KmS+L`z3H1x+x|Xs7-N-iw|1C=QiJdU)f~z z{vO4hpP`0MyqmwIHN=l?jSq>OKG6CEC#O`*blP`?>)CUWj5j1cB>%6N7;`kfZ1iQV zam~SDB?{uyp^=vF_u|=8xn3S)L;wF8ZRZV{bezM-EH;MC91JQZ{KcZZ$IWJUy?SJGeGUWm6PeuO8-K2|hD~p;Ls~9Y-4lE+?|bF)XaNKUNX(K7 zBQk0Z{n>hrH-CA`bTr$6z0n@Cn9EL$XZ3=X7NopjcI=;z<(X7-oEmK}BId=PxX*!b7Q6oL@ufd%eEPc`_la(}WkT zKe?-YJWn^6b$^{dhdJZ)I!Kn6c}iw%o5mLDyvM7qJZbkGG?zLU;M|W;Wis|A;SuY3{_X53`+>9g^B%O4b{;^t$^;{oKHbo*CY%u91 zp#2d8Pg=I0&UX{qwr=y=o_^BLdk=KYH$=Z8+k|p8V5`ph~3b^{^NnL4m_+4zx( zeoTt@f<$DmsB1}o%R1Hx`ToPuBl+P6cb-?uF{1!z-2WvdR4+vJ*SYTic5@gwnzu%e zD!HF^X=$ha^#1hi*@~^nDL!HQ;MC&e+6=onaJgm-J-+|>PpmU=SIe?EQE5vJiqziw z*K=Z%bWZz_we!qiFqE`I?#$yozNxIE7Ei;csv>++r*?)0bozFpF&oLh94u z-2c2L`5BarP7l>87|f)vxaT*9(!Q`2xBMZ&^JVj-|1)Tg!6OW=lk=w zLwVlr!*<(l*L$a?ox3+%!~UIj3Ej@KD;W>1E_c)1szDi93BC;0K?drOQ>@$yi|DtT zSir}!Yx>znf&b0KS;Lk7VKPDF@e>(qQr0%SNcGQd(p9StjqJ`QSW&c{ggF?5{d22w zlkX%JTUq`;(3WSH+)WHl%qlF)iNG_?}K?ZM3cS7#u5v zZ!apx4Apv=PWsn}eD%MI#=KA)OlNy0)l@~D^1;NC5k@|OPW3wt>WNYDN+8~+gM%E! z$ z`Olr0;eytiK&~O*ps%KV?2vq+DhuRh*!6Ilzu>A;iMe9 zI?zug9nT9CI_o)O}KF_I_U z_Cswu{)3pCYgw{eOt#E?UCqBwkAugSl>5 zX?G=Ci(Lo+r3suuJezyQyDvw*<1b{rx*&ZaY2HlJ>k{Qc%IZeU43pQXw4mh!4I5>l zZ@4$uxaPY#!*IhL4Hctn#!n#S+SiPcZP_PTd5fXf1exhFi5zf3kl`UcW2RUk)F2oF z_ogN`{03PiseQR;fa#{Uy;jeNlJ0Sle`~;ZYhLjkuy>a^!Z_nR~`$&F?NVuIE3HX;i zD82snwlwPb`7yE)ZA_Ndmq5zuSO1{{1}(d9u4#!Fl_|eOuxKBwOfQ*tG`VjCV$-WF zxi0c&+w}Z)rqz{%f46@`ADPdGm#x)+zpT+gyfDi;_P zR{#Ta`Mzd=putKO@5lQJO*aNy(i?}Ltwy^Z;69f|eqi#UCI1$vL!+(#mi?dK`OL$! z3jQnx$_$+Li2<__CL@Wuk4^J7-!n3j2I4N8e#=qpir+iEQcrn3`B4yNOd1BBLEni<(tdRWE>m0I^ zt(^*Td+S3}$5rOzXy=MW>%#MN_qy%5St!>HrGZ~Fq1WKw-&kv@2TrCcPCPzY%2aO- zN?7@+$4?&qA|uv{QHuV)O9haZpG7Jx2f%D)7J@oWTxJ#E_YSq_6qT1tomOD?02(1otT{Hk8{?g(944>h4f% zOJ8tzjecV{x2uWde&6oAP)*({ zFkW0Q%gdI*9@W)oKO65DgP<3F_BIKvRXLAR?Z61&0g2TR6mEZ7OZK?dP7zukdg?s_tNZeuOsh^e1Tmdlz5rIg?LcK|%aQ1FsSDv#W0EnHd z9M)p;gAL_R~Z5cojTdwy+qDsd6R01Vtxmq&FhfPz{wxmB$${zW~z@{Ro_ zK#y5^KqIp!#@or>GD`c+aZ(PV1=`Eo1?a55p6a*WepFgxvmp!^2518YEU-;{F}fLr zD~)=S0m=+px3TUN8-El}Xb}{2ET*_i3-|WlY@V7vr6#&cOr*+oS9?GF?@)K6op>>o z4af0@%KwaLr`{3P&)474<3rDMsd!IM-bepWfhfuMmJt}#0%PgDSx*q(s0m%ZFgWTj zwwvH%2!(i9{RHX~FVUB5qHvF{+ZF}+(bZVPG1)a*Ph>KV;cYNK^aB@R#dS~&`^60V zn2Z24Y{{djzK33}t@q%!v5k)u7jAXB_H{#4Ut2 z1}0j5$RXcTyfazqL9=^Qe%GL`G)=!lirv7AgVRf^=XyEM&kiOe_%JD!O?sXK&hrDo zF}m9B68im!oGshuZluy2H#T$`XPZQu@zf;(nBCZB-cjQ&w*p@Tm_$pe^MTN3EauI) zJG&G^H-4S|1OCd#@A6jO+IcAXG#5M-d9E!^YNmV7Z(=F^?8bfrYf&mLMnRd_22&Q} z2*msbLsrI!XPeOK@|V?n>`kNC`8eSFmekELLr|!-wQRltxZnuRedup<7VflowJ+gC z)F}P6lUSsh^B41?=~0*68YA6z63lKG`W$@{GV!cC2FCl0s<7yz6!3JWoBbUDTgpg% z4VNUk%xblMy7PjLF2We*3XY7K*N(*9Yx!_M zjU$&JXLiNxaTzoa&k@NSbzbLJTn$6bu6SPWYx)Zc1Li~Lqj($GuWsA#;zg85eH{yx zz3IIOea3A4QFGmJCfn7N_d$8a77j+T^W}Sr%0XdVLFf&zJ$s^D5Vrc!iV&GXyb5*A z6mG8d*6EDN7a;=dgVjYI--~4@Fe{{fcJ4B|;_Qg~&%6#?I(?X_$S4rDw{=>=8iZS=M^I#EF!m zXn%K_xXWwmm7R40LKXPo6ZzNZfN1-$S6RuVU=JlC|3#Xjo-%ebJvvC4n%IM)Q8NDh zGXd)L;ay_JMozc^mU*Uifnp=#+if>LD*O9MV#@wB1l``z|tlu(7PJqS6rm)0@ zJzP50{0Vpa`_?92oB;*i(?i225a6tZgT+9Dg?vTh)N4OKA~(c8{$8-ZKz=mb@$4IT9g8>;k11WIT+Y=%Z})`y#OJ zK-~rlEy!T%0h!Qo+jjPF2RQz2Z^B;dbvYg2JS`+@D~OWH{2-EEs^BdnuJskh>CKeT z1b;%8dU6QU%i@z?^6Q-{XESe^qRiw`ka+k!d-{c%&lXM}vCX^T=|?|;t6r?N*h-W4 z?o4Hy%BWqW+5=+md#5^8|49zjM zon_Do@rhzZ4XAb}-m|bMH$Vg<;^Bo6A8cfhUQ>|wFk~j(`>1NgD3sTg)He1pWrUj9WZ8R(Wn5Rr zhc&dXvv_m%HrwwHo9l_))NgdVUff%d&@4^$Pc=MDZdZ^xHL$KX^ z7W1{3UJ%>9v$W{Y3>vBvflE-soDj8{`>#F|8Z$EF%lN$NylORTn5JsI4mTMHWd*%- z2sD(RO(H-&i8&Ge)5i12slI5VekYCZ)s8rv&_)194;vKY2m8DIC2{4<&xTM3HHxwT zd(42n)gCJ$O4I|8sJq07#0U7Yk7PjPK&bMdy-5b)OdhSsBo^|IB_H43@&F@tpdJR0 z#~)=UJdP|=)O{0(rVZnjbTtwHV^}&kfLJQP@R6rda;K;O>9J9bnW$BgbzOZ8aO{D8 zPuJ%=Nqg~rdzk-IW0ZC5I%cc;ek5~=lDXl4?gMOQQ!KE5Aq$9qeGFM6jFP;Xy6)%N zjg{q(E6fnF02P3L*tutbHRR-gyYK3g^y9H?GMtIs;ojG zY~3*C>qD)(8jz}89w|xfb7L`^d>AG#%D-uq=qz}(o9kzzrx0LSBX90ykr*5oM+YmoTRWe+Cj6aq^xnWRymLmE>krCpoC9K%2LT0aK0Y< zt@kUUrrj1WL9rmBB8B;WXqg-BztOiUZX-!`*a&-75+!WZ!R0OPiZz?w`Of4q#+(;m z`${Ea6GnTCY3`V2R8w*}knf)*`RA@(8k{Lp4VP;<+ z9O_z0_{3=HcVi z5)&QGEB_&$)mu@)(Z8zuw#>Gc6C>^O-FUZEo;TO1@$>-xu%`v`tMS3V-8R1pb5w&zP%&rAP2*5h z$k{jqReFXCJhJ?-{x(2j5gH_zQ>;#Ec*@bUqF0u}XB09+U-K}+jQd>)k#AOkr6M8x zHyhrfJ`99@Vzr_B@*p@`DxeJ#`jimavZ9ZV%v{mO0!%9$TY(f%_}BU~3R%QxmSdD1 z2Bp45R0C=8qtx-~+oULrzCMHMof!&H<~~>BhOu9t%ti7ERzy&MfeFI`yIK^$C)AW3 zNQRoy0G}{Z0U#b~iYF^Jc^xOlG#4#C=;O>}m0(@{S^B2chkhuBA^ur)c`E;iGC9@z z7%fqif|WXh26-3;GTi8YpXUOSVWuR&C%jb}s5V4o;X~?V>XaR)8gBIQvmh3-xs)|E z8CExUnh>Ngjb^6YLgG<K?>j`V4Zp4G4%h8vUG^ouv)P!AnMkAWurg1zX2{E)hFp5ex ziBTDWLl+>ihx>1Um{+p<{v-zS?fx&Ioeu#9;aON_P4|J-J)gPF2-0?yt=+nHsn^1G z2bM#YbR1hHRbR9Or49U3T&x=1c0%dKX4HI!55MQv`3gt5ENVMAhhgEp@kG2k+qT|<5K~u`9G7x z?eB%b2B#mq)&K}m$lwDv|MU~=Y(D2jO{j*Box$GUn=$90z6O^7F?7pn=P;{r4C8qa zv1n*5N7uIvTn`8$>}(74>Oqk=E7){#pHUFd5XRJ5ObMhqODTa}=V0;+a(7JZR-4<3 zBTvsqRwLh?*ZF)JWsWOkEq7*XMQ!G3Rmkdh7ZbM#v1~?jt((e2y}u}Ky>1qa&Y7m@ zveIzH@?5Gexr79*?sbZGkVS;s1U<7D(%~7HjAmzj$aDYv_FGl5JX@LW8>w=HCDl6W z%?rsr0)bErYJ5G1v&zjr{8=lW)ZYcstgZAuL}!0~8HAcgOm@nJ9cvOOtL@)Fpl2Dr z8876Lt<|1eF88Jx#C*XyGI)C5z_o!Os!t=Xy0$Kj^4fG1pb@16%g z+<)zJ1n1QO78g#$3yHj+(Smv`HW5y_-PP{h2A1UXMG-c%hMvHLbF6t}G>KA)H# z`AWL~>8JUT(iq7;zJr!Aj)AS+n{mRbA3aM+Gj}b#PhHdTM_NkwQm330EC9waM$=slPfxR1vmr!vf~t_M?a%`@`&tdE}ipY-p#Q#zhLK zd9eFC;PjIEAKLkRkO94{rTuNFqKbNUGtaNZRRbax9;|%2WbnGu!44#64RriY5u0O} z05G^e&JB?Wb*8^g)aM`yt|}~QJkKCipFNeyex~P~SFPVEafD(73rncKmm)m~&`O*YUyY9z7tO%ec7z@wWcoOr-ebP z1k+|y?d{>1jLC=s4B2tEhiTtu->WVJno&%%6bG46KuU9D`GEN!C!9chM>zd=cl0+- z^k>4rpkq7_iWGHtBvy$Q`dja2;1ZdYmF6cANU6{v>l1=fSKRpsTRonp@alC%p{bhU z>g+(%-)&_nDQ~#bq5;xo^06RggA&uH4RMVb6wt;oQI+`m_zt>SiI5hXkfEnn6@ZNk zh9KUr1jtt6lBg$O#TAoTRvwUtWeMP3EjnGoRPQppiNF(sX%|Q4@kIjas|WZWXSENO zfF#2yOb;%XO*LeOoAwlf{u7_39$x(w3xT~)2BNJ2l5u4n3a0NkNLT4yT);7fA?1Vt zCz*`hbw-doYa09E!05zcfOT0EOORY``E@D z5{v%@F~&|UfNt@>vrj66W5f>jy+G_8&VB9D0*>N!7_Nr=-x6N?A)M8>1~q(X34sXp zpA%@w&c};L7u*G3;(Qe=LFL}NbTF$|aX#A%P(h`-N=ZRxCvlG$>Klv}jo0MS|UR8qKq-1FokBJmrbTJjQ!k#Is0tY+0c)m4Gp80YzYD zEGXd~ihaihk;?xUknXNH?rssjzaF+l6?HnDQjVP$i=q}{lp_WbOTKKg}HPKW)2sW`L#NvgmaY0^b2Ldk|t{P6{L{>ym;Xgao1PrudBgEMRFb^ zkPJ6v0h^tJ>K@;maHk_|6Z>yFzq@YvDOeO6Ob_?P4Ey>kHiJv`Wlh_MX4fBY36f%^ zV#2t;$Rg&}!Kwifm z;TVZXMxw3~$--{&A8-6vnUZ#s4`Z-zQ#+y7UI8#Hgsc|ompLUc zqlAG!Ti>t{JzYF^5pM925*PUWUvDuYDGKhC4FMx45c`L#V7%V+88@|khLj|V=J9Un zJEcP5qVCzR6p{FK!nIY~TXo)tJ!{>CG;~&u;EPlnNrwJ=5)ke@hJosN!siM$8b2mM zmc&weo-rY{n1+%c`c<{AT3i zjF{p253Ul-)s5A+!8Dp7?viXAdH1+qlY%mK5pp?{pS1t!3qmmDOq2TnoV`F3<>(XK z1=gfH39N_~8O+~({MZX~+QHyB>vtgwK0@uqGkX^eaf$UFHiO#>LB*7@=c0o6`0muj zmH00_F#p)s3E*$A-zP+p2bvXARTg3)Lxh`tf~9X>7!Z^kHV`uE%V9+BiBG=mxj*)M zr%3rn=)>GR`{#zmwD)$3ToLMx++uqsCx(+50Uk*5QJp2c6msxLD&P-y{c|XK6zZl3 z_Fgu8kp|gKVWv`GS!c56FWPO)ZrCCtYh#*yp-ssus)ot>_~UB zyGfjTjz#fXod{^KEQK1~@jN|;SZw5OgH#0wK78Oe4#vV3*|&XPQU z$r~5u8ziT0<#ICrX^<1){mvtaqT9OqlW?wiSu4X#rOC(0uL{Ownb%i1F_G&d>=l51 zx!FEO4_LK+)W^N6UF+fAccyyp{t)TE`;vF@1irbNjcXF8b?yFh zl5UEB>@;wO`~gMF!QB;h<``+f(lxAb_8B$;&vT7)(bXG(7x_5f%AZ5;h#3WjHisX{ zLTSguapAADXMwWZ&jsD0+K!+8#*6z7-(T+QUk>(~!Q|0&!d)PgEw8F6RK;LkB;!HXg79$+l*KU&-fRF|$o+kR4mJ36k9p&>*uS~RhCV+*Y$3U-k%~M)jxCFW zl9;bQ-fx4HPy)*(bhrKL!81M6*@6p5W?z*W`jb;@JKMFwmic{gQPv*) z?I{Fh)y)}(-6uh^I52xKo!LRZV0c*1X)Z(g+GVFN{2n%vD*@&IkVI{R_0;M28M z8vu?M+xVF-&<{l@1g{PA#hnyAq(gudz4WKSFL5YOr3q!|qrxa7z~F~rEJ29VQKgNe z1*L^m9&acg2p7&`u&V%oY|AKF(Xpv=)wf&j#n|;2UYEaUIHLJuTQw$SbrNn+)38PlfV^0<6s>)|hT#IAAS*T)_^_q@I} z0S%tV-HrXOjzkvW!YSbDjdH=g;=4A@whsDB zI8^aX6n=|ab(?!Ay!)CxH(wC(iX~Q@%FEx>C{Hmp98f2ku$Bsw%lk6v50(U@; zu68Z9U&za}O#-Mv^+!V=eyj6S)5oS{My`1MVs)nlnYl_$xU^QId1_jMf7&K8ij)jQ zJ|+~@l)xpV%~Y{P()$`+nBihkjE|3t3t8PoKU3wZ_Eg%0P<>%(A@oW#*8i$X!nfG& z;&&2ZIKlD~*Gff+p3A7QB!}Ei>RGhUUz^UoEpeJ{`2ov>wH!O@1$VW>A#D#{i2z9l z{d)FK9OYxRY#(6NUMO=q^5Ve7R|72%f}ZDlsm0BN&LzyaSHurXV4p5HGf7|Z)}8)g z5J#S6h{-+_U0m$k#+|N{6_8MYactWzWb+1~ea8wX3zX<@O0>pU*q($J{=R&7)P&jg z6Kb)o=HAnC_MP;cIeBq}{gG^0CZzOUJZ|7C-VjE}!?*UtKTcwwF33v^BYC&}Rq)C* zpAJ07-!{`flYX1@n;ZK-=x4)!o(%(1UqulVmes(D z^`_HNfM#umEYy~=zh$9&+?8$4!l(4rr?d#8hS4iks@9w%E4l`BKmhUtvsm1X-mKC3 z>4(u4yS45OgZIOQ;EQ6s`sjNelo!~mLe7gS69TW2WnFwEKcAwioq2mLXV<9CIa#(0`sQpl>vwW`A$D?!2%nt*HEb;Ga=o?92 zHAOICmXHEQ%Cc{m2>dLjPU1J}^w7zilFIxy9nG(OZbYPtW?3KJyv@A7|1A*NiD_v! zTLC}%E4kI*d?$lQBRL==MPsD#FyN0ZSr`;aeQ4C6a2INH9klU~_gCH;G2%8R4EuHb z44Ej^6301>?c06FP3X~xyP{77p`-3td;HKAGf4mZw1qRd6Z^^L#?qaiAKv~px)*jAV^re~beps9m{kJzb6n(oS8uCt#Lnjofg;Rl z=apY)JsV;^dVkzCW)jDrii_WTT`3iKri(xmCC1^AO}Vqt-1B*wwIlBAmE1AmdRtMc zD!fB@mtwHPHyV-^VIVU??*~*{olz-Ub)NCX941BDj_CKZ+QYQ?+``tyhy_7WFXF}_ z?~CVO#LsDYD!&}cph22{PZ*TK?$K^u`E7%{^na89Rm%!jSZs7vI-D zL1POD!1cu56G)*p1gui3-i^JZPX3tI*_Fq&JRwbz*#8LUSiMRWjuu`zD|uk;+X&d@ zuxF5C2{Zp#O?GtOB+R2~tF>MDI(}%p-W=M>1tEY}8E=b_l*WbOO zY9tCPgL3vMEqz)_eWeqmN{qobq_4)XdXJSe6Hj;Eie0??2ZZ?p;*_K8@(&v~1evu- zxQCA2YYvv@qhzamqdi`?{Z{c*7$arCdz4-4G(`O5It%y&8>d{#Y9Vax^FZ99ZK zUdIPpkNhp8uP3T+W4lhvUIYaoY##y6KtxBFoj3&5^@Q(^{677%C#3YJh$p-Ee2M6F ztJAoQv1N0L!|N8XBD(eAYcB#gRaIX7T8U5xXbx~cJSon~YnC zaJYE%zOj9y?E==_B$*9NiAm{~)2Z}t1$$l?qOYct5Ep5HvqFKvuSE7A5YF$K@2>UE zbQOdTNzjD#zS(L>wa2$K-WK!Pc%pY^8To58;^JaXZ}F30wuYl;WWs~rCoo&vrEtUh zTBLMU??yx1#;-weCPZyOJ%Yeb?14z+OXW0L_E+<)(q=;xz74U-Q~R~n*oC;MxyrJo(74r$y2t;x`D~{nhUw`N{Bbc zo`l5kb`Yy;L=&@MTQ~Ml_%V%){mCIj4WC}5q=A_ACx2^by!4w1rVX6H0ifayJsw;; z=+}5kjC?RG*q)^FA;udd?fK$7vU1x>y0w;A-)YbE%l$J%nRRjAIlrItFPgQvJ7Ytb z%HSFnjF2||X&L_g-Q>1{(mholW_-EJmSzsO%*VVVB4)#OAv<(kOIx2H!f)I9#e_Nyjdb$&*1KN^gM}yFIhi%%BWB}7Ke0M{0WY>CxJQUuL<9GW$I>S z8~;QmE{^wS?I`=DyV^l+MozMPWLoFz=uSLu99tiVHdCN>7jRs~vd13`&Gey!!7_+< z6o@25%!eN~+Eki#7iq@#{Hxl7pF0^`N;~p~#tc6HXJP0g5xvK|AuLSwNHVI2_Y-!& z4hemc%vOM5!ySDypyEGe=lAeFbIp`w8FIUcTqUwens>sTIV-jDhrcKGX7XHFXyazb z^DO8=ZgefY6R6&+)c1_i*WoenjtR5@_JU#Ph;4M8fpmznxE9R`=r@-#_y zkD?Muq|*gg7f*BQeI|Np#}Q|NXLJHM6GE{;SJn8ce`V1Gehym~{8c+M<2~=HcCRuk z-v&$8dc8YG+tK}NYVhwdm1iZ&A#r+T<>Ez88)Eq9j+G5h5D(_u{WQdUTOs+QbA(=? z{F6n6UV8D2*lvb)0vDrca$729KG$xO2aH$jWoWl0drlmefYsTswh)`GjMtmR=vEkJ zN$aTp_@@KL%KQ-VDB2ppbZK@X`6cJA5n`g>sbCTvU_xdid!{9gWA|>Mfs6rtHx6s` z_wMt*FgUTBZ@I2C62&zbs?pPvK9TpatkXzqDqe4YTr^nnQg8gWxjKt*s&eOMEp!Qc zG~PT`>xg76Xqh^dKI-Eu#K*VnvEf9qT{L0yNpVj)eVD#kQzGgVRbTB!5nWY=?t!cggiEGBAcWM2xNtW&9 zZB_6RZ}|a87CuEYRYCRJ`Sg+_gBK$_J@*zoWcJJw>eBw?G9WY(Jw~qN|A3MBR^~jm?>k5oGv7z+0jWOox(co@%nya|* zE-2peyX)#@svgwwDMPJ89dT=iO>}@wtNR@NUQ|cJZ};sX(w2uWP4AE5)@A ziJgy_TIZ+T&vG&xPh@Jmt!OJ|zA6C0ZxfF2 z7>aIZqecbmM$lyvDMwg2?Ipo9b)-WL6K_7(X_rmJgdd$-Qc^ywEw4SThChz6*_yu= z{v~a4V|RJtH-GThc2C0Z|JHPl{II-!?B~7cWnRz&dgP*UqoY!iCo&i-xeM}kl?ID* zKTX`w+;z0+MCdGcl{N?xb|tYb%Id=k++k_@(V%bTS&n09`0{S0)|>IH_F;V@_zrxS-dKDDc7+i`nHN8J z;38w69lzAS*WWa+dnVvk(0-KD3%*)TerLH zSCc}Tjc-mR5|1HAL$C1}oue|Qp&M!hmyDUcg)Cz>GXPEyeYf}+s48kIl*pL{{treP BIP(Ai literal 0 HcmV?d00001 diff --git a/fabricexample/android/app/src/main/res/values/strings.xml b/fabricexample/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..067bb0f4f --- /dev/null +++ b/fabricexample/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + fabricexample + diff --git a/fabricexample/android/app/src/main/res/values/styles.xml b/fabricexample/android/app/src/main/res/values/styles.xml new file mode 100644 index 000000000..7ba83a2ad --- /dev/null +++ b/fabricexample/android/app/src/main/res/values/styles.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/fabricexample/android/app/src/release/java/com/fabricexample/ReactNativeFlipper.java b/fabricexample/android/app/src/release/java/com/fabricexample/ReactNativeFlipper.java new file mode 100644 index 000000000..e2d5d1837 --- /dev/null +++ b/fabricexample/android/app/src/release/java/com/fabricexample/ReactNativeFlipper.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + *

This source code is licensed under the MIT license found in the LICENSE file in the root + * directory of this source tree. + */ +package com.fabricexample; + +import android.content.Context; +import com.facebook.react.ReactInstanceManager; + +/** + * Class responsible of loading Flipper inside your React Native application. This is the release + * flavor of it so it's empty as we don't want to load Flipper. + */ +public class ReactNativeFlipper { + public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { + // Do nothing as we don't want to initialize Flipper on Release. + } +} diff --git a/fabricexample/android/build.gradle b/fabricexample/android/build.gradle new file mode 100644 index 000000000..0778e4046 --- /dev/null +++ b/fabricexample/android/build.gradle @@ -0,0 +1,43 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext { + buildToolsVersion = "33.0.0" + minSdkVersion = 21 + compileSdkVersion = 33 + targetSdkVersion = 33 + + RNMapboxMapsImpl = "mapbox" + + // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. + ndkVersion = "23.1.7779620" + } + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle") + classpath("com.facebook.react:react-native-gradle-plugin") + } +} + +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? + } +} diff --git a/fabricexample/android/gradle.properties b/fabricexample/android/gradle.properties new file mode 100644 index 000000000..a3b2fa124 --- /dev/null +++ b/fabricexample/android/gradle.properties @@ -0,0 +1,44 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true + +# Version of flipper SDK to use with React Native +FLIPPER_VERSION=0.182.0 + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=false + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true diff --git a/fabricexample/android/gradle/wrapper/gradle-wrapper.jar b/fabricexample/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/fabricexample/android/gradle/wrapper/gradle-wrapper.properties b/fabricexample/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..6ec1567a0 --- /dev/null +++ b/fabricexample/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/fabricexample/android/gradlew b/fabricexample/android/gradlew new file mode 100755 index 000000000..65dcd68d6 --- /dev/null +++ b/fabricexample/android/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/fabricexample/android/gradlew.bat b/fabricexample/android/gradlew.bat new file mode 100644 index 000000000..93e3f59f1 --- /dev/null +++ b/fabricexample/android/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/fabricexample/android/settings.gradle b/fabricexample/android/settings.gradle new file mode 100644 index 000000000..db7378fa7 --- /dev/null +++ b/fabricexample/android/settings.gradle @@ -0,0 +1,4 @@ +rootProject.name = 'fabricexample' +apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) +include ':app' +includeBuild('../node_modules/@react-native/gradle-plugin') diff --git a/fabricexample/app.json b/fabricexample/app.json new file mode 100644 index 000000000..b3f7e526a --- /dev/null +++ b/fabricexample/app.json @@ -0,0 +1,4 @@ +{ + "name": "fabricexample", + "displayName": "fabricexample" +} diff --git a/fabricexample/babel.config.js b/fabricexample/babel.config.js new file mode 100644 index 000000000..681d47b7e --- /dev/null +++ b/fabricexample/babel.config.js @@ -0,0 +1,4 @@ +module.exports = { + presets: ['module:metro-react-native-babel-preset'], + plugins: [['module:react-native-dotenv']], +}; diff --git a/fabricexample/index.js b/fabricexample/index.js new file mode 100644 index 000000000..a850d031d --- /dev/null +++ b/fabricexample/index.js @@ -0,0 +1,9 @@ +/** + * @format + */ + +import {AppRegistry} from 'react-native'; +import App from './App'; +import {name as appName} from './app.json'; + +AppRegistry.registerComponent(appName, () => App); diff --git a/fabricexample/ios/.xcode.env b/fabricexample/ios/.xcode.env new file mode 100644 index 000000000..772b339b4 --- /dev/null +++ b/fabricexample/ios/.xcode.env @@ -0,0 +1 @@ +export NODE_BINARY=$(command -v node) diff --git a/fabricexample/ios/Podfile b/fabricexample/ios/Podfile new file mode 100644 index 000000000..b0ce847e4 --- /dev/null +++ b/fabricexample/ios/Podfile @@ -0,0 +1,64 @@ +$RNMapboxMapsImpl = 'mapbox' + +# Resolve react_native_pods.rb with node to allow for hoisting +require Pod::Executable.execute_command('node', ['-p', + 'require.resolve( + "react-native/scripts/react_native_pods.rb", + {paths: [process.argv[1]]}, + )', __dir__]).strip + +platform :ios, min_ios_version_supported +prepare_react_native_project! + +# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. +# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded +# +# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` +# ```js +# module.exports = { +# dependencies: { +# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), +# ``` +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled + +linkage = ENV['USE_FRAMEWORKS'] +if linkage != nil + Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green + use_frameworks! :linkage => linkage.to_sym +end + +target 'fabricexample' do + config = use_native_modules! + + # Flags change depending on the env values. + flags = get_default_flags() + + use_react_native!( + :path => config[:reactNativePath], + # Hermes is now enabled by default. Disable by setting this flag to false. + :hermes_enabled => flags[:hermes_enabled], + :fabric_enabled => flags[:fabric_enabled], + # Enables Flipper. + # + # Note that if you have use_frameworks! enabled, Flipper will not work and + # you should disable the next line. + :flipper_configuration => flipper_config, + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/.." + ) + + target 'fabricexampleTests' do + inherit! :complete + # Pods for testing + end + + post_install do |installer| + # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202 + react_native_post_install( + installer, + config[:reactNativePath], + :mac_catalyst_enabled => false + ) + __apply_Xcode_12_5_M1_post_install_workaround(installer) + end +end diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock new file mode 100644 index 000000000..73e67eb30 --- /dev/null +++ b/fabricexample/ios/Podfile.lock @@ -0,0 +1,748 @@ +PODS: + - boost (1.76.0) + - CocoaAsyncSocket (7.6.5) + - DoubleConversion (1.1.6) + - FBLazyVector (0.72.4) + - FBReactNativeSpec (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - Flipper (0.182.0): + - Flipper-Folly (~> 2.6) + - Flipper-Boost-iOSX (1.76.0.1.11) + - Flipper-DoubleConversion (3.2.0.1) + - Flipper-Fmt (7.1.7) + - Flipper-Folly (2.6.10): + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt (= 7.1.7) + - Flipper-Glog + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - Flipper-Glog (0.5.0.5) + - Flipper-PeerTalk (0.0.4) + - FlipperKit (0.182.0): + - FlipperKit/Core (= 0.182.0) + - FlipperKit/Core (0.182.0): + - Flipper (~> 0.182.0) + - FlipperKit/CppBridge + - FlipperKit/FBCxxFollyDynamicConvert + - FlipperKit/FBDefines + - FlipperKit/FKPortForwarding + - SocketRocket (~> 0.6.0) + - FlipperKit/CppBridge (0.182.0): + - Flipper (~> 0.182.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.182.0): + - Flipper-Folly (~> 2.6) + - FlipperKit/FBDefines (0.182.0) + - FlipperKit/FKPortForwarding (0.182.0): + - CocoaAsyncSocket (~> 7.6) + - Flipper-PeerTalk (~> 0.0.4) + - FlipperKit/FlipperKitHighlightOverlay (0.182.0) + - FlipperKit/FlipperKitLayoutHelpers (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutIOSDescriptors + - FlipperKit/FlipperKitLayoutTextSearchable + - YogaKit (~> 1.18) + - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0) + - FlipperKit/FlipperKitNetworkPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitReactPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/SKIOSNetworkPlugin (0.182.0): + - FlipperKit/Core + - FlipperKit/FlipperKitNetworkPlugin + - fmt (6.2.1) + - glog (0.3.5) + - hermes-engine (0.72.4): + - hermes-engine/Pre-built (= 0.72.4) + - hermes-engine/Pre-built (0.72.4) + - libevent (2.1.12) + - MapboxCommon (23.7.0) + - MapboxCoreMaps (10.15.0): + - MapboxCommon (~> 23.7) + - MapboxMaps (10.15.0): + - MapboxCommon (= 23.7.0) + - MapboxCoreMaps (= 10.15.0) + - MapboxMobileEvents (= 1.0.10) + - Turf (~> 2.0) + - MapboxMobileEvents (1.0.10) + - OpenSSL-Universal (1.1.1100) + - RCT-Folly (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Default (= 2021.07.22.00) + - RCT-Folly/Default (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - RCT-Folly/Futures (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - libevent + - RCTRequired (0.72.4) + - RCTTypeSafety (0.72.4): + - FBLazyVector (= 0.72.4) + - RCTRequired (= 0.72.4) + - React-Core (= 0.72.4) + - React (0.72.4): + - React-Core (= 0.72.4) + - React-Core/DevSupport (= 0.72.4) + - React-Core/RCTWebSocket (= 0.72.4) + - React-RCTActionSheet (= 0.72.4) + - React-RCTAnimation (= 0.72.4) + - React-RCTBlob (= 0.72.4) + - React-RCTImage (= 0.72.4) + - React-RCTLinking (= 0.72.4) + - React-RCTNetwork (= 0.72.4) + - React-RCTSettings (= 0.72.4) + - React-RCTText (= 0.72.4) + - React-RCTVibration (= 0.72.4) + - React-callinvoker (0.72.4) + - React-Codegen (0.72.4): + - DoubleConversion + - FBReactNativeSpec + - glog + - hermes-engine + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-rncore + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-Core (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/CoreModulesHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/Default (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/DevSupport (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) + - React-Core/RCTWebSocket (= 0.72.4) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector (= 0.72.4) + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTActionSheetHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTAnimationHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTBlobHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTImageHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTLinkingHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTNetworkHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTSettingsHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTTextHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTVibrationHeaders (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-Core/RCTWebSocket (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) + - React-cxxreact + - React-hermes + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimeexecutor + - React-utils + - SocketRocket (= 0.6.1) + - Yoga + - React-CoreModules (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/CoreModulesHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - React-RCTBlob + - React-RCTImage (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - SocketRocket (= 0.6.1) + - React-cxxreact (0.72.4): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.72.4) + - React-debug (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsinspector (= 0.72.4) + - React-logger (= 0.72.4) + - React-perflogger (= 0.72.4) + - React-runtimeexecutor (= 0.72.4) + - React-debug (0.72.4) + - React-hermes (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - RCT-Folly/Futures (= 2021.07.22.00) + - React-cxxreact (= 0.72.4) + - React-jsi + - React-jsiexecutor (= 0.72.4) + - React-jsinspector (= 0.72.4) + - React-perflogger (= 0.72.4) + - React-jsi (0.72.4): + - boost (= 1.76.0) + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-jsiexecutor (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-cxxreact (= 0.72.4) + - React-jsi (= 0.72.4) + - React-perflogger (= 0.72.4) + - React-jsinspector (0.72.4) + - React-logger (0.72.4): + - glog + - React-NativeModulesApple (0.72.4): + - hermes-engine + - React-callinvoker + - React-Core + - React-cxxreact + - React-jsi + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-perflogger (0.72.4) + - React-RCTActionSheet (0.72.4): + - React-Core/RCTActionSheetHeaders (= 0.72.4) + - React-RCTAnimation (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTAnimationHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTAppDelegate (0.72.4): + - RCT-Folly + - RCTRequired + - RCTTypeSafety + - React-Core + - React-CoreModules + - React-hermes + - React-NativeModulesApple + - React-RCTImage + - React-RCTNetwork + - React-runtimescheduler + - ReactCommon/turbomodule/core + - React-RCTBlob (0.72.4): + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.72.4) + - React-Core/RCTBlobHeaders (= 0.72.4) + - React-Core/RCTWebSocket (= 0.72.4) + - React-jsi (= 0.72.4) + - React-RCTNetwork (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTImage (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTImageHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - React-RCTNetwork (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTLinking (0.72.4): + - React-Codegen (= 0.72.4) + - React-Core/RCTLinkingHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTNetwork (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTNetworkHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTSettings (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - RCTTypeSafety (= 0.72.4) + - React-Codegen (= 0.72.4) + - React-Core/RCTSettingsHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTText (0.72.4): + - React-Core/RCTTextHeaders (= 0.72.4) + - React-RCTVibration (0.72.4): + - RCT-Folly (= 2021.07.22.00) + - React-Codegen (= 0.72.4) + - React-Core/RCTVibrationHeaders (= 0.72.4) + - React-jsi (= 0.72.4) + - ReactCommon/turbomodule/core (= 0.72.4) + - React-rncore (0.72.4) + - React-runtimeexecutor (0.72.4): + - React-jsi (= 0.72.4) + - React-runtimescheduler (0.72.4): + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker + - React-debug + - React-jsi + - React-runtimeexecutor + - React-utils (0.72.4): + - glog + - RCT-Folly (= 2021.07.22.00) + - React-debug + - ReactCommon/turbomodule/bridging (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.72.4) + - React-cxxreact (= 0.72.4) + - React-jsi (= 0.72.4) + - React-logger (= 0.72.4) + - React-perflogger (= 0.72.4) + - ReactCommon/turbomodule/core (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2021.07.22.00) + - React-callinvoker (= 0.72.4) + - React-cxxreact (= 0.72.4) + - React-jsi (= 0.72.4) + - React-logger (= 0.72.4) + - React-perflogger (= 0.72.4) + - rnmapbox-maps (10.0.12-rc.3): + - MapboxMaps (~> 10.15.0) + - React + - React-Core + - rnmapbox-maps/DynamicLibrary (= 10.0.12-rc.3) + - Turf + - rnmapbox-maps/DynamicLibrary (10.0.12-rc.3): + - MapboxMaps (~> 10.15.0) + - React + - React-Core + - Turf + - SocketRocket (0.6.1) + - Turf (2.6.1) + - Yoga (1.14.0) + - YogaKit (1.18.1): + - Yoga (~> 1.14) + +DEPENDENCIES: + - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) + - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - Flipper (= 0.182.0) + - Flipper-Boost-iOSX (= 1.76.0.1.11) + - Flipper-DoubleConversion (= 3.2.0.1) + - Flipper-Fmt (= 7.1.7) + - Flipper-Folly (= 2.6.10) + - Flipper-Glog (= 0.5.0.5) + - Flipper-PeerTalk (= 0.0.4) + - FlipperKit (= 0.182.0) + - FlipperKit/Core (= 0.182.0) + - FlipperKit/CppBridge (= 0.182.0) + - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0) + - FlipperKit/FBDefines (= 0.182.0) + - FlipperKit/FKPortForwarding (= 0.182.0) + - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0) + - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0) + - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0) + - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0) + - FlipperKit/FlipperKitReactPlugin (= 0.182.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0) + - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) + - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Codegen (from `build/generated/ios`) + - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rncore (from `../node_modules/react-native/ReactCommon`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "rnmapbox-maps (from `../node_modules/@rnmapbox/maps`)" + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - CocoaAsyncSocket + - Flipper + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt + - Flipper-Folly + - Flipper-Glog + - Flipper-PeerTalk + - FlipperKit + - fmt + - libevent + - MapboxCommon + - MapboxCoreMaps + - MapboxMaps + - MapboxMobileEvents + - OpenSSL-Universal + - SocketRocket + - Turf + - YogaKit + +EXTERNAL SOURCES: + boost: + :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" + DoubleConversion: + :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + FBReactNativeSpec: + :path: "../node_modules/react-native/React/FBReactNativeSpec" + glog: + :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0 + RCT-Folly: + :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" + RCTRequired: + :path: "../node_modules/react-native/Libraries/RCTRequired" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Codegen: + :path: build/generated/ios + React-Core: + :path: "../node_modules/react-native/" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-rncore: + :path: "../node_modules/react-native/ReactCommon" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + rnmapbox-maps: + :path: "../node_modules/@rnmapbox/maps" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + boost: 57d2868c099736d80fcd648bf211b4431e51a558 + CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 + DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 + FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5 + FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f + Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 + Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c + Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 + Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b + Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 + Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 + Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 + FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 + fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 + glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b + hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2 + libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 + MapboxCommon: dcbdb86acbcfc1a23efd341ed097c6c63ab532a9 + MapboxCoreMaps: bcbaac14467616940187f79bba49ca491cd37906 + MapboxMaps: 1fd9d97d0e8eceb7a45b9ac8bf87a8922da881a8 + MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6 + OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9 + RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f + React: a1be3c6dc0a6e949ccd3e659781aa47bbae1868f + React-callinvoker: 1020b33f6cb1a1824f9ca2a86609fbce2a73c6ed + React-Codegen: a0a26badf098d4a779acda922caf74f6ecabed28 + React-Core: 52075b80f10c26f62219d7b5d13d7d8089f027b3 + React-CoreModules: 21abab85d7ad9038ce2b1c33d39e3baaf7dc9244 + React-cxxreact: 4ad1cc861e32fb533dad6ff7a4ea25680fa1c994 + React-debug: 17366a3d5c5d2f5fc04f09101a4af38cb42b54ae + React-hermes: 37377d0a56aa0cf55c65248271866ce3268cde3f + React-jsi: 6de8b0ccc6b765b58e4eee9ee38049dbeaf5c221 + React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 + React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f + React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77 + React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f + React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58 + React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00 + React-RCTAnimation: 88feaf0a85648fb8fd497ce749829774910276d6 + React-RCTAppDelegate: 5792ac0f0feccb584765fdd7aa81ea320c4d9b0b + React-RCTBlob: 0dbc9e2a13d241b37d46b53e54630cbad1f0e141 + React-RCTImage: b111645ab901f8e59fc68fbe31f5731bdbeef087 + React-RCTLinking: 3d719727b4c098aad3588aa3559361ee0579f5de + React-RCTNetwork: b44d3580be05d74556ba4efbf53570f17e38f734 + React-RCTSettings: c0c54b330442c29874cd4dae6e94190dc11a6f6f + React-RCTText: 9b9f5589d9b649d7246c3f336e116496df28cfe6 + React-RCTVibration: 691c67f3beaf1d084ceed5eb5c1dddd9afa8591e + React-rncore: 142268f6c92e296dc079aadda3fade778562f9e4 + React-runtimeexecutor: d465ba0c47ef3ed8281143f59605cacc2244d5c7 + React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 + React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a + ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d + rnmapbox-maps: 24414d4a08775776ee5ae561874bf4a457f734ad + SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 + Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 + Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 + YogaKit: f782866e155069a2cca2517aafea43200b01fd5a + +PODFILE CHECKSUM: 03261cafaf2be596790fa09f953f81ddb585d010 + +COCOAPODS: 1.12.1 diff --git a/fabricexample/ios/_xcode.env b/fabricexample/ios/_xcode.env new file mode 100644 index 000000000..3d5782c71 --- /dev/null +++ b/fabricexample/ios/_xcode.env @@ -0,0 +1,11 @@ +# This `.xcode.env` file is versioned and is used to source the environment +# used when running script phases inside Xcode. +# To customize your local environment, you can create an `.xcode.env.local` +# file that is not versioned. + +# NODE_BINARY variable contains the PATH to the node executable. +# +# Customize the NODE_BINARY variable here. +# For example, to use nvm with brew, add the following line +# . "$(brew --prefix nvm)/nvm.sh" --no-use +export NODE_BINARY=$(command -v node) diff --git a/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj b/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj new file mode 100644 index 000000000..d6371b1d6 --- /dev/null +++ b/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj @@ -0,0 +1,706 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 00E356F31AD99517003FC87E /* fabricexampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* fabricexampleTests.m */; }; + 0C80B921A6F3F58F76C31292 /* libPods-fabricexample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-fabricexample.a */; }; + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 7699B88040F8A987B510C191 /* libPods-fabricexample-fabricexampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-fabricexample-fabricexampleTests.a */; }; + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 13B07F861A680F5B00A75B9A; + remoteInfo = fabricexample; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00E356EE1AD99517003FC87E /* fabricexampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = fabricexampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* fabricexampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = fabricexampleTests.m; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* fabricexample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fabricexample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = fabricexample/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = fabricexample/AppDelegate.mm; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = fabricexample/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = fabricexample/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = fabricexample/main.m; sourceTree = ""; }; + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-fabricexample-fabricexampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fabricexample-fabricexampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B4392A12AC88292D35C810B /* Pods-fabricexample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample.debug.xcconfig"; path = "Target Support Files/Pods-fabricexample/Pods-fabricexample.debug.xcconfig"; sourceTree = ""; }; + 5709B34CF0A7D63546082F79 /* Pods-fabricexample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample.release.xcconfig"; path = "Target Support Files/Pods-fabricexample/Pods-fabricexample.release.xcconfig"; sourceTree = ""; }; + 5B7EB9410499542E8C5724F5 /* Pods-fabricexample-fabricexampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample-fabricexampleTests.debug.xcconfig"; path = "Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests.debug.xcconfig"; sourceTree = ""; }; + 5DCACB8F33CDC322A6C60F78 /* libPods-fabricexample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fabricexample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = fabricexample/LaunchScreen.storyboard; sourceTree = ""; }; + 89C6BE57DB24E9ADA2F236DE /* Pods-fabricexample-fabricexampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample-fabricexampleTests.release.xcconfig"; path = "Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests.release.xcconfig"; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00E356EB1AD99517003FC87E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7699B88040F8A987B510C191 /* libPods-fabricexample-fabricexampleTests.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C80B921A6F3F58F76C31292 /* libPods-fabricexample.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00E356EF1AD99517003FC87E /* fabricexampleTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* fabricexampleTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = fabricexampleTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* fabricexample */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.mm */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = fabricexample; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 5DCACB8F33CDC322A6C60F78 /* libPods-fabricexample.a */, + 19F6CBCC0A4E27FBF8BF4A61 /* libPods-fabricexample-fabricexampleTests.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* fabricexample */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* fabricexampleTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + BBD78D7AC51CEA395F1C20DB /* Pods */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* fabricexample.app */, + 00E356EE1AD99517003FC87E /* fabricexampleTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + BBD78D7AC51CEA395F1C20DB /* Pods */ = { + isa = PBXGroup; + children = ( + 3B4392A12AC88292D35C810B /* Pods-fabricexample.debug.xcconfig */, + 5709B34CF0A7D63546082F79 /* Pods-fabricexample.release.xcconfig */, + 5B7EB9410499542E8C5724F5 /* Pods-fabricexample-fabricexampleTests.debug.xcconfig */, + 89C6BE57DB24E9ADA2F236DE /* Pods-fabricexample-fabricexampleTests.release.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00E356ED1AD99517003FC87E /* fabricexampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "fabricexampleTests" */; + buildPhases = ( + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */, + 00E356EA1AD99517003FC87E /* Sources */, + 00E356EB1AD99517003FC87E /* Frameworks */, + 00E356EC1AD99517003FC87E /* Resources */, + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */, + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + 00E356F51AD99517003FC87E /* PBXTargetDependency */, + ); + name = fabricexampleTests; + productName = fabricexampleTests; + productReference = 00E356EE1AD99517003FC87E /* fabricexampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 13B07F861A680F5B00A75B9A /* fabricexample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "fabricexample" */; + buildPhases = ( + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, + FD10A7F022414F080027D42C /* Start Packager */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = fabricexample; + productName = fabricexample; + productReference = 13B07F961A680F5B00A75B9A /* fabricexample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1210; + TargetAttributes = { + 00E356ED1AD99517003FC87E = { + CreatedOnToolsVersion = 6.2; + TestTargetID = 13B07F861A680F5B00A75B9A; + }; + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1120; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "fabricexample" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* fabricexample */, + 00E356ED1AD99517003FC87E /* fabricexampleTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 00E356EC1AD99517003FC87E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/.xcode.env", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; + }; + 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample/Pods-fabricexample-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample/Pods-fabricexample-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-fabricexample/Pods-fabricexample-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-fabricexample-fabricexampleTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-fabricexample-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample/Pods-fabricexample-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample/Pods-fabricexample-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-fabricexample/Pods-fabricexample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + FD10A7F022414F080027D42C /* Start Packager */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Start Packager"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00E356EA1AD99517003FC87E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 00E356F31AD99517003FC87E /* fabricexampleTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 13B07F861A680F5B00A75B9A /* fabricexample */; + targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 00E356F61AD99517003FC87E /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-fabricexample-fabricexampleTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = fabricexampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fabricexample.app/fabricexample"; + }; + name = Debug; + }; + 00E356F71AD99517003FC87E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-fabricexample-fabricexampleTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + COPY_PHASE_STRIP = NO; + INFOPLIST_FILE = fabricexampleTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + "$(inherited)", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/fabricexample.app/fabricexample"; + }; + name = Release; + }; + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-fabricexample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = fabricexample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = fabricexample; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-fabricexample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = fabricexample/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = fabricexample; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = "$(inherited)"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SDKROOT)/usr/lib/swift\"", + "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", + "\"$(inherited)\"", + ); + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = "$(inherited)"; + OTHER_CPLUSPLUSFLAGS = ( + "$(OTHER_CFLAGS)", + "-DFOLLY_NO_CONFIG", + "-DFOLLY_MOBILE=1", + "-DFOLLY_USE_LIBCPP=1", + ); + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "fabricexampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00E356F61AD99517003FC87E /* Debug */, + 00E356F71AD99517003FC87E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "fabricexample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "fabricexample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/fabricexample/ios/fabricexample.xcodeproj/xcshareddata/xcschemes/fabricexample.xcscheme b/fabricexample/ios/fabricexample.xcodeproj/xcshareddata/xcschemes/fabricexample.xcscheme new file mode 100644 index 000000000..7b5e187b6 --- /dev/null +++ b/fabricexample/ios/fabricexample.xcodeproj/xcshareddata/xcschemes/fabricexample.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fabricexample/ios/fabricexample.xcworkspace/contents.xcworkspacedata b/fabricexample/ios/fabricexample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..3042edb3f --- /dev/null +++ b/fabricexample/ios/fabricexample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/fabricexample/ios/fabricexample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/fabricexample/ios/fabricexample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/fabricexample/ios/fabricexample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/fabricexample/ios/fabricexample/AppDelegate.h b/fabricexample/ios/fabricexample/AppDelegate.h new file mode 100644 index 000000000..5d2808256 --- /dev/null +++ b/fabricexample/ios/fabricexample/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : RCTAppDelegate + +@end diff --git a/fabricexample/ios/fabricexample/AppDelegate.mm b/fabricexample/ios/fabricexample/AppDelegate.mm new file mode 100644 index 000000000..7ceb58d21 --- /dev/null +++ b/fabricexample/ios/fabricexample/AppDelegate.mm @@ -0,0 +1,26 @@ +#import "AppDelegate.h" + +#import + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + self.moduleName = @"fabricexample"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; + + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ +#if DEBUG + return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; +#else + return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +#endif +} + +@end diff --git a/fabricexample/ios/fabricexample/Images.xcassets/AppIcon.appiconset/Contents.json b/fabricexample/ios/fabricexample/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..81213230d --- /dev/null +++ b/fabricexample/ios/fabricexample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,53 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/fabricexample/ios/fabricexample/Images.xcassets/Contents.json b/fabricexample/ios/fabricexample/Images.xcassets/Contents.json new file mode 100644 index 000000000..2d92bd53f --- /dev/null +++ b/fabricexample/ios/fabricexample/Images.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/fabricexample/ios/fabricexample/Info.plist b/fabricexample/ios/fabricexample/Info.plist new file mode 100644 index 000000000..d5ade93dc --- /dev/null +++ b/fabricexample/ios/fabricexample/Info.plist @@ -0,0 +1,55 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + fabricexample + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSExceptionDomains + + localhost + + NSExceptionAllowsInsecureHTTPLoads + + + + + NSLocationWhenInUseUsageDescription + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/fabricexample/ios/fabricexample/LaunchScreen.storyboard b/fabricexample/ios/fabricexample/LaunchScreen.storyboard new file mode 100644 index 000000000..34d5c4787 --- /dev/null +++ b/fabricexample/ios/fabricexample/LaunchScreen.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fabricexample/ios/fabricexample/main.m b/fabricexample/ios/fabricexample/main.m new file mode 100644 index 000000000..d645c7246 --- /dev/null +++ b/fabricexample/ios/fabricexample/main.m @@ -0,0 +1,10 @@ +#import + +#import "AppDelegate.h" + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/fabricexample/ios/fabricexampleTests/Info.plist b/fabricexample/ios/fabricexampleTests/Info.plist new file mode 100644 index 000000000..ba72822e8 --- /dev/null +++ b/fabricexample/ios/fabricexampleTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/fabricexample/ios/fabricexampleTests/fabricexampleTests.m b/fabricexample/ios/fabricexampleTests/fabricexampleTests.m new file mode 100644 index 000000000..4ac1afd06 --- /dev/null +++ b/fabricexample/ios/fabricexampleTests/fabricexampleTests.m @@ -0,0 +1,66 @@ +#import +#import + +#import +#import + +#define TIMEOUT_SECONDS 600 +#define TEXT_TO_LOOK_FOR @"Welcome to React" + +@interface fabricexampleTests : XCTestCase + +@end + +@implementation fabricexampleTests + +- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test +{ + if (test(view)) { + return YES; + } + for (UIView *subview in [view subviews]) { + if ([self findSubviewInView:subview matching:test]) { + return YES; + } + } + return NO; +} + +- (void)testRendersWelcomeScreen +{ + UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; + NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; + BOOL foundElement = NO; + + __block NSString *redboxError = nil; +#ifdef DEBUG + RCTSetLogFunction( + ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { + if (level >= RCTLogLevelError) { + redboxError = message; + } + }); +#endif + + while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { + [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + + foundElement = [self findSubviewInView:vc.view + matching:^BOOL(UIView *view) { + if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { + return YES; + } + return NO; + }]; + } + +#ifdef DEBUG + RCTSetLogFunction(RCTDefaultLogFunction); +#endif + + XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); + XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); +} + +@end diff --git a/fabricexample/jest.config.js b/fabricexample/jest.config.js new file mode 100644 index 000000000..8eb675e9b --- /dev/null +++ b/fabricexample/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'react-native', +}; diff --git a/fabricexample/metro.config.js b/fabricexample/metro.config.js new file mode 100644 index 000000000..6b535f5e3 --- /dev/null +++ b/fabricexample/metro.config.js @@ -0,0 +1,37 @@ +const path = require('path'); +const exclusionList = require('metro-config/src/defaults/exclusionList'); +const escape = require('escape-string-regexp'); +const pack = require('../package.json'); + +const root = path.resolve(__dirname, '..'); + +const modules = Object.keys(pack.peerDependencies); + +module.exports = { + projectRoot: __dirname, + watchFolders: [root], + + // We need to make sure that only one version is loaded for peerDependencies + // So we exclude them at the root, and alias them to the versions in example's node_modules + resolver: { + blacklistRE: exclusionList( + modules.map( + m => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`), + ), + ), + + extraNodeModules: modules.reduce((acc, name) => { + acc[name] = path.join(__dirname, 'node_modules', name); + return acc; + }, {}), + }, + + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, +}; diff --git a/fabricexample/package.json b/fabricexample/package.json new file mode 100644 index 000000000..50bb9a7a1 --- /dev/null +++ b/fabricexample/package.json @@ -0,0 +1,38 @@ +{ + "name": "fabricexample", + "version": "0.0.1", + "private": true, + "scripts": { + "android": "react-native run-android", + "ios": "react-native run-ios", + "lint": "eslint .", + "start": "react-native start", + "test": "jest" + }, + "dependencies": { + "@rnmapbox/maps": "link:../", + "react": "18.2.0", + "react-native": "0.72.4" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@react-native/eslint-config": "^0.72.2", + "@react-native/metro-config": "^0.72.11", + "@tsconfig/react-native": "^3.0.0", + "@types/react": "^18.0.24", + "@types/react-test-renderer": "^18.0.0", + "babel-jest": "^29.2.1", + "eslint": "^8.19.0", + "jest": "^29.2.1", + "metro-react-native-babel-preset": "0.76.8", + "prettier": "^2.4.1", + "react-native-dotenv": "^3.4.9", + "react-test-renderer": "18.2.0", + "typescript": "4.8.4" + }, + "engines": { + "node": ">=16" + } +} diff --git a/fabricexample/tsconfig.json b/fabricexample/tsconfig.json new file mode 100644 index 000000000..45a6c7072 --- /dev/null +++ b/fabricexample/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@tsconfig/react-native/tsconfig.json" +} From 0e5b78b5ef2975adf54477882693560355d56767 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 24 Aug 2023 11:01:21 +0200 Subject: [PATCH 02/33] Enable new architecture --- fabricexample/android/gradle.properties | 2 +- fabricexample/ios/Podfile | 2 + fabricexample/ios/Podfile.lock | 620 +++++++++++++++++- .../fabricexample.xcodeproj/project.pbxproj | 12 +- src/utils/index.ts | 4 + 5 files changed, 620 insertions(+), 20 deletions(-) diff --git a/fabricexample/android/gradle.properties b/fabricexample/android/gradle.properties index a3b2fa124..885445bfe 100644 --- a/fabricexample/android/gradle.properties +++ b/fabricexample/android/gradle.properties @@ -37,7 +37,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false +newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/fabricexample/ios/Podfile b/fabricexample/ios/Podfile index b0ce847e4..966c779d1 100644 --- a/fabricexample/ios/Podfile +++ b/fabricexample/ios/Podfile @@ -27,6 +27,8 @@ if linkage != nil use_frameworks! :linkage => linkage.to_sym end +ENV['RCT_NEW_ARCH_ENABLED'] = '1' + target 'fabricexample' do config = use_native_modules! diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock index 73e67eb30..87fd8f392 100644 --- a/fabricexample/ios/Podfile.lock +++ b/fabricexample/ios/Podfile.lock @@ -3,13 +3,6 @@ PODS: - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - FBLazyVector (0.72.4) - - FBReactNativeSpec (0.72.4): - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.72.4) - - RCTTypeSafety (= 0.72.4) - - React-Core (= 0.72.4) - - React-jsi (= 0.72.4) - - ReactCommon/turbomodule/core (= 0.72.4) - Flipper (0.182.0): - Flipper-Folly (~> 2.6) - Flipper-Boost-iOSX (1.76.0.1.11) @@ -95,6 +88,11 @@ PODS: - DoubleConversion - fmt (~> 6.2.1) - glog + - RCT-Folly/Fabric (2021.07.22.00): + - boost + - DoubleConversion + - fmt (~> 6.2.1) + - glog - RCT-Folly/Futures (2021.07.22.00): - boost - DoubleConversion @@ -122,17 +120,19 @@ PODS: - React-callinvoker (0.72.4) - React-Codegen (0.72.4): - DoubleConversion - - FBReactNativeSpec - glog - hermes-engine - RCT-Folly - RCTRequired - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-graphics - React-jsi - React-jsiexecutor - React-NativeModulesApple - - React-rncore + - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - React-Core (0.72.4): @@ -356,6 +356,555 @@ PODS: - React-perflogger (= 0.72.4) - React-runtimeexecutor (= 0.72.4) - React-debug (0.72.4) + - React-Fabric (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-Fabric/animations (= 0.72.4) + - React-Fabric/attributedstring (= 0.72.4) + - React-Fabric/butter (= 0.72.4) + - React-Fabric/componentregistry (= 0.72.4) + - React-Fabric/componentregistrynative (= 0.72.4) + - React-Fabric/components (= 0.72.4) + - React-Fabric/config (= 0.72.4) + - React-Fabric/core (= 0.72.4) + - React-Fabric/debug_renderer (= 0.72.4) + - React-Fabric/imagemanager (= 0.72.4) + - React-Fabric/leakchecker (= 0.72.4) + - React-Fabric/mapbuffer (= 0.72.4) + - React-Fabric/mounting (= 0.72.4) + - React-Fabric/scheduler (= 0.72.4) + - React-Fabric/telemetry (= 0.72.4) + - React-Fabric/templateprocessor (= 0.72.4) + - React-Fabric/textlayoutmanager (= 0.72.4) + - React-Fabric/uimanager (= 0.72.4) + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/animations (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/attributedstring (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/butter (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/componentregistry (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/componentregistrynative (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-Fabric/components/activityindicator (= 0.72.4) + - React-Fabric/components/image (= 0.72.4) + - React-Fabric/components/inputaccessory (= 0.72.4) + - React-Fabric/components/legacyviewmanagerinterop (= 0.72.4) + - React-Fabric/components/modal (= 0.72.4) + - React-Fabric/components/rncore (= 0.72.4) + - React-Fabric/components/root (= 0.72.4) + - React-Fabric/components/safeareaview (= 0.72.4) + - React-Fabric/components/scrollview (= 0.72.4) + - React-Fabric/components/text (= 0.72.4) + - React-Fabric/components/textinput (= 0.72.4) + - React-Fabric/components/unimplementedview (= 0.72.4) + - React-Fabric/components/view (= 0.72.4) + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/activityindicator (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/image (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/inputaccessory (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/legacyviewmanagerinterop (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/modal (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/rncore (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/root (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/safeareaview (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/scrollview (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/text (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/textinput (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/unimplementedview (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/components/view (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - Yoga + - React-Fabric/config (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/core (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/debug_renderer (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/imagemanager (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/leakchecker (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/mapbuffer (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/mounting (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/scheduler (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/telemetry (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/templateprocessor (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/textlayoutmanager (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-Fabric/uimanager + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-Fabric/uimanager (0.72.4): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - RCTRequired (= 0.72.4) + - RCTTypeSafety (= 0.72.4) + - React-Core + - React-debug + - React-graphics (= 0.72.4) + - React-jsi (= 0.72.4) + - React-jsiexecutor (= 0.72.4) + - React-logger + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core (= 0.72.4) + - React-graphics (0.72.4): + - glog + - RCT-Folly/Fabric (= 2021.07.22.00) + - React-Core/Default (= 0.72.4) - React-hermes (0.72.4): - DoubleConversion - glog @@ -367,6 +916,14 @@ PODS: - React-jsiexecutor (= 0.72.4) - React-jsinspector (= 0.72.4) - React-perflogger (= 0.72.4) + - React-ImageManager (0.72.4): + - glog + - RCT-Folly/Fabric + - React-Core/Default + - React-debug + - React-Fabric + - React-RCTImage + - React-utils - React-jsi (0.72.4): - boost (= 1.76.0) - DoubleConversion @@ -409,11 +966,15 @@ PODS: - RCTTypeSafety - React-Core - React-CoreModules + - React-debug + - React-graphics - React-hermes - React-NativeModulesApple + - React-RCTFabric - React-RCTImage - React-RCTNetwork - React-runtimescheduler + - React-utils - ReactCommon/turbomodule/core - React-RCTBlob (0.72.4): - hermes-engine @@ -424,6 +985,18 @@ PODS: - React-jsi (= 0.72.4) - React-RCTNetwork (= 0.72.4) - ReactCommon/turbomodule/core (= 0.72.4) + - React-RCTFabric (0.72.4): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2021.07.22.00) + - React-Core (= 0.72.4) + - React-Fabric (= 0.72.4) + - React-ImageManager + - React-RCTImage (= 0.72.4) + - React-RCTText + - React-runtimescheduler + - React-utils + - Yoga - React-RCTImage (0.72.4): - RCT-Folly (= 2021.07.22.00) - RCTTypeSafety (= 0.72.4) @@ -515,7 +1088,6 @@ DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - Flipper (= 0.182.0) - Flipper-Boost-iOSX (= 1.76.0.1.11) - Flipper-DoubleConversion (= 3.2.0.1) @@ -541,6 +1113,7 @@ DEPENDENCIES: - libevent (~> 2.1.12) - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) + - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - React (from `../node_modules/react-native/`) @@ -552,7 +1125,10 @@ DEPENDENCIES: - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) @@ -563,6 +1139,7 @@ DEPENDENCIES: - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTFabric (from `../node_modules/react-native/React`) - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) @@ -606,8 +1183,6 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" FBLazyVector: :path: "../node_modules/react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../node_modules/react-native/React/FBReactNativeSpec" glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: @@ -633,8 +1208,14 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/cxxreact" React-debug: :path: "../node_modules/react-native/ReactCommon/react/debug" + React-Fabric: + :path: "../node_modules/react-native/ReactCommon" + React-graphics: + :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" React-hermes: :path: "../node_modules/react-native/ReactCommon/hermes" + React-ImageManager: + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" React-jsi: :path: "../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: @@ -655,6 +1236,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/AppDelegate" React-RCTBlob: :path: "../node_modules/react-native/Libraries/Blob" + React-RCTFabric: + :path: "../node_modules/react-native/React" React-RCTImage: :path: "../node_modules/react-native/Libraries/Image" React-RCTLinking: @@ -687,7 +1270,6 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5 - FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 @@ -710,12 +1292,15 @@ SPEC CHECKSUMS: RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f React: a1be3c6dc0a6e949ccd3e659781aa47bbae1868f React-callinvoker: 1020b33f6cb1a1824f9ca2a86609fbce2a73c6ed - React-Codegen: a0a26badf098d4a779acda922caf74f6ecabed28 + React-Codegen: 0a4f532a16541eebba4b7f5dd2e69a396911f1bf React-Core: 52075b80f10c26f62219d7b5d13d7d8089f027b3 React-CoreModules: 21abab85d7ad9038ce2b1c33d39e3baaf7dc9244 React-cxxreact: 4ad1cc861e32fb533dad6ff7a4ea25680fa1c994 React-debug: 17366a3d5c5d2f5fc04f09101a4af38cb42b54ae + React-Fabric: bd595702c2a473faca32b59c427d927e9d3a4cc1 + React-graphics: 89d631f399096ffb5f93e19ca6908ba93a123797 React-hermes: 37377d0a56aa0cf55c65248271866ce3268cde3f + React-ImageManager: e57287a6a9d34b95c5f348a2f8773d9f6007c507 React-jsi: 6de8b0ccc6b765b58e4eee9ee38049dbeaf5c221 React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594 React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f @@ -724,15 +1309,16 @@ SPEC CHECKSUMS: React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58 React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00 React-RCTAnimation: 88feaf0a85648fb8fd497ce749829774910276d6 - React-RCTAppDelegate: 5792ac0f0feccb584765fdd7aa81ea320c4d9b0b + React-RCTAppDelegate: 035cd8f2a17fa2b7c4a957729fe35f0a55879004 React-RCTBlob: 0dbc9e2a13d241b37d46b53e54630cbad1f0e141 + React-RCTFabric: 0d443ab3cc3f0af82442ec95747d503cee955f26 React-RCTImage: b111645ab901f8e59fc68fbe31f5731bdbeef087 React-RCTLinking: 3d719727b4c098aad3588aa3559361ee0579f5de React-RCTNetwork: b44d3580be05d74556ba4efbf53570f17e38f734 React-RCTSettings: c0c54b330442c29874cd4dae6e94190dc11a6f6f React-RCTText: 9b9f5589d9b649d7246c3f336e116496df28cfe6 React-RCTVibration: 691c67f3beaf1d084ceed5eb5c1dddd9afa8591e - React-rncore: 142268f6c92e296dc079aadda3fade778562f9e4 + React-rncore: 705a03a7c9db5287f82da01a4ed5f7ed5c7dab0f React-runtimeexecutor: d465ba0c47ef3ed8281143f59605cacc2244d5c7 React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a @@ -743,6 +1329,6 @@ SPEC CHECKSUMS: Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: 03261cafaf2be596790fa09f953f81ddb585d010 +PODFILE CHECKSUM: de9931e9b87f58c6afadcb6f4e3379fa8d627287 COCOAPODS: 1.12.1 diff --git a/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj b/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj index d6371b1d6..d4f1da461 100644 --- a/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj +++ b/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj @@ -592,12 +592,16 @@ ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = "$(inherited)"; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRN_FABRIC_ENABLED", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", + "-DRN_FABRIC_ENABLED", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -657,12 +661,16 @@ "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; - OTHER_CFLAGS = "$(inherited)"; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRN_FABRIC_ENABLED", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", + "-DRN_FABRIC_ENABLED", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/src/utils/index.ts b/src/utils/index.ts index 8d0f10ada..10f9e0e15 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -71,6 +71,10 @@ export function runNativeCommand( nativeRef: any, args: NativeArg[], ): Promise { + throw new Error( + `TODO: figure out what this method actually does and do it in a way that doesn't instantly crash on the new arch`, + ); + const handle = findNodeHandle(nativeRef); if (!handle) { throw new Error(`Could not find handle for native ref ${module}.${name}`); From d8e5ae1b6577823eefee158eafcc485005c02e22 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 24 Aug 2023 13:04:30 +0200 Subject: [PATCH 03/33] Basic ios setup --- fabricexample/ios/Podfile | 5 +- fabricexample/ios/Podfile.lock | 124 +- .../fabricexample.xcodeproj/project.pbxproj | 32 +- ios/RCTMGL-v10/MBXMapViewComponentView.h | 15 + ios/RCTMGL-v10/MBXMapViewComponentView.mm | 57 + ios/RCTMGL-v10/RCTMGLMapViewManager.m | 3 +- package.json | 8 + rnmapbox-maps.podspec | 12 +- src/components/MapView.tsx | 2242 +++++++++-------- src/specs/MBXMapViewNativeComponent.ts | 49 + 10 files changed, 1307 insertions(+), 1240 deletions(-) create mode 100644 ios/RCTMGL-v10/MBXMapViewComponentView.h create mode 100644 ios/RCTMGL-v10/MBXMapViewComponentView.mm create mode 100644 src/specs/MBXMapViewNativeComponent.ts diff --git a/fabricexample/ios/Podfile b/fabricexample/ios/Podfile index 966c779d1..5ea818e94 100644 --- a/fabricexample/ios/Podfile +++ b/fabricexample/ios/Podfile @@ -19,7 +19,8 @@ prepare_react_native_project! # dependencies: { # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), # ``` -flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled + +flipper_config = FlipperConfiguration.disabled linkage = ENV['USE_FRAMEWORKS'] if linkage != nil @@ -29,6 +30,8 @@ end ENV['RCT_NEW_ARCH_ENABLED'] = '1' +use_modular_headers! + target 'fabricexample' do config = use_native_modules! diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock index 87fd8f392..af876c510 100644 --- a/fabricexample/ios/Podfile.lock +++ b/fabricexample/ios/Podfile.lock @@ -1,66 +1,7 @@ PODS: - boost (1.76.0) - - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - FBLazyVector (0.72.4) - - Flipper (0.182.0): - - Flipper-Folly (~> 2.6) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - FlipperKit (0.182.0): - - FlipperKit/Core (= 0.182.0) - - FlipperKit/Core (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.182.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.182.0) - - FlipperKit/FKPortForwarding (0.182.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.182.0) - - FlipperKit/FlipperKitLayoutHelpers (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) - hermes-engine (0.72.4): @@ -76,7 +17,6 @@ PODS: - MapboxMobileEvents (= 1.0.10) - Turf (~> 2.0) - MapboxMobileEvents (1.0.10) - - OpenSSL-Universal (1.1.1100) - RCT-Folly (2021.07.22.00): - boost - DoubleConversion @@ -1074,44 +1014,35 @@ PODS: - rnmapbox-maps/DynamicLibrary (= 10.0.12-rc.3) - Turf - rnmapbox-maps/DynamicLibrary (10.0.12-rc.3): + - hermes-engine - MapboxMaps (~> 10.15.0) + - RCT-Folly (= 2021.07.22.00) + - RCTRequired + - RCTTypeSafety - React + - React-Codegen - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-NativeModulesApple + - React-RCTFabric + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core - Turf + - Yoga - SocketRocket (0.6.1) - Turf (2.6.1) - Yoga (1.14.0) - - YogaKit (1.18.1): - - Yoga (~> 1.14) DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - Flipper (= 0.182.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - FlipperKit (= 0.182.0) - - FlipperKit/Core (= 0.182.0) - - FlipperKit/CppBridge (= 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0) - - FlipperKit/FBDefines (= 0.182.0) - - FlipperKit/FKPortForwarding (= 0.182.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0) - - FlipperKit/FlipperKitReactPlugin (= 0.182.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) @@ -1120,7 +1051,6 @@ DEPENDENCIES: - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) - - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) @@ -1156,25 +1086,14 @@ DEPENDENCIES: SPEC REPOS: trunk: - - CocoaAsyncSocket - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - FlipperKit - fmt - libevent - MapboxCommon - MapboxCoreMaps - MapboxMaps - MapboxMobileEvents - - OpenSSL-Universal - SocketRocket - Turf - - YogaKit EXTERNAL SOURCES: boost: @@ -1267,17 +1186,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: 57d2868c099736d80fcd648bf211b4431e51a558 - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5 - Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2 @@ -1286,7 +1196,6 @@ SPEC CHECKSUMS: MapboxCoreMaps: bcbaac14467616940187f79bba49ca491cd37906 MapboxMaps: 1fd9d97d0e8eceb7a45b9ac8bf87a8922da881a8 MapboxMobileEvents: de50b3a4de180dd129c326e09cd12c8adaaa46d6 - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9 RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f @@ -1323,12 +1232,11 @@ SPEC CHECKSUMS: React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d - rnmapbox-maps: 24414d4a08775776ee5ae561874bf4a457f734ad + rnmapbox-maps: 0421180d3c876686f95e02fde625f4b073885c49 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: de9931e9b87f58c6afadcb6f4e3379fa8d627287 +PODFILE CHECKSUM: 5e10b4cbc6ff307ec5fa415a884b5af5baf524e0 COCOAPODS: 1.12.1 diff --git a/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj b/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj index d4f1da461..1ab7357ee 100644 --- a/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj +++ b/fabricexample/ios/fabricexample.xcodeproj/project.pbxproj @@ -8,12 +8,12 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* fabricexampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* fabricexampleTests.m */; }; - 0C80B921A6F3F58F76C31292 /* libPods-fabricexample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-fabricexample.a */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 7699B88040F8A987B510C191 /* libPods-fabricexample-fabricexampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-fabricexample-fabricexampleTests.a */; }; + 29B24CC61AF93CAA59CB7528 /* libPods-fabricexample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F3FCC724DC45B51468E3FF7A /* libPods-fabricexample.a */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; + C701538EB5789896B565D46A /* libPods-fabricexample-fabricexampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 86D63E92E5A22897BAEF5064 /* libPods-fabricexample-fabricexampleTests.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -36,14 +36,14 @@ 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = fabricexample/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = fabricexample/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = fabricexample/main.m; sourceTree = ""; }; - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-fabricexample-fabricexampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fabricexample-fabricexampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3B4392A12AC88292D35C810B /* Pods-fabricexample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample.debug.xcconfig"; path = "Target Support Files/Pods-fabricexample/Pods-fabricexample.debug.xcconfig"; sourceTree = ""; }; 5709B34CF0A7D63546082F79 /* Pods-fabricexample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample.release.xcconfig"; path = "Target Support Files/Pods-fabricexample/Pods-fabricexample.release.xcconfig"; sourceTree = ""; }; 5B7EB9410499542E8C5724F5 /* Pods-fabricexample-fabricexampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample-fabricexampleTests.debug.xcconfig"; path = "Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests.debug.xcconfig"; sourceTree = ""; }; - 5DCACB8F33CDC322A6C60F78 /* libPods-fabricexample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fabricexample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = fabricexample/LaunchScreen.storyboard; sourceTree = ""; }; + 86D63E92E5A22897BAEF5064 /* libPods-fabricexample-fabricexampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fabricexample-fabricexampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 89C6BE57DB24E9ADA2F236DE /* Pods-fabricexample-fabricexampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-fabricexample-fabricexampleTests.release.xcconfig"; path = "Target Support Files/Pods-fabricexample-fabricexampleTests/Pods-fabricexample-fabricexampleTests.release.xcconfig"; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + F3FCC724DC45B51468E3FF7A /* libPods-fabricexample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-fabricexample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -51,7 +51,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7699B88040F8A987B510C191 /* libPods-fabricexample-fabricexampleTests.a in Frameworks */, + C701538EB5789896B565D46A /* libPods-fabricexample-fabricexampleTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -59,7 +59,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 0C80B921A6F3F58F76C31292 /* libPods-fabricexample.a in Frameworks */, + 29B24CC61AF93CAA59CB7528 /* libPods-fabricexample.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -100,8 +100,8 @@ isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 5DCACB8F33CDC322A6C60F78 /* libPods-fabricexample.a */, - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-fabricexample-fabricexampleTests.a */, + F3FCC724DC45B51468E3FF7A /* libPods-fabricexample.a */, + 86D63E92E5A22897BAEF5064 /* libPods-fabricexample-fabricexampleTests.a */, ); name = Frameworks; sourceTree = ""; @@ -580,6 +580,14 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", + "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + ); IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, @@ -650,6 +658,14 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core", + "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", + "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", + "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", + ); IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.h b/ios/RCTMGL-v10/MBXMapViewComponentView.h new file mode 100644 index 000000000..9b349fc23 --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.h @@ -0,0 +1,15 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MBXMapViewComponentView : RCTViewComponentView + +@end + +NS_ASSUME_NONNULL_END + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm new file mode 100644 index 000000000..a741bbebf --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -0,0 +1,57 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#import "MBXMapViewComponentView.h" + +#import +#import + +#import +#import +#import +#import + +using namespace facebook::react; + +@interface MBXMapViewComponentView () +@end + +@implementation MBXMapViewComponentView { + UIView *_view; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + static const auto defaultProps = std::make_shared(); + _props = defaultProps; + _view = [[UIView alloc] initWithFrame:self.bounds]; + + self.contentView = _view; + } + + return self; +} + +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + +- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps +{ + const auto &newProps = *std::static_pointer_cast(props); + + _view.backgroundColor = [UIColor greenColor]; + + [super updateProps:props oldProps:oldProps]; +} +@end + +Class MBXMapViewCls(void) +{ + return MBXMapViewComponentView.class; +} + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/ios/RCTMGL-v10/RCTMGLMapViewManager.m b/ios/RCTMGL-v10/RCTMGLMapViewManager.m index cb0c04797..d2494afd2 100644 --- a/ios/RCTMGL-v10/RCTMGLMapViewManager.m +++ b/ios/RCTMGL-v10/RCTMGLMapViewManager.m @@ -1,7 +1,8 @@ #import #import -@interface RCT_EXTERN_REMAP_MODULE(RCTMGLMapView, RCTMGLMapViewManager, RCTViewManager) +// TODO: Change it back to RCTMGLMapView +@interface RCT_EXTERN_REMAP_MODULE(MBXMapView, RCTMGLMapViewManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(onCameraChanged, RCTDirectEventBlock) diff --git a/package.json b/package.json index d4af5cc4a..033d06488 100644 --- a/package.json +++ b/package.json @@ -116,6 +116,14 @@ "react-test-renderer": "17.0.2", "typescript": "4.8.4" }, + "codegenConfig": { + "name": "rnmapbox_maps", + "type": "all", + "jsSrcsDir": "src/specs", + "android": { + "javaPackageName": "com.mapbox.rctmgl" + } + }, "jest": { "preset": "react-native", "collectCoverageFrom": [ diff --git a/rnmapbox-maps.podspec b/rnmapbox-maps.podspec index 94b0c9ae8..dd29566be 100644 --- a/rnmapbox-maps.podspec +++ b/rnmapbox-maps.podspec @@ -26,6 +26,8 @@ rnMapboxMapsDefaultMapLibreVersion = 'exactVersion 5.12.1' rnMapboxMapsDefaultImpl = 'maplibre' +new_arch_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' + # DEPRECATIONS @@ -257,11 +259,15 @@ Pod::Spec.new do |s| s.subspec 'DynamicLibrary' do |sp| case $RNMapboxMapsImpl when 'mapbox' - sp.source_files = "ios/RCTMGL-v10/**/*.{h,m,swift}" + sp.source_files = "ios/RCTMGL-v10/**/*.{h,m,mm,swift}" + + if new_arch_enabled + install_modules_dependencies(sp) + end when 'mapbox-gl' - sp.source_files = "ios/RCTMGL/**/*.{h,m}" + sp.source_files = "ios/RCTMGL/**/*.{h,m,mm}" when 'maplibre' - sp.source_files = "ios/RCTMGL/**/*.{h,m}" + sp.source_files = "ios/RCTMGL/**/*.{h,m,mm}" sp.compiler_flags = '-DRNMBGL_USE_MAPLIBRE=1' end end diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index f8940cfbd..c1853c55c 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -1,1119 +1,1123 @@ -import React, { Component } from 'react'; -import { - View, - StyleSheet, - NativeModules, - requireNativeComponent, - ViewProps, - NativeSyntheticEvent, - NativeMethods, - HostComponent, - LayoutChangeEvent, -} from 'react-native'; -import { debounce } from 'debounce'; - -import { - isFunction, - isAndroid, - type NativeArg, - type OrnamentPositonProp, -} from '../utils'; -import { getFilter } from '../utils/filterUtils'; -import Logger from '../utils/Logger'; -import { FilterExpression } from '../utils/MapboxStyles'; -import { type Position } from '../types/Position'; -import { type Location } from '../modules/location/locationManager'; - -import NativeBridgeComponent from './NativeBridgeComponent'; - -const { MGLModule } = NativeModules; -const { EventTypes } = MGLModule; - -if (MGLModule == null) { - console.error( - 'Native part of Mapbox React Native libraries were not registered properly, double check our native installation guides.', - ); -} -if (!MGLModule.MapboxV10) { - console.warn( - '@rnmapbox/maps: Non v10 implementations are deprecated and will be removed in next version - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre', - ); -} - -export const NATIVE_MODULE_NAME = 'RCTMGLMapView'; - -export const ANDROID_TEXTURE_NATIVE_MODULE_NAME = 'RCTMGLAndroidTextureMapView'; - -const styles = StyleSheet.create({ - matchParent: { flex: 1 }, -}); - -const defaultStyleURL = MGLModule.StyleURL.Street; - -export type Point = { - x: number; - y: number; -}; - -type BBox = [number, number, number, number]; - -export type RegionPayload = { - zoomLevel: number; - heading: number; - animated: boolean; - isUserInteraction: boolean; - visibleBounds: GeoJSON.Position[]; - pitch: number; -}; - -/** - * v10 only - */ -export type MapState = { - properties: { - center: GeoJSON.Position; - bounds: { - ne: GeoJSON.Position; - sw: GeoJSON.Position; - }; - zoom: number; - heading: number; - pitch: number; - }; - gestures: { - isGestureActive: boolean; - }; - timestamp?: number; -}; - -/** - * label localization settings (v10 only). `true` is equivalent to current locale. - */ -type LocalizeLabels = - | { - /** locale code like `es` or `current` for the device's current locale */ - locale: string; - /** layer id to localize. If not specified, all layers will be localized */ - layerIds?: string[]; - } - | true; - -type Props = ViewProps & { - /** - * The distance from the edges of the map view’s frame to the edges of the map view’s logical viewport. - * @deprecated use Camera `padding` instead - */ - contentInset?: number | number[]; - - /** - * The projection used when rendering the map - */ - projection?: 'mercator' | 'globe'; - - /** - * Style URL for map - notice, if non is set it _will_ default to `Mapbox.StyleURL.Street` - */ - styleURL?: string; - - /** - * StyleJSON for map - according to TileJSON specs: https://github.com/mapbox/tilejson-spec - */ - styleJSON?: string; - - /** - * iOS: The preferred frame rate at which the map view is rendered. - * The default value for this property is MGLMapViewPreferredFramesPerSecondDefault, - * which will adaptively set the preferred frame rate based on the capability of - * the user’s device to maintain a smooth experience. This property can be set to arbitrary integer values. - * - * Android: The maximum frame rate at which the map view is rendered, but it can't exceed the ability of device hardware. - * This property can be set to arbitrary integer values. - */ - preferredFramesPerSecond?: number; - - /** - * Enable/Disable zoom on the map - */ - zoomEnabled?: boolean; - - /** - * Enable/Disable scroll on the map - */ - scrollEnabled?: boolean; - - /** - * Enable/Disable pitch on map - */ - pitchEnabled?: boolean; - - /** - * Enable/Disable rotation on map - */ - rotateEnabled?: boolean; - - /** - * The Mapbox terms of service, which governs the use of Mapbox-hosted vector tiles and styles, - * [requires](https://www.mapbox.com/help/how-attribution-works/) these copyright notices to accompany any map that features Mapbox-designed styles, OpenStreetMap data, or other Mapbox data such as satellite or terrain data. - * If that applies to this map view, do not hide this view or remove any notices from it. - * - * You are additionally [required](https://www.mapbox.com/help/how-mobile-apps-work/#telemetry) to provide users with the option to disable anonymous usage and location sharing (telemetry). - * If this view is hidden, you must implement this setting elsewhere in your app. See our website for [Android](https://www.mapbox.com/android-docs/map-sdk/overview/#telemetry-opt-out) and [iOS](https://www.mapbox.com/ios-sdk/#telemetry_opt_out) for implementation details. - * - * Enable/Disable attribution on map. For iOS you need to add MGLMapboxMetricsEnabledSettingShownInApp=YES - * to your Info.plist - */ - attributionEnabled?: boolean; - - /** - * Adds attribution offset, e.g. `{top: 8, left: 8}` will put attribution button in top-left corner of the map. By default on Android, the attribution with information icon (i) will be on the bottom left, while on iOS the mapbox logo will be on bottom left with information icon (i) on bottom right. Read more about mapbox attribution [here](https://docs.mapbox.com/help/getting-started/attribution/) - */ - attributionPosition?: OrnamentPositonProp; - - /** - * MapView's tintColor - */ - tintColor?: string | number[]; - - /** - * Enable/Disable the logo on the map. - */ - logoEnabled?: boolean; - - /** - * Adds logo offset, e.g. `{top: 8, left: 8}` will put the logo in top-left corner of the map - */ - logoPosition?: OrnamentPositonProp; - - /** - * Enable/Disable the compass from appearing on the map - */ - compassEnabled?: boolean; - - /** - * [`mapbox` (v10) implementation only] Enable/Disable if the compass should fade out when the map is pointing north - */ - compassFadeWhenNorth?: boolean; - - /** - * [`mapbox` (v10) implementation only] Adds compass offset, e.g. `{top: 8, left: 8}` will put the compass in top-left corner of the map - */ - compassPosition?: OrnamentPositonProp; - - /** - * Change corner of map the compass starts at. 0: TopLeft, 1: TopRight, 2: BottomLeft, 3: BottomRight - */ - compassViewPosition?: number; - - /** - * Add margins to the compass with x and y values - */ - compassViewMargins?: Point; - - /** - * [iOS, `mapbox` (v10) implementation only] A string referencing an image key. Requires an `Images` component. - */ - compassImage?: string; - - /** - * [`mapbox` (v10) implementation only] Enable/Disable the scale bar from appearing on the map - */ - scaleBarEnabled?: boolean; - - /** - * [`mapbox` (v10) implementation only] Adds scale bar offset, e.g. `{top: 8, left: 8}` will put the scale bar in top-left corner of the map - */ - scaleBarPosition?: OrnamentPositonProp; - - /** - * [Android only] Enable/Disable use of GLSurfaceView instead of TextureView. - */ - surfaceView?: boolean; - - /** - * [Android only] Experimental, call requestDisallowInterceptTouchEvent on parent with onTochEvent, this allows touch interaction to work - * when embedded into a scroll view - */ - requestDisallowInterceptTouchEvent?: boolean; - - /** - * [`mapbox` (v10) implementation only] - * Set map's label locale, e.g. { "locale": "es" } will localize labels to Spanish, { "locale": "current" } will localize labels to system locale. - */ - localizeLabels?: LocalizeLabels; - - /** - * Map press listener, gets called when a user presses the map - */ - onPress?: (feature: GeoJSON.Feature) => void; - - /** - * Map long press listener, gets called when a user long presses the map - */ - onLongPress?: (feature: GeoJSON.Feature) => void; - - /** - * , - ) => void; - - /** - * - * This event is triggered whenever the currently displayed map region is changing. - * - * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds - */ - onRegionIsChanging?: ( - feature: GeoJSON.Feature, - ) => void; - - /** - * - * This event is triggered whenever the currently displayed map region finished changing. - * - * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds - */ - onRegionDidChange?: ( - feature: GeoJSON.Feature, - ) => void; - - /** - * v10 only, replaces onRegionIsChanging - */ - onCameraChanged?: (state: MapState) => void; - - /** - * v10 only, replaces onRegionDidChange - */ - onMapIdle?: (state: MapState) => void; - - /** - * This event is triggered when the map is about to start loading a new map style. - */ - onWillStartLoadingMap?: () => void; - - /** - * This is triggered when the map has successfully loaded a new map style. - */ - onDidFinishLoadingMap?: () => void; - - /** - * This event is triggered when the map has failed to load a new map style. On v10 it's deprecated and replaced by onMapLoadingError - * @deprecated use onMapLoadingError - */ - onDidFailLoadingMap?: () => void; - - /** - * This event is tiggered when there is an error during map load. V10 only, replaces onDidFailLoadingMap, might be called multiple times and not exclusive with onDidFinishLoadingMap. - */ - onMapLoadingError?: () => void; - - /** - * This event is triggered when the map will start rendering a frame. - */ - onWillStartRenderingFrame?: () => void; - - /** - * This event is triggered when the map finished rendering a frame. - */ - onDidFinishRenderingFrame?: () => void; - - /** - * This event is triggered when the map fully finished rendering a frame. - */ - onDidFinishRenderingFrameFully?: () => void; - - /** - * This event is triggered when the map will start rendering the map. - */ - onWillStartRenderingMap?: () => void; - - /** - * This event is triggered when the map finished rendering the map. - */ - onDidFinishRenderingMap?: () => void; - - /** - * This event is triggered when the map fully finished rendering the map. - */ - onDidFinishRenderingMapFully?: () => void; - - /** - * This event is triggered when the user location is updated. - */ - onUserLocationUpdate?: (feature: Location) => void; - - /** - * This event is triggered when a style has finished loading. - */ - onDidFinishLoadingStyle?: () => void; - - /** - * The emitted frequency of regionwillchange events - */ - regionWillChangeDebounceTime?: number; - - /** - * The emitted frequency of regiondidchange events - */ - regionDidChangeDebounceTime?: number; -}; - -type CallbablePropKeys = - | 'onRegionWillChange' - | 'onRegionIsChanging' - | 'onRegionDidChange' - | 'onUserLocationUpdate' - | 'onWillStartLoadingMap' - | 'onMapLoadingError' - | 'onDidFinishLoadingMap' - | 'onDidFailLoadingMap' - | 'onWillStartRenderingFrame' - | 'onDidFinishRenderingFrame' - | 'onDidFinishRenderingFrameFully' - | 'onWillStartRenderingMap' - | 'onDidFinishRenderingMap' - | 'onDidFinishRenderingMapFully' - | 'onDidFinishLoadingStyle' - | 'onMapIdle' - | 'onCameraChanged'; - -type CallbablePropKeysWithoutOn = CallbablePropKeys extends `on${infer C}` - ? C - : never; - -type Debounced = F & { clear(): void; flush(): void }; - -/** - * MapView backed by Mapbox Native GL - */ -class MapView extends NativeBridgeComponent( - React.PureComponent, - NATIVE_MODULE_NAME, -) { - static defaultProps: Props = { - projection: 'mercator', - scrollEnabled: true, - pitchEnabled: true, - rotateEnabled: true, - attributionEnabled: true, - compassEnabled: false, - compassFadeWhenNorth: false, - logoEnabled: true, - scaleBarEnabled: true, - surfaceView: MGLModule.MapboxV10 ? true : false, - requestDisallowInterceptTouchEvent: false, - regionWillChangeDebounceTime: 10, - regionDidChangeDebounceTime: 500, - }; - - deprecationLogged: { - contentInset: boolean; - regionDidChange: boolean; - regionIsChanging: boolean; - } = { - contentInset: false, - regionDidChange: false, - regionIsChanging: false, - }; - logger: Logger; - _onDebouncedRegionWillChange: Debounced< - ( - payload: GeoJSON.Feature< - GeoJSON.Point, - RegionPayload & { isAnimatingFromUserInteraction: boolean } - >, - ) => void - >; - _onDebouncedRegionDidChange: Debounced< - ( - payload: GeoJSON.Feature< - GeoJSON.Point, - RegionPayload & { isAnimatingFromUserInteraction: boolean } - >, - ) => void - >; - _nativeRef?: RCTMGLMapViewRefType; - state: { - isReady: boolean | null; - region: null; - width: number; - height: number; - isUserInteraction: boolean; - }; - - constructor(props: Props) { - super(props); - - this.logger = Logger.sharedInstance(); - this.logger.start(); - - this.state = { - isReady: null, - region: null, - width: 0, - height: 0, - isUserInteraction: false, - }; - - this._onPress = this._onPress.bind(this); - this._onLongPress = this._onLongPress.bind(this); - this._onChange = this._onChange.bind(this); - this._onLayout = this._onLayout.bind(this); - this._onCameraChanged = this._onCameraChanged.bind(this); - - // debounced map change methods - this._onDebouncedRegionWillChange = debounce( - this._onRegionWillChange.bind(this), - props.regionWillChangeDebounceTime, - true, - ); - - this._onDebouncedRegionDidChange = debounce( - this._onRegionDidChange.bind(this), - props.regionDidChangeDebounceTime, - ); - } - - componentDidMount() { - this._setHandledMapChangedEvents(this.props); - } - - componentWillUnmount() { - this._onDebouncedRegionWillChange.clear(); - this._onDebouncedRegionDidChange.clear(); - this.logger.stop(); - } - - UNSAFE_componentWillReceiveProps(nextProps: Props) { - this._setHandledMapChangedEvents(nextProps); - } - - _setHandledMapChangedEvents(props: Props) { - if (isAndroid() || MGLModule.MapboxV10) { - const events: string[] = []; - - function addIfHasHandler(name: CallbablePropKeysWithoutOn) { - if (props[`on${name}`] != null) { - if (EventTypes[name] == null) { - if (name === 'DidFailLoadingMap') { - console.warn( - `rnmapbox maps: on${name} is deprecated, please use onMapLoadingError`, - ); - } else { - console.warn(`rnmapbox maps: ${name} is not supported`); - } - } else { - events.push(EventTypes[name]); - return true; - } - } - return false; - } - - addIfHasHandler('RegionWillChange'); - addIfHasHandler('RegionIsChanging'); - addIfHasHandler('RegionDidChange'); - addIfHasHandler('UserLocationUpdate'); - addIfHasHandler('WillStartLoadingMap'); - addIfHasHandler('DidFinishLoadingMap'); - addIfHasHandler('MapLoadingError'); - addIfHasHandler('DidFailLoadingMap'); - addIfHasHandler('WillStartRenderingFrame'); - addIfHasHandler('DidFinishRenderingFrame'); - addIfHasHandler('DidFinishRenderingFrameFully'); - addIfHasHandler('WillStartRenderingMap'); - addIfHasHandler('DidFinishRenderingMap'); - addIfHasHandler('DidFinishRenderingMapFully'); - addIfHasHandler('DidFinishLoadingStyle'); - - addIfHasHandler('CameraChanged'); - addIfHasHandler('MapIdle'); - - if (addIfHasHandler('RegionDidChange')) { - if (!this.deprecationLogged.regionDidChange) { - console.warn( - 'onRegionDidChange is deprecated and will be removed in next release - please use onMapIdle. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', - ); - this.deprecationLogged.regionDidChange = true; - } - if (props.onMapIdle) { - console.warn( - 'rnmapbox/maps: only one of MapView.onRegionDidChange or onMapIdle is supported', - ); - } - } - if (addIfHasHandler('RegionIsChanging')) { - if (!this.deprecationLogged.regionIsChanging) { - console.warn( - 'onRegionIsChanging is deprecated and will be removed in next release - please use onCameraChanged. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', - ); - this.deprecationLogged.regionIsChanging = true; - } - if (props.onCameraChanged) { - console.warn( - 'rnmapbox/maps: only one of MapView.onRegionIsChanging or onCameraChanged is supported', - ); - } - } - - if (props.onRegionWillChange) { - console.warn( - 'onRegionWillChange is deprecated and will be removed in v10 - please use onRegionIsChanging', - ); - } - - this._runNativeCommand('setHandledMapChangedEvents', this._nativeRef, [ - events, - ]); - } - } - - /** - * Converts a geographic coordinate to a point in the given view’s coordinate system. - * - * @example - * const pointInView = await this._map.getPointInView([-37.817070, 144.949901]); - * - * @param {Array} coordinate - A point expressed in the map view's coordinate system. - * @return {Array} - */ - async getPointInView(coordinate: Position): Promise { - const res = await this._runNative<{ pointInView: Position }>( - 'getPointInView', - [coordinate], - ); - return res.pointInView; - } - - /** - * Converts a point in the given view’s coordinate system to a geographic coordinate. - * - * @example - * const coordinate = await this._map.getCoordinateFromView([100, 100]); - * - * @param {Array} point - A point expressed in the given view’s coordinate system. - * @return {Array} - */ - async getCoordinateFromView(point: Position): Promise { - const res = await this._runNative<{ coordinateFromView: Position }>( - 'getCoordinateFromView', - [point], - ); - return res.coordinateFromView; - } - - /** - * The coordinate bounds (ne, sw) visible in the user’s viewport. - * - * @example - * const visibleBounds = await this._map.getVisibleBounds(); - * - * @return {Array} - */ - async getVisibleBounds(): Promise<[Position, Position]> { - const res = await this._runNative<{ visibleBounds: [Position, Position] }>( - 'getVisibleBounds', - ); - return res.visibleBounds; - } - - /** - * Returns an array of rendered map features that intersect with a given point. - * - * @example - * this._map.queryRenderedFeaturesAtPoint([30, 40], ['==', 'type', 'Point'], ['id1', 'id2']) - * - * @param {Array} coordinate - A point expressed in the map view’s coordinate system. - * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. - * @param {Array=} layerIDs - A array of layer id's to filter the features by - * @return {FeatureCollection} - */ - - async queryRenderedFeaturesAtPoint( - coordinate: Position, - filter: FilterExpression | [] = [], - layerIDs: string[] = [], - ): Promise { - if (!coordinate || coordinate.length < 2) { - throw new Error('Must pass in valid coordinate[lng, lat]'); - } - - const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( - 'queryRenderedFeaturesAtPoint', - [coordinate, getFilter(filter), layerIDs], - ); - - if (isAndroid()) { - return JSON.parse(res.data as unknown as string); - } - - return res.data as GeoJSON.FeatureCollection; - } - - /** - * Returns an array of rendered map features that intersect with the given rectangle, - * restricted to the given style layers and filtered by the given predicate. In v10, - * passing an empty array will query the entire visible bounds of the map. - * - * @example - * this._map.queryRenderedFeaturesInRect([30, 40, 20, 10], ['==', 'type', 'Point'], ['id1', 'id2']) - * - * @param {Array} bbox - A rectangle expressed in the map view’s coordinate system. For v10, this can be an empty array to query the visible map area. - * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. - * @param {Array=} layerIDs - A array of layer id's to filter the features by - * @return {FeatureCollection} - */ - async queryRenderedFeaturesInRect( - bbox: BBox | [], - filter: FilterExpression | [] = [], - layerIDs: string[] | null = null, - ): Promise { - if ( - bbox != null && - (bbox.length === 4 || (MGLModule.MapboxV10 && bbox.length === 0)) - ) { - const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( - 'queryRenderedFeaturesInRect', - [bbox, getFilter(filter), layerIDs], - ); - - if (isAndroid()) { - return JSON.parse(res.data as unknown as string); - } - - return res.data; - } else { - throw new Error( - 'Must pass in a valid bounding box: [top, right, bottom, left]. An empty array [] is also acceptable in v10.', - ); - } - } - - /** - * Returns an array of GeoJSON Feature objects representing features within the specified vector tile or GeoJSON source that satisfy the query parameters. - * - * @example - * this._map.querySourceFeatures('your-source-id', [], ['your-source-layer']) - * - * @param {String} sourceId - Style source identifier used to query for source features. - * @param {Array=} filter - A filter to limit query results. - * @param {Array=} sourceLayerIDs - The name of the source layers to query. For vector tile sources, this parameter is required. For GeoJSON sources, it is ignored. - * @return {FeatureCollection} - */ - async querySourceFeatures( - sourceId: string, - filter: FilterExpression | [] = [], - sourceLayerIDs: string[] = [], - ): Promise { - const args = [sourceId, getFilter(filter), sourceLayerIDs]; - const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( - 'querySourceFeatures', - args, - ); - - if (isAndroid()) { - return JSON.parse(res.data as unknown as string); - } - - return res.data; - } - - /** - * Map camera will perform updates based on provided config. Deprecated use Camera#setCamera. - * @deprecated use Camera#setCamera - */ - setCamera() { - console.warn( - 'MapView.setCamera is deprecated - please use Camera#setCamera', - ); - } - - _runNative( - methodName: string, - args: NativeArg[] = [], - ): Promise { - return super._runNativeCommand( - methodName, - this._nativeRef as HostComponent | undefined, - args, - ); - } - - /** - * Takes snapshot of map with current tiles and returns a URI to the image - * @param {Boolean} writeToDisk If true will create a temp file, otherwise it is in base64 - * @return {String} - */ - async takeSnap(writeToDisk = false): Promise { - const res = await this._runNative<{ uri: string }>('takeSnap', [ - writeToDisk, - ]); - return res.uri; - } - - /** - * Returns the current zoom of the map view. - * - * @example - * const zoom = await this._map.getZoom(); - * - * @return {Number} - */ - - async getZoom(): Promise { - const res = await this._runNative<{ zoom: number }>('getZoom'); - return res.zoom; - } - - /** - * Returns the map's geographical centerpoint - * - * @example - * const center = await this._map.getCenter(); - * - * @return {Array} Coordinates - */ - async getCenter(): Promise { - const res = await this._runNative<{ center: Position }>('getCenter'); - return res.center; - } - - /** - * - * Clears temporary map data from the data path defined in the given resource - * options. Useful to reduce the disk usage or in case the disk cache contains - * invalid data. - * - * v10 only - */ - async clearData(): Promise { - if (!MGLModule.MapboxV10) { - console.warn( - 'RNMapbox: clearData is only implemented in v10 implementation or later', - ); - return; - } - await this._runNative('clearData'); - } - - /** - * Queries the currently loaded data for elevation at a geographical location. - * The elevation is returned in meters relative to mean sea-level. - * Returns null if terrain is disabled or if terrain data for the location hasn't been loaded yet. - * - * @param {Array} coordinate - the coordinates to query elevation at - * @return {Number} - */ - async queryTerrainElevation(coordinate: Position): Promise { - const res = await this._runNative<{ data: number }>( - 'queryTerrainElevation', - [coordinate], - ); - return res.data; - } - - /** - * Sets the visibility of all the layers referencing the specified `sourceLayerId` and/or `sourceId` - * - * @example - * await this._map.setSourceVisibility(false, 'composite', 'building') - * - * @param {boolean} visible - Visibility of the layers - * @param {String} sourceId - Identifier of the target source (e.g. 'composite') - * @param {String=} sourceLayerId - Identifier of the target source-layer (e.g. 'building') - */ - setSourceVisibility( - visible: boolean, - sourceId: string, - sourceLayerId: string | null = null, - ) { - this._runNative('setSourceVisibility', [ - visible, - sourceId, - sourceLayerId, - ]); - } - - /** - * Show the attribution and telemetry action sheet. - * If you implement a custom attribution button, you should add this action to the button. - */ - showAttribution() { - return this._runNativeCommand('showAttribution', this._nativeRef); - } - - _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { - if (isFunction(this.props.onPress)) { - this.props.onPress(e.nativeEvent.payload); - } - } - - _onLongPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { - if (isFunction(this.props.onLongPress)) { - this.props.onLongPress(e.nativeEvent.payload); - } - } - - _onRegionWillChange( - payload: GeoJSON.Feature< - GeoJSON.Point, - RegionPayload & { isAnimatingFromUserInteraction: boolean } - >, - ) { - if (isFunction(this.props.onRegionWillChange)) { - this.props.onRegionWillChange(payload); - } - this.setState({ - isUserInteraction: payload.properties.isUserInteraction, - isAnimatingFromUserInteraction: - payload.properties.isAnimatingFromUserInteraction, - }); - } - - _onRegionDidChange(payload: GeoJSON.Feature) { - if (isFunction(this.props.onRegionDidChange)) { - this.props.onRegionDidChange(payload); - } - this.setState({ region: payload }); - } - - _onCameraChanged(e: NativeSyntheticEvent<{ payload: MapState }>) { - this.props.onCameraChanged?.(e.nativeEvent.payload); - } - - _onChange( - e: NativeSyntheticEvent<{ - type: string; - payload: GeoJSON.Feature< - GeoJSON.Point, - RegionPayload & { isAnimatingFromUserInteraction: boolean } - >; - }>, - ) { - const { regionWillChangeDebounceTime, regionDidChangeDebounceTime } = - this.props; - const { type, payload } = e.nativeEvent; - let propName: CallbablePropKeys | '' = ''; - let deprecatedPropName: CallbablePropKeys | '' = ''; - - switch (type) { - case EventTypes.RegionWillChange: - if (regionWillChangeDebounceTime && regionWillChangeDebounceTime > 0) { - this._onDebouncedRegionWillChange(payload); - } else { - propName = 'onRegionWillChange'; - } - break; - case EventTypes.RegionIsChanging: - propName = 'onRegionIsChanging'; - break; - case EventTypes.RegionDidChange: - if (regionDidChangeDebounceTime && regionDidChangeDebounceTime > 0) { - this._onDebouncedRegionDidChange(payload); - } else { - propName = 'onRegionDidChange'; - } - break; - case EventTypes.CameraChanged: - propName = 'onCameraChanged'; - break; - case EventTypes.MapIdle: - propName = 'onMapIdle'; - break; - case EventTypes.UserLocationUpdated: - propName = 'onUserLocationUpdate'; - break; - case EventTypes.WillStartLoadingMap: - propName = 'onWillStartLoadingMap'; - break; - case EventTypes.DidFinishLoadingMap: - propName = 'onDidFinishLoadingMap'; - break; - case EventTypes.DidFailLoadingMap: - propName = 'onDidFailLoadingMap'; - break; - case EventTypes.MapLoadingError: - propName = 'onMapLoadingError'; - deprecatedPropName = 'onDidFailLoadingMap'; - break; - case EventTypes.WillStartRenderingFrame: - propName = 'onWillStartRenderingFrame'; - break; - case EventTypes.DidFinishRenderingFrame: - propName = 'onDidFinishRenderingFrame'; - break; - case EventTypes.DidFinishRenderingFrameFully: - propName = 'onDidFinishRenderingFrameFully'; - break; - case EventTypes.WillStartRenderingMap: - propName = 'onWillStartRenderingMap'; - break; - case EventTypes.DidFinishRenderingMap: - propName = 'onDidFinishRenderingMap'; - break; - case EventTypes.DidFinishRenderingMapFully: - propName = 'onDidFinishRenderingMapFully'; - break; - case EventTypes.DidFinishLoadingStyle: - propName = 'onDidFinishLoadingStyle'; - break; - default: - console.warn('Unhandled event callback type', type); - } - - if (propName !== '') { - this._handleOnChange(propName, payload); - } - if (deprecatedPropName !== '') { - this._handleOnChange(deprecatedPropName, payload); - } - } - - _onLayout(e: LayoutChangeEvent) { - this.setState({ - isReady: true, - width: e.nativeEvent.layout.width, - height: e.nativeEvent.layout.height, - }); - } - - _handleOnChange(propName: CallbablePropKeys, payload: object) { - const func = this.props[propName] as (payload: object) => void; - if (func && isFunction(func)) { - func(payload); - } - } - - _getContentInset() { - if (!this.props.contentInset) { - return; - } - - if (MGLModule.MapboxV10) { - if (!this.deprecationLogged.contentInset) { - console.warn( - '@rnmapbox/maps: contentInset is deprecated, use Camera padding instead.', - ); - this.deprecationLogged.contentInset = true; - } - } - - if (!Array.isArray(this.props.contentInset)) { - return [this.props.contentInset]; - } - - return this.props.contentInset; - } - - _setNativeRef(nativeRef: RCTMGLMapViewRefType) { - this._nativeRef = nativeRef; - super._runPendingNativeCommands(nativeRef); - } - - setNativeProps(props: NativeProps) { - if (this._nativeRef) { - this._nativeRef.setNativeProps(props); - } - } - - _setStyleURL(props: Props) { - // user set a styleURL, no need to alter props - if (props.styleURL) { - return; - } - - // user set styleJSON pass it to styleURL - if (props.styleJSON && !props.styleURL) { - props.styleURL = props.styleJSON; - } - - // user neither set styleJSON nor styleURL - // set defaultStyleUrl - if (!props.styleJSON || !props.styleURL) { - props.styleURL = defaultStyleURL; - } - } - - _setLocalizeLabels(props: Props) { - if (!MGLModule.MapboxV10) { - return; - } - if (typeof props.localizeLabels === 'boolean') { - props.localizeLabels = { - locale: 'current', - }; - } - } - - render() { - const props = { - ...this.props, - contentInset: this._getContentInset(), - style: styles.matchParent, - }; - - this._setStyleURL(props); - this._setLocalizeLabels(props); - - const callbacks = { - ref: (nativeRef: RCTMGLMapViewRefType) => this._setNativeRef(nativeRef), - onPress: this._onPress, - onLongPress: this._onLongPress, - onMapChange: this._onChange, - onAndroidCallback: isAndroid() ? this._onAndroidCallback : undefined, - onCameraChanged: this._onCameraChanged, - }; - - let mapView = null; - if (isAndroid() && !this.props.surfaceView && this.state.isReady) { - mapView = ( - - {this.props.children} - - ); - } else if (this.state.isReady) { - mapView = ( - - {this.props.children} - - ); - } - - return ( - - {mapView} - - ); - } -} - -type NativeProps = Omit< - Props, - 'onPress' | 'onLongPress' | 'onCameraChanged' -> & { - onPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; - onLongPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; - onCameraChanged(event: NativeSyntheticEvent<{ payload: MapState }>): void; -}; - -type RCTMGLMapViewRefType = Component & Readonly; -const RCTMGLMapView = requireNativeComponent(NATIVE_MODULE_NAME); - -let RCTMGLAndroidTextureMapView: typeof RCTMGLMapView; -if (isAndroid()) { - RCTMGLAndroidTextureMapView = requireNativeComponent( - ANDROID_TEXTURE_NATIVE_MODULE_NAME, - ); -} - -export default MapView; +import View from '../specs/MBXMapViewNativeComponent'; + +export default View; + +// import React, { Component } from 'react'; +// import { +// View, +// StyleSheet, +// NativeModules, +// requireNativeComponent, +// ViewProps, +// NativeSyntheticEvent, +// NativeMethods, +// HostComponent, +// LayoutChangeEvent, +// } from 'react-native'; +// import { debounce } from 'debounce'; + +// import { +// isFunction, +// isAndroid, +// type NativeArg, +// type OrnamentPositonProp, +// } from '../utils'; +// import { getFilter } from '../utils/filterUtils'; +// import Logger from '../utils/Logger'; +// import { FilterExpression } from '../utils/MapboxStyles'; +// import { type Position } from '../types/Position'; +// import { type Location } from '../modules/location/locationManager'; + +// import NativeBridgeComponent from './NativeBridgeComponent'; + +// const { MGLModule } = NativeModules; +// const { EventTypes } = MGLModule; + +// if (MGLModule == null) { +// console.error( +// 'Native part of Mapbox React Native libraries were not registered properly, double check our native installation guides.', +// ); +// } +// if (!MGLModule.MapboxV10) { +// console.warn( +// '@rnmapbox/maps: Non v10 implementations are deprecated and will be removed in next version - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre', +// ); +// } + +// export const NATIVE_MODULE_NAME = 'RCTMGLMapView'; + +// export const ANDROID_TEXTURE_NATIVE_MODULE_NAME = 'RCTMGLAndroidTextureMapView'; + +// const styles = StyleSheet.create({ +// matchParent: { flex: 1 }, +// }); + +// const defaultStyleURL = MGLModule.StyleURL.Street; + +// export type Point = { +// x: number; +// y: number; +// }; + +// type BBox = [number, number, number, number]; + +// export type RegionPayload = { +// zoomLevel: number; +// heading: number; +// animated: boolean; +// isUserInteraction: boolean; +// visibleBounds: GeoJSON.Position[]; +// pitch: number; +// }; + +// /** +// * v10 only +// */ +// export type MapState = { +// properties: { +// center: GeoJSON.Position; +// bounds: { +// ne: GeoJSON.Position; +// sw: GeoJSON.Position; +// }; +// zoom: number; +// heading: number; +// pitch: number; +// }; +// gestures: { +// isGestureActive: boolean; +// }; +// timestamp?: number; +// }; + +// /** +// * label localization settings (v10 only). `true` is equivalent to current locale. +// */ +// type LocalizeLabels = +// | { +// /** locale code like `es` or `current` for the device's current locale */ +// locale: string; +// /** layer id to localize. If not specified, all layers will be localized */ +// layerIds?: string[]; +// } +// | true; + +// type Props = ViewProps & { +// /** +// * The distance from the edges of the map view’s frame to the edges of the map view’s logical viewport. +// * @deprecated use Camera `padding` instead +// */ +// contentInset?: number | number[]; + +// /** +// * The projection used when rendering the map +// */ +// projection?: 'mercator' | 'globe'; + +// /** +// * Style URL for map - notice, if non is set it _will_ default to `Mapbox.StyleURL.Street` +// */ +// styleURL?: string; + +// /** +// * StyleJSON for map - according to TileJSON specs: https://github.com/mapbox/tilejson-spec +// */ +// styleJSON?: string; + +// /** +// * iOS: The preferred frame rate at which the map view is rendered. +// * The default value for this property is MGLMapViewPreferredFramesPerSecondDefault, +// * which will adaptively set the preferred frame rate based on the capability of +// * the user’s device to maintain a smooth experience. This property can be set to arbitrary integer values. +// * +// * Android: The maximum frame rate at which the map view is rendered, but it can't exceed the ability of device hardware. +// * This property can be set to arbitrary integer values. +// */ +// preferredFramesPerSecond?: number; + +// /** +// * Enable/Disable zoom on the map +// */ +// zoomEnabled?: boolean; + +// /** +// * Enable/Disable scroll on the map +// */ +// scrollEnabled?: boolean; + +// /** +// * Enable/Disable pitch on map +// */ +// pitchEnabled?: boolean; + +// /** +// * Enable/Disable rotation on map +// */ +// rotateEnabled?: boolean; + +// /** +// * The Mapbox terms of service, which governs the use of Mapbox-hosted vector tiles and styles, +// * [requires](https://www.mapbox.com/help/how-attribution-works/) these copyright notices to accompany any map that features Mapbox-designed styles, OpenStreetMap data, or other Mapbox data such as satellite or terrain data. +// * If that applies to this map view, do not hide this view or remove any notices from it. +// * +// * You are additionally [required](https://www.mapbox.com/help/how-mobile-apps-work/#telemetry) to provide users with the option to disable anonymous usage and location sharing (telemetry). +// * If this view is hidden, you must implement this setting elsewhere in your app. See our website for [Android](https://www.mapbox.com/android-docs/map-sdk/overview/#telemetry-opt-out) and [iOS](https://www.mapbox.com/ios-sdk/#telemetry_opt_out) for implementation details. +// * +// * Enable/Disable attribution on map. For iOS you need to add MGLMapboxMetricsEnabledSettingShownInApp=YES +// * to your Info.plist +// */ +// attributionEnabled?: boolean; + +// /** +// * Adds attribution offset, e.g. `{top: 8, left: 8}` will put attribution button in top-left corner of the map. By default on Android, the attribution with information icon (i) will be on the bottom left, while on iOS the mapbox logo will be on bottom left with information icon (i) on bottom right. Read more about mapbox attribution [here](https://docs.mapbox.com/help/getting-started/attribution/) +// */ +// attributionPosition?: OrnamentPositonProp; + +// /** +// * MapView's tintColor +// */ +// tintColor?: string | number[]; + +// /** +// * Enable/Disable the logo on the map. +// */ +// logoEnabled?: boolean; + +// /** +// * Adds logo offset, e.g. `{top: 8, left: 8}` will put the logo in top-left corner of the map +// */ +// logoPosition?: OrnamentPositonProp; + +// /** +// * Enable/Disable the compass from appearing on the map +// */ +// compassEnabled?: boolean; + +// /** +// * [`mapbox` (v10) implementation only] Enable/Disable if the compass should fade out when the map is pointing north +// */ +// compassFadeWhenNorth?: boolean; + +// /** +// * [`mapbox` (v10) implementation only] Adds compass offset, e.g. `{top: 8, left: 8}` will put the compass in top-left corner of the map +// */ +// compassPosition?: OrnamentPositonProp; + +// /** +// * Change corner of map the compass starts at. 0: TopLeft, 1: TopRight, 2: BottomLeft, 3: BottomRight +// */ +// compassViewPosition?: number; + +// /** +// * Add margins to the compass with x and y values +// */ +// compassViewMargins?: Point; + +// /** +// * [iOS, `mapbox` (v10) implementation only] A string referencing an image key. Requires an `Images` component. +// */ +// compassImage?: string; + +// /** +// * [`mapbox` (v10) implementation only] Enable/Disable the scale bar from appearing on the map +// */ +// scaleBarEnabled?: boolean; + +// /** +// * [`mapbox` (v10) implementation only] Adds scale bar offset, e.g. `{top: 8, left: 8}` will put the scale bar in top-left corner of the map +// */ +// scaleBarPosition?: OrnamentPositonProp; + +// /** +// * [Android only] Enable/Disable use of GLSurfaceView instead of TextureView. +// */ +// surfaceView?: boolean; + +// /** +// * [Android only] Experimental, call requestDisallowInterceptTouchEvent on parent with onTochEvent, this allows touch interaction to work +// * when embedded into a scroll view +// */ +// requestDisallowInterceptTouchEvent?: boolean; + +// /** +// * [`mapbox` (v10) implementation only] +// * Set map's label locale, e.g. { "locale": "es" } will localize labels to Spanish, { "locale": "current" } will localize labels to system locale. +// */ +// localizeLabels?: LocalizeLabels; + +// /** +// * Map press listener, gets called when a user presses the map +// */ +// onPress?: (feature: GeoJSON.Feature) => void; + +// /** +// * Map long press listener, gets called when a user long presses the map +// */ +// onLongPress?: (feature: GeoJSON.Feature) => void; + +// /** +// * , +// ) => void; + +// /** +// * +// * This event is triggered whenever the currently displayed map region is changing. +// * +// * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds +// */ +// onRegionIsChanging?: ( +// feature: GeoJSON.Feature, +// ) => void; + +// /** +// * +// * This event is triggered whenever the currently displayed map region finished changing. +// * +// * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds +// */ +// onRegionDidChange?: ( +// feature: GeoJSON.Feature, +// ) => void; + +// /** +// * v10 only, replaces onRegionIsChanging +// */ +// onCameraChanged?: (state: MapState) => void; + +// /** +// * v10 only, replaces onRegionDidChange +// */ +// onMapIdle?: (state: MapState) => void; + +// /** +// * This event is triggered when the map is about to start loading a new map style. +// */ +// onWillStartLoadingMap?: () => void; + +// /** +// * This is triggered when the map has successfully loaded a new map style. +// */ +// onDidFinishLoadingMap?: () => void; + +// /** +// * This event is triggered when the map has failed to load a new map style. On v10 it's deprecated and replaced by onMapLoadingError +// * @deprecated use onMapLoadingError +// */ +// onDidFailLoadingMap?: () => void; + +// /** +// * This event is tiggered when there is an error during map load. V10 only, replaces onDidFailLoadingMap, might be called multiple times and not exclusive with onDidFinishLoadingMap. +// */ +// onMapLoadingError?: () => void; + +// /** +// * This event is triggered when the map will start rendering a frame. +// */ +// onWillStartRenderingFrame?: () => void; + +// /** +// * This event is triggered when the map finished rendering a frame. +// */ +// onDidFinishRenderingFrame?: () => void; + +// /** +// * This event is triggered when the map fully finished rendering a frame. +// */ +// onDidFinishRenderingFrameFully?: () => void; + +// /** +// * This event is triggered when the map will start rendering the map. +// */ +// onWillStartRenderingMap?: () => void; + +// /** +// * This event is triggered when the map finished rendering the map. +// */ +// onDidFinishRenderingMap?: () => void; + +// /** +// * This event is triggered when the map fully finished rendering the map. +// */ +// onDidFinishRenderingMapFully?: () => void; + +// /** +// * This event is triggered when the user location is updated. +// */ +// onUserLocationUpdate?: (feature: Location) => void; + +// /** +// * This event is triggered when a style has finished loading. +// */ +// onDidFinishLoadingStyle?: () => void; + +// /** +// * The emitted frequency of regionwillchange events +// */ +// regionWillChangeDebounceTime?: number; + +// /** +// * The emitted frequency of regiondidchange events +// */ +// regionDidChangeDebounceTime?: number; +// }; + +// type CallbablePropKeys = +// | 'onRegionWillChange' +// | 'onRegionIsChanging' +// | 'onRegionDidChange' +// | 'onUserLocationUpdate' +// | 'onWillStartLoadingMap' +// | 'onMapLoadingError' +// | 'onDidFinishLoadingMap' +// | 'onDidFailLoadingMap' +// | 'onWillStartRenderingFrame' +// | 'onDidFinishRenderingFrame' +// | 'onDidFinishRenderingFrameFully' +// | 'onWillStartRenderingMap' +// | 'onDidFinishRenderingMap' +// | 'onDidFinishRenderingMapFully' +// | 'onDidFinishLoadingStyle' +// | 'onMapIdle' +// | 'onCameraChanged'; + +// type CallbablePropKeysWithoutOn = CallbablePropKeys extends `on${infer C}` +// ? C +// : never; + +// type Debounced = F & { clear(): void; flush(): void }; + +// /** +// * MapView backed by Mapbox Native GL +// */ +// class MapView extends NativeBridgeComponent( +// React.PureComponent, +// NATIVE_MODULE_NAME, +// ) { +// static defaultProps: Props = { +// projection: 'mercator', +// scrollEnabled: true, +// pitchEnabled: true, +// rotateEnabled: true, +// attributionEnabled: true, +// compassEnabled: false, +// compassFadeWhenNorth: false, +// logoEnabled: true, +// scaleBarEnabled: true, +// surfaceView: MGLModule.MapboxV10 ? true : false, +// requestDisallowInterceptTouchEvent: false, +// regionWillChangeDebounceTime: 10, +// regionDidChangeDebounceTime: 500, +// }; + +// deprecationLogged: { +// contentInset: boolean; +// regionDidChange: boolean; +// regionIsChanging: boolean; +// } = { +// contentInset: false, +// regionDidChange: false, +// regionIsChanging: false, +// }; +// logger: Logger; +// _onDebouncedRegionWillChange: Debounced< +// ( +// payload: GeoJSON.Feature< +// GeoJSON.Point, +// RegionPayload & { isAnimatingFromUserInteraction: boolean } +// >, +// ) => void +// >; +// _onDebouncedRegionDidChange: Debounced< +// ( +// payload: GeoJSON.Feature< +// GeoJSON.Point, +// RegionPayload & { isAnimatingFromUserInteraction: boolean } +// >, +// ) => void +// >; +// _nativeRef?: RCTMGLMapViewRefType; +// state: { +// isReady: boolean | null; +// region: null; +// width: number; +// height: number; +// isUserInteraction: boolean; +// }; + +// constructor(props: Props) { +// super(props); + +// this.logger = Logger.sharedInstance(); +// this.logger.start(); + +// this.state = { +// isReady: null, +// region: null, +// width: 0, +// height: 0, +// isUserInteraction: false, +// }; + +// this._onPress = this._onPress.bind(this); +// this._onLongPress = this._onLongPress.bind(this); +// this._onChange = this._onChange.bind(this); +// this._onLayout = this._onLayout.bind(this); +// this._onCameraChanged = this._onCameraChanged.bind(this); + +// // debounced map change methods +// this._onDebouncedRegionWillChange = debounce( +// this._onRegionWillChange.bind(this), +// props.regionWillChangeDebounceTime, +// true, +// ); + +// this._onDebouncedRegionDidChange = debounce( +// this._onRegionDidChange.bind(this), +// props.regionDidChangeDebounceTime, +// ); +// } + +// componentDidMount() { +// this._setHandledMapChangedEvents(this.props); +// } + +// componentWillUnmount() { +// this._onDebouncedRegionWillChange.clear(); +// this._onDebouncedRegionDidChange.clear(); +// this.logger.stop(); +// } + +// UNSAFE_componentWillReceiveProps(nextProps: Props) { +// this._setHandledMapChangedEvents(nextProps); +// } + +// _setHandledMapChangedEvents(props: Props) { +// if (isAndroid() || MGLModule.MapboxV10) { +// const events: string[] = []; + +// function addIfHasHandler(name: CallbablePropKeysWithoutOn) { +// if (props[`on${name}`] != null) { +// if (EventTypes[name] == null) { +// if (name === 'DidFailLoadingMap') { +// console.warn( +// `rnmapbox maps: on${name} is deprecated, please use onMapLoadingError`, +// ); +// } else { +// console.warn(`rnmapbox maps: ${name} is not supported`); +// } +// } else { +// events.push(EventTypes[name]); +// return true; +// } +// } +// return false; +// } + +// addIfHasHandler('RegionWillChange'); +// addIfHasHandler('RegionIsChanging'); +// addIfHasHandler('RegionDidChange'); +// addIfHasHandler('UserLocationUpdate'); +// addIfHasHandler('WillStartLoadingMap'); +// addIfHasHandler('DidFinishLoadingMap'); +// addIfHasHandler('MapLoadingError'); +// addIfHasHandler('DidFailLoadingMap'); +// addIfHasHandler('WillStartRenderingFrame'); +// addIfHasHandler('DidFinishRenderingFrame'); +// addIfHasHandler('DidFinishRenderingFrameFully'); +// addIfHasHandler('WillStartRenderingMap'); +// addIfHasHandler('DidFinishRenderingMap'); +// addIfHasHandler('DidFinishRenderingMapFully'); +// addIfHasHandler('DidFinishLoadingStyle'); + +// addIfHasHandler('CameraChanged'); +// addIfHasHandler('MapIdle'); + +// if (addIfHasHandler('RegionDidChange')) { +// if (!this.deprecationLogged.regionDidChange) { +// console.warn( +// 'onRegionDidChange is deprecated and will be removed in next release - please use onMapIdle. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', +// ); +// this.deprecationLogged.regionDidChange = true; +// } +// if (props.onMapIdle) { +// console.warn( +// 'rnmapbox/maps: only one of MapView.onRegionDidChange or onMapIdle is supported', +// ); +// } +// } +// if (addIfHasHandler('RegionIsChanging')) { +// if (!this.deprecationLogged.regionIsChanging) { +// console.warn( +// 'onRegionIsChanging is deprecated and will be removed in next release - please use onCameraChanged. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', +// ); +// this.deprecationLogged.regionIsChanging = true; +// } +// if (props.onCameraChanged) { +// console.warn( +// 'rnmapbox/maps: only one of MapView.onRegionIsChanging or onCameraChanged is supported', +// ); +// } +// } + +// if (props.onRegionWillChange) { +// console.warn( +// 'onRegionWillChange is deprecated and will be removed in v10 - please use onRegionIsChanging', +// ); +// } + +// this._runNativeCommand('setHandledMapChangedEvents', this._nativeRef, [ +// events, +// ]); +// } +// } + +// /** +// * Converts a geographic coordinate to a point in the given view’s coordinate system. +// * +// * @example +// * const pointInView = await this._map.getPointInView([-37.817070, 144.949901]); +// * +// * @param {Array} coordinate - A point expressed in the map view's coordinate system. +// * @return {Array} +// */ +// async getPointInView(coordinate: Position): Promise { +// const res = await this._runNative<{ pointInView: Position }>( +// 'getPointInView', +// [coordinate], +// ); +// return res.pointInView; +// } + +// /** +// * Converts a point in the given view’s coordinate system to a geographic coordinate. +// * +// * @example +// * const coordinate = await this._map.getCoordinateFromView([100, 100]); +// * +// * @param {Array} point - A point expressed in the given view’s coordinate system. +// * @return {Array} +// */ +// async getCoordinateFromView(point: Position): Promise { +// const res = await this._runNative<{ coordinateFromView: Position }>( +// 'getCoordinateFromView', +// [point], +// ); +// return res.coordinateFromView; +// } + +// /** +// * The coordinate bounds (ne, sw) visible in the user’s viewport. +// * +// * @example +// * const visibleBounds = await this._map.getVisibleBounds(); +// * +// * @return {Array} +// */ +// async getVisibleBounds(): Promise<[Position, Position]> { +// const res = await this._runNative<{ visibleBounds: [Position, Position] }>( +// 'getVisibleBounds', +// ); +// return res.visibleBounds; +// } + +// /** +// * Returns an array of rendered map features that intersect with a given point. +// * +// * @example +// * this._map.queryRenderedFeaturesAtPoint([30, 40], ['==', 'type', 'Point'], ['id1', 'id2']) +// * +// * @param {Array} coordinate - A point expressed in the map view’s coordinate system. +// * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. +// * @param {Array=} layerIDs - A array of layer id's to filter the features by +// * @return {FeatureCollection} +// */ + +// async queryRenderedFeaturesAtPoint( +// coordinate: Position, +// filter: FilterExpression | [] = [], +// layerIDs: string[] = [], +// ): Promise { +// if (!coordinate || coordinate.length < 2) { +// throw new Error('Must pass in valid coordinate[lng, lat]'); +// } + +// const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( +// 'queryRenderedFeaturesAtPoint', +// [coordinate, getFilter(filter), layerIDs], +// ); + +// if (isAndroid()) { +// return JSON.parse(res.data as unknown as string); +// } + +// return res.data as GeoJSON.FeatureCollection; +// } + +// /** +// * Returns an array of rendered map features that intersect with the given rectangle, +// * restricted to the given style layers and filtered by the given predicate. In v10, +// * passing an empty array will query the entire visible bounds of the map. +// * +// * @example +// * this._map.queryRenderedFeaturesInRect([30, 40, 20, 10], ['==', 'type', 'Point'], ['id1', 'id2']) +// * +// * @param {Array} bbox - A rectangle expressed in the map view’s coordinate system. For v10, this can be an empty array to query the visible map area. +// * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. +// * @param {Array=} layerIDs - A array of layer id's to filter the features by +// * @return {FeatureCollection} +// */ +// async queryRenderedFeaturesInRect( +// bbox: BBox | [], +// filter: FilterExpression | [] = [], +// layerIDs: string[] | null = null, +// ): Promise { +// if ( +// bbox != null && +// (bbox.length === 4 || (MGLModule.MapboxV10 && bbox.length === 0)) +// ) { +// const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( +// 'queryRenderedFeaturesInRect', +// [bbox, getFilter(filter), layerIDs], +// ); + +// if (isAndroid()) { +// return JSON.parse(res.data as unknown as string); +// } + +// return res.data; +// } else { +// throw new Error( +// 'Must pass in a valid bounding box: [top, right, bottom, left]. An empty array [] is also acceptable in v10.', +// ); +// } +// } + +// /** +// * Returns an array of GeoJSON Feature objects representing features within the specified vector tile or GeoJSON source that satisfy the query parameters. +// * +// * @example +// * this._map.querySourceFeatures('your-source-id', [], ['your-source-layer']) +// * +// * @param {String} sourceId - Style source identifier used to query for source features. +// * @param {Array=} filter - A filter to limit query results. +// * @param {Array=} sourceLayerIDs - The name of the source layers to query. For vector tile sources, this parameter is required. For GeoJSON sources, it is ignored. +// * @return {FeatureCollection} +// */ +// async querySourceFeatures( +// sourceId: string, +// filter: FilterExpression | [] = [], +// sourceLayerIDs: string[] = [], +// ): Promise { +// const args = [sourceId, getFilter(filter), sourceLayerIDs]; +// const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( +// 'querySourceFeatures', +// args, +// ); + +// if (isAndroid()) { +// return JSON.parse(res.data as unknown as string); +// } + +// return res.data; +// } + +// /** +// * Map camera will perform updates based on provided config. Deprecated use Camera#setCamera. +// * @deprecated use Camera#setCamera +// */ +// setCamera() { +// console.warn( +// 'MapView.setCamera is deprecated - please use Camera#setCamera', +// ); +// } + +// _runNative( +// methodName: string, +// args: NativeArg[] = [], +// ): Promise { +// return super._runNativeCommand( +// methodName, +// this._nativeRef as HostComponent | undefined, +// args, +// ); +// } + +// /** +// * Takes snapshot of map with current tiles and returns a URI to the image +// * @param {Boolean} writeToDisk If true will create a temp file, otherwise it is in base64 +// * @return {String} +// */ +// async takeSnap(writeToDisk = false): Promise { +// const res = await this._runNative<{ uri: string }>('takeSnap', [ +// writeToDisk, +// ]); +// return res.uri; +// } + +// /** +// * Returns the current zoom of the map view. +// * +// * @example +// * const zoom = await this._map.getZoom(); +// * +// * @return {Number} +// */ + +// async getZoom(): Promise { +// const res = await this._runNative<{ zoom: number }>('getZoom'); +// return res.zoom; +// } + +// /** +// * Returns the map's geographical centerpoint +// * +// * @example +// * const center = await this._map.getCenter(); +// * +// * @return {Array} Coordinates +// */ +// async getCenter(): Promise { +// const res = await this._runNative<{ center: Position }>('getCenter'); +// return res.center; +// } + +// /** +// * +// * Clears temporary map data from the data path defined in the given resource +// * options. Useful to reduce the disk usage or in case the disk cache contains +// * invalid data. +// * +// * v10 only +// */ +// async clearData(): Promise { +// if (!MGLModule.MapboxV10) { +// console.warn( +// 'RNMapbox: clearData is only implemented in v10 implementation or later', +// ); +// return; +// } +// await this._runNative('clearData'); +// } + +// /** +// * Queries the currently loaded data for elevation at a geographical location. +// * The elevation is returned in meters relative to mean sea-level. +// * Returns null if terrain is disabled or if terrain data for the location hasn't been loaded yet. +// * +// * @param {Array} coordinate - the coordinates to query elevation at +// * @return {Number} +// */ +// async queryTerrainElevation(coordinate: Position): Promise { +// const res = await this._runNative<{ data: number }>( +// 'queryTerrainElevation', +// [coordinate], +// ); +// return res.data; +// } + +// /** +// * Sets the visibility of all the layers referencing the specified `sourceLayerId` and/or `sourceId` +// * +// * @example +// * await this._map.setSourceVisibility(false, 'composite', 'building') +// * +// * @param {boolean} visible - Visibility of the layers +// * @param {String} sourceId - Identifier of the target source (e.g. 'composite') +// * @param {String=} sourceLayerId - Identifier of the target source-layer (e.g. 'building') +// */ +// setSourceVisibility( +// visible: boolean, +// sourceId: string, +// sourceLayerId: string | null = null, +// ) { +// this._runNative('setSourceVisibility', [ +// visible, +// sourceId, +// sourceLayerId, +// ]); +// } + +// /** +// * Show the attribution and telemetry action sheet. +// * If you implement a custom attribution button, you should add this action to the button. +// */ +// showAttribution() { +// return this._runNativeCommand('showAttribution', this._nativeRef); +// } + +// _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { +// if (isFunction(this.props.onPress)) { +// this.props.onPress(e.nativeEvent.payload); +// } +// } + +// _onLongPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { +// if (isFunction(this.props.onLongPress)) { +// this.props.onLongPress(e.nativeEvent.payload); +// } +// } + +// _onRegionWillChange( +// payload: GeoJSON.Feature< +// GeoJSON.Point, +// RegionPayload & { isAnimatingFromUserInteraction: boolean } +// >, +// ) { +// if (isFunction(this.props.onRegionWillChange)) { +// this.props.onRegionWillChange(payload); +// } +// this.setState({ +// isUserInteraction: payload.properties.isUserInteraction, +// isAnimatingFromUserInteraction: +// payload.properties.isAnimatingFromUserInteraction, +// }); +// } + +// _onRegionDidChange(payload: GeoJSON.Feature) { +// if (isFunction(this.props.onRegionDidChange)) { +// this.props.onRegionDidChange(payload); +// } +// this.setState({ region: payload }); +// } + +// _onCameraChanged(e: NativeSyntheticEvent<{ payload: MapState }>) { +// this.props.onCameraChanged?.(e.nativeEvent.payload); +// } + +// _onChange( +// e: NativeSyntheticEvent<{ +// type: string; +// payload: GeoJSON.Feature< +// GeoJSON.Point, +// RegionPayload & { isAnimatingFromUserInteraction: boolean } +// >; +// }>, +// ) { +// const { regionWillChangeDebounceTime, regionDidChangeDebounceTime } = +// this.props; +// const { type, payload } = e.nativeEvent; +// let propName: CallbablePropKeys | '' = ''; +// let deprecatedPropName: CallbablePropKeys | '' = ''; + +// switch (type) { +// case EventTypes.RegionWillChange: +// if (regionWillChangeDebounceTime && regionWillChangeDebounceTime > 0) { +// this._onDebouncedRegionWillChange(payload); +// } else { +// propName = 'onRegionWillChange'; +// } +// break; +// case EventTypes.RegionIsChanging: +// propName = 'onRegionIsChanging'; +// break; +// case EventTypes.RegionDidChange: +// if (regionDidChangeDebounceTime && regionDidChangeDebounceTime > 0) { +// this._onDebouncedRegionDidChange(payload); +// } else { +// propName = 'onRegionDidChange'; +// } +// break; +// case EventTypes.CameraChanged: +// propName = 'onCameraChanged'; +// break; +// case EventTypes.MapIdle: +// propName = 'onMapIdle'; +// break; +// case EventTypes.UserLocationUpdated: +// propName = 'onUserLocationUpdate'; +// break; +// case EventTypes.WillStartLoadingMap: +// propName = 'onWillStartLoadingMap'; +// break; +// case EventTypes.DidFinishLoadingMap: +// propName = 'onDidFinishLoadingMap'; +// break; +// case EventTypes.DidFailLoadingMap: +// propName = 'onDidFailLoadingMap'; +// break; +// case EventTypes.MapLoadingError: +// propName = 'onMapLoadingError'; +// deprecatedPropName = 'onDidFailLoadingMap'; +// break; +// case EventTypes.WillStartRenderingFrame: +// propName = 'onWillStartRenderingFrame'; +// break; +// case EventTypes.DidFinishRenderingFrame: +// propName = 'onDidFinishRenderingFrame'; +// break; +// case EventTypes.DidFinishRenderingFrameFully: +// propName = 'onDidFinishRenderingFrameFully'; +// break; +// case EventTypes.WillStartRenderingMap: +// propName = 'onWillStartRenderingMap'; +// break; +// case EventTypes.DidFinishRenderingMap: +// propName = 'onDidFinishRenderingMap'; +// break; +// case EventTypes.DidFinishRenderingMapFully: +// propName = 'onDidFinishRenderingMapFully'; +// break; +// case EventTypes.DidFinishLoadingStyle: +// propName = 'onDidFinishLoadingStyle'; +// break; +// default: +// console.warn('Unhandled event callback type', type); +// } + +// if (propName !== '') { +// this._handleOnChange(propName, payload); +// } +// if (deprecatedPropName !== '') { +// this._handleOnChange(deprecatedPropName, payload); +// } +// } + +// _onLayout(e: LayoutChangeEvent) { +// this.setState({ +// isReady: true, +// width: e.nativeEvent.layout.width, +// height: e.nativeEvent.layout.height, +// }); +// } + +// _handleOnChange(propName: CallbablePropKeys, payload: object) { +// const func = this.props[propName] as (payload: object) => void; +// if (func && isFunction(func)) { +// func(payload); +// } +// } + +// _getContentInset() { +// if (!this.props.contentInset) { +// return; +// } + +// if (MGLModule.MapboxV10) { +// if (!this.deprecationLogged.contentInset) { +// console.warn( +// '@rnmapbox/maps: contentInset is deprecated, use Camera padding instead.', +// ); +// this.deprecationLogged.contentInset = true; +// } +// } + +// if (!Array.isArray(this.props.contentInset)) { +// return [this.props.contentInset]; +// } + +// return this.props.contentInset; +// } + +// _setNativeRef(nativeRef: RCTMGLMapViewRefType) { +// this._nativeRef = nativeRef; +// super._runPendingNativeCommands(nativeRef); +// } + +// setNativeProps(props: NativeProps) { +// if (this._nativeRef) { +// this._nativeRef.setNativeProps(props); +// } +// } + +// _setStyleURL(props: Props) { +// // user set a styleURL, no need to alter props +// if (props.styleURL) { +// return; +// } + +// // user set styleJSON pass it to styleURL +// if (props.styleJSON && !props.styleURL) { +// props.styleURL = props.styleJSON; +// } + +// // user neither set styleJSON nor styleURL +// // set defaultStyleUrl +// if (!props.styleJSON || !props.styleURL) { +// props.styleURL = defaultStyleURL; +// } +// } + +// _setLocalizeLabels(props: Props) { +// if (!MGLModule.MapboxV10) { +// return; +// } +// if (typeof props.localizeLabels === 'boolean') { +// props.localizeLabels = { +// locale: 'current', +// }; +// } +// } + +// render() { +// const props = { +// ...this.props, +// contentInset: this._getContentInset(), +// style: styles.matchParent, +// }; + +// this._setStyleURL(props); +// this._setLocalizeLabels(props); + +// const callbacks = { +// ref: (nativeRef: RCTMGLMapViewRefType) => this._setNativeRef(nativeRef), +// onPress: this._onPress, +// onLongPress: this._onLongPress, +// onMapChange: this._onChange, +// onAndroidCallback: isAndroid() ? this._onAndroidCallback : undefined, +// onCameraChanged: this._onCameraChanged, +// }; + +// let mapView = null; +// if (isAndroid() && !this.props.surfaceView && this.state.isReady) { +// mapView = ( +// +// {this.props.children} +// +// ); +// } else if (this.state.isReady) { +// mapView = ( +// +// {this.props.children} +// +// ); +// } + +// return ( +// +// {mapView} +// +// ); +// } +// } + +// type NativeProps = Omit< +// Props, +// 'onPress' | 'onLongPress' | 'onCameraChanged' +// > & { +// onPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; +// onLongPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; +// onCameraChanged(event: NativeSyntheticEvent<{ payload: MapState }>): void; +// }; + +// type RCTMGLMapViewRefType = Component & Readonly; +// const RCTMGLMapView = requireNativeComponent(NATIVE_MODULE_NAME); + +// let RCTMGLAndroidTextureMapView: typeof RCTMGLMapView; +// if (isAndroid()) { +// RCTMGLAndroidTextureMapView = requireNativeComponent( +// ANDROID_TEXTURE_NATIVE_MODULE_NAME, +// ); +// } + +// export default MapView; diff --git a/src/specs/MBXMapViewNativeComponent.ts b/src/specs/MBXMapViewNativeComponent.ts new file mode 100644 index 000000000..e51bcd358 --- /dev/null +++ b/src/specs/MBXMapViewNativeComponent.ts @@ -0,0 +1,49 @@ +import type { HostComponent, ViewProps } from 'react-native'; +import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import { + WithDefault, + DirectEventHandler, +} from 'react-native/Libraries/Types/CodegenTypes'; + +/// see +// https://github.com/react-native-webview/react-native-webview/blob/681aac4fe7e35834264daa01b67a9893c4a9ebe7/src/RNCWebViewNativeComponent.ts#L4 +// for complex example + +type OnPressEventType = { payload: string }; +type OnWillStartLoadingType = { payload: boolean }; + +export interface NativeProps extends ViewProps { + // add other props here + contentInset?: ReadonlyArray; + + projection?: WithDefault<'mercator' | 'globe', 'mercator'>; + + styleURL?: string; + + onWillStartLoadingMap?: DirectEventHandler; + + onPress?: DirectEventHandler; + // +} + +type MapViewViewType = HostComponent; + +export interface NativeCommands { + sayHello: ( + viewRef: React.ElementRef, + message: string, + ) => void; + setHandledMapChangedEvents: ( + viewRef: React.ElementRef, + events: string, // ReadonlyArray, + ) => void; +} + +export const Commands: NativeCommands = codegenNativeCommands({ + supportedCommands: ['sayHello', 'setHandledMapChangedEvents'], +}); + +export default codegenNativeComponent( + 'MBXMapView', +) as HostComponent; From f40bfa7896c0d2946106cad8f65ca9351dfc49e2 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 25 Aug 2023 12:41:15 +0200 Subject: [PATCH 04/33] Some iOS progress: - codegen partially works - map is actually displayed - *one* prop is working --- fabricexample/App.tsx | 2 +- fabricexample/ios/Podfile.lock | 2 +- ios/RCTMGL-v10/Bridge/RCTMGL.h | 1 + ios/RCTMGL-v10/MBXMapView.h | 9 + ios/RCTMGL-v10/MBXMapView.swift | 24 + ios/RCTMGL-v10/MBXMapViewComponentView.mm | 23 +- ios/RCTMGL-v10/MBXMapViewManager.m | 16 + ios/RCTMGL-v10/RCTMGLMapViewManager.m | 3 +- src/components/MapView.tsx | 2239 ++++++++++----------- src/specs/MBXMapViewNativeComponent.ts | 129 +- 10 files changed, 1295 insertions(+), 1153 deletions(-) create mode 100644 ios/RCTMGL-v10/MBXMapView.h create mode 100644 ios/RCTMGL-v10/MBXMapView.swift create mode 100644 ios/RCTMGL-v10/MBXMapViewManager.m diff --git a/fabricexample/App.tsx b/fabricexample/App.tsx index aacf879ba..c806510f4 100644 --- a/fabricexample/App.tsx +++ b/fabricexample/App.tsx @@ -11,7 +11,7 @@ const App = () => { return ( - + ); diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock index af876c510..0525186de 100644 --- a/fabricexample/ios/Podfile.lock +++ b/fabricexample/ios/Podfile.lock @@ -1237,6 +1237,6 @@ SPEC CHECKSUMS: Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 -PODFILE CHECKSUM: 5e10b4cbc6ff307ec5fa415a884b5af5baf524e0 +PODFILE CHECKSUM: e0bb91cec8c0b8362d299ffc928ec86944f02acd COCOAPODS: 1.12.1 diff --git a/ios/RCTMGL-v10/Bridge/RCTMGL.h b/ios/RCTMGL-v10/Bridge/RCTMGL.h index 56185b970..057763926 100644 --- a/ios/RCTMGL-v10/Bridge/RCTMGL.h +++ b/ios/RCTMGL-v10/Bridge/RCTMGL.h @@ -5,3 +5,4 @@ #import #import "RCTSwiftLog.h" +#import "MBXMapView.h" diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h new file mode 100644 index 000000000..4904d55cf --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -0,0 +1,9 @@ +#import + +@protocol MBXMapViewProtocol +- (void)setAttributionEnabled:(BOOL)enabled; +@end + +@interface MBXMapViewFactory ++ (UIView*)createWithFrame:(CGRect)frame eventDispatcher:(id)eventDispatcher NS_SWIFT_NAME(create(frame:eventDispatcher:)); +@end diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift new file mode 100644 index 000000000..3df06cf88 --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -0,0 +1,24 @@ +import MapboxMaps + +@objc(MBXMapView) +open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { + required public init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) { + super.init(frame: frame, eventDispatcher: eventDispatcher) + } + + public required init(coder: NSCoder) { + super .init(coder: coder) + } + + public func setAttributionEnabled(_ enabled: Bool) { + self.setReactAttributionEnabled(enabled) + } +} + +@objc(MBXMapViewFactory) +open class MBXMapViewFactory : NSObject { + @objc + static func create(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) -> MBXMapViewProtocol { + return MBXMapView(frame: frame, eventDispatcher: eventDispatcher) + } +} diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index a741bbebf..6167e7b19 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -2,6 +2,7 @@ #import "MBXMapViewComponentView.h" +#import #import #import @@ -10,13 +11,28 @@ #import #import +#import "MBXMapView.h" + using namespace facebook::react; @interface MBXMapViewComponentView () @end +@interface MBXMapViewEventDispatcher : NSObject +@end + +@implementation MBXMapViewEventDispatcher + +// TODO: figure out how to use this custom dispatcher to bridge the new cpp event emitter and swift impl +- (void)sendEvent:(id)event { + NSLog(@"attepmt to send map event: %@", event.eventName); +} + +@end + @implementation MBXMapViewComponentView { - UIView *_view; + UIView *_view; + MBXMapViewEventDispatcher *_eventDispatcher; } - (instancetype)initWithFrame:(CGRect)frame @@ -24,7 +40,8 @@ - (instancetype)initWithFrame:(CGRect)frame if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; - _view = [[UIView alloc] initWithFrame:self.bounds]; + _eventDispatcher = [[MBXMapViewEventDispatcher alloc] init]; + _view = [MBXMapViewFactory createWithFrame:frame eventDispatcher:_eventDispatcher]; self.contentView = _view; } @@ -43,7 +60,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & { const auto &newProps = *std::static_pointer_cast(props); - _view.backgroundColor = [UIColor greenColor]; + [_view setAttributionEnabled:newProps.attributionEnabled]; [super updateProps:props oldProps:oldProps]; } diff --git a/ios/RCTMGL-v10/MBXMapViewManager.m b/ios/RCTMGL-v10/MBXMapViewManager.m new file mode 100644 index 000000000..fba715ff9 --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapViewManager.m @@ -0,0 +1,16 @@ +#import + +// used only to register the view in UIManager and generate view config +// probably can be deleted once static view configs and bridgeless are a thing + +@interface MBXMapViewManager : RCTViewManager + +@end + +@implementation MBXMapViewManager + +RCT_EXPORT_MODULE(MBXMapView) + +RCT_EXPORT_VIEW_PROPERTY(attributionEnabled, BOOL) + +@end diff --git a/ios/RCTMGL-v10/RCTMGLMapViewManager.m b/ios/RCTMGL-v10/RCTMGLMapViewManager.m index d2494afd2..cb0c04797 100644 --- a/ios/RCTMGL-v10/RCTMGLMapViewManager.m +++ b/ios/RCTMGL-v10/RCTMGLMapViewManager.m @@ -1,8 +1,7 @@ #import #import -// TODO: Change it back to RCTMGLMapView -@interface RCT_EXTERN_REMAP_MODULE(MBXMapView, RCTMGLMapViewManager, RCTViewManager) +@interface RCT_EXTERN_REMAP_MODULE(RCTMGLMapView, RCTMGLMapViewManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(onCameraChanged, RCTDirectEventBlock) diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index c1853c55c..855f446e6 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -1,1123 +1,1122 @@ -import View from '../specs/MBXMapViewNativeComponent'; - -export default View; - -// import React, { Component } from 'react'; -// import { -// View, -// StyleSheet, -// NativeModules, -// requireNativeComponent, -// ViewProps, -// NativeSyntheticEvent, -// NativeMethods, -// HostComponent, -// LayoutChangeEvent, -// } from 'react-native'; -// import { debounce } from 'debounce'; - -// import { -// isFunction, -// isAndroid, -// type NativeArg, -// type OrnamentPositonProp, -// } from '../utils'; -// import { getFilter } from '../utils/filterUtils'; -// import Logger from '../utils/Logger'; -// import { FilterExpression } from '../utils/MapboxStyles'; -// import { type Position } from '../types/Position'; -// import { type Location } from '../modules/location/locationManager'; - -// import NativeBridgeComponent from './NativeBridgeComponent'; - -// const { MGLModule } = NativeModules; -// const { EventTypes } = MGLModule; - -// if (MGLModule == null) { -// console.error( -// 'Native part of Mapbox React Native libraries were not registered properly, double check our native installation guides.', -// ); -// } -// if (!MGLModule.MapboxV10) { -// console.warn( -// '@rnmapbox/maps: Non v10 implementations are deprecated and will be removed in next version - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre', -// ); -// } - -// export const NATIVE_MODULE_NAME = 'RCTMGLMapView'; - -// export const ANDROID_TEXTURE_NATIVE_MODULE_NAME = 'RCTMGLAndroidTextureMapView'; - -// const styles = StyleSheet.create({ -// matchParent: { flex: 1 }, -// }); - -// const defaultStyleURL = MGLModule.StyleURL.Street; - -// export type Point = { -// x: number; -// y: number; -// }; - -// type BBox = [number, number, number, number]; - -// export type RegionPayload = { -// zoomLevel: number; -// heading: number; -// animated: boolean; -// isUserInteraction: boolean; -// visibleBounds: GeoJSON.Position[]; -// pitch: number; -// }; - -// /** -// * v10 only -// */ -// export type MapState = { -// properties: { -// center: GeoJSON.Position; -// bounds: { -// ne: GeoJSON.Position; -// sw: GeoJSON.Position; -// }; -// zoom: number; -// heading: number; -// pitch: number; -// }; -// gestures: { -// isGestureActive: boolean; -// }; -// timestamp?: number; -// }; - -// /** -// * label localization settings (v10 only). `true` is equivalent to current locale. -// */ -// type LocalizeLabels = -// | { -// /** locale code like `es` or `current` for the device's current locale */ -// locale: string; -// /** layer id to localize. If not specified, all layers will be localized */ -// layerIds?: string[]; -// } -// | true; - -// type Props = ViewProps & { -// /** -// * The distance from the edges of the map view’s frame to the edges of the map view’s logical viewport. -// * @deprecated use Camera `padding` instead -// */ -// contentInset?: number | number[]; - -// /** -// * The projection used when rendering the map -// */ -// projection?: 'mercator' | 'globe'; - -// /** -// * Style URL for map - notice, if non is set it _will_ default to `Mapbox.StyleURL.Street` -// */ -// styleURL?: string; - -// /** -// * StyleJSON for map - according to TileJSON specs: https://github.com/mapbox/tilejson-spec -// */ -// styleJSON?: string; - -// /** -// * iOS: The preferred frame rate at which the map view is rendered. -// * The default value for this property is MGLMapViewPreferredFramesPerSecondDefault, -// * which will adaptively set the preferred frame rate based on the capability of -// * the user’s device to maintain a smooth experience. This property can be set to arbitrary integer values. -// * -// * Android: The maximum frame rate at which the map view is rendered, but it can't exceed the ability of device hardware. -// * This property can be set to arbitrary integer values. -// */ -// preferredFramesPerSecond?: number; - -// /** -// * Enable/Disable zoom on the map -// */ -// zoomEnabled?: boolean; - -// /** -// * Enable/Disable scroll on the map -// */ -// scrollEnabled?: boolean; - -// /** -// * Enable/Disable pitch on map -// */ -// pitchEnabled?: boolean; - -// /** -// * Enable/Disable rotation on map -// */ -// rotateEnabled?: boolean; - -// /** -// * The Mapbox terms of service, which governs the use of Mapbox-hosted vector tiles and styles, -// * [requires](https://www.mapbox.com/help/how-attribution-works/) these copyright notices to accompany any map that features Mapbox-designed styles, OpenStreetMap data, or other Mapbox data such as satellite or terrain data. -// * If that applies to this map view, do not hide this view or remove any notices from it. -// * -// * You are additionally [required](https://www.mapbox.com/help/how-mobile-apps-work/#telemetry) to provide users with the option to disable anonymous usage and location sharing (telemetry). -// * If this view is hidden, you must implement this setting elsewhere in your app. See our website for [Android](https://www.mapbox.com/android-docs/map-sdk/overview/#telemetry-opt-out) and [iOS](https://www.mapbox.com/ios-sdk/#telemetry_opt_out) for implementation details. -// * -// * Enable/Disable attribution on map. For iOS you need to add MGLMapboxMetricsEnabledSettingShownInApp=YES -// * to your Info.plist -// */ -// attributionEnabled?: boolean; - -// /** -// * Adds attribution offset, e.g. `{top: 8, left: 8}` will put attribution button in top-left corner of the map. By default on Android, the attribution with information icon (i) will be on the bottom left, while on iOS the mapbox logo will be on bottom left with information icon (i) on bottom right. Read more about mapbox attribution [here](https://docs.mapbox.com/help/getting-started/attribution/) -// */ -// attributionPosition?: OrnamentPositonProp; - -// /** -// * MapView's tintColor -// */ -// tintColor?: string | number[]; - -// /** -// * Enable/Disable the logo on the map. -// */ -// logoEnabled?: boolean; - -// /** -// * Adds logo offset, e.g. `{top: 8, left: 8}` will put the logo in top-left corner of the map -// */ -// logoPosition?: OrnamentPositonProp; - -// /** -// * Enable/Disable the compass from appearing on the map -// */ -// compassEnabled?: boolean; - -// /** -// * [`mapbox` (v10) implementation only] Enable/Disable if the compass should fade out when the map is pointing north -// */ -// compassFadeWhenNorth?: boolean; - -// /** -// * [`mapbox` (v10) implementation only] Adds compass offset, e.g. `{top: 8, left: 8}` will put the compass in top-left corner of the map -// */ -// compassPosition?: OrnamentPositonProp; - -// /** -// * Change corner of map the compass starts at. 0: TopLeft, 1: TopRight, 2: BottomLeft, 3: BottomRight -// */ -// compassViewPosition?: number; - -// /** -// * Add margins to the compass with x and y values -// */ -// compassViewMargins?: Point; - -// /** -// * [iOS, `mapbox` (v10) implementation only] A string referencing an image key. Requires an `Images` component. -// */ -// compassImage?: string; - -// /** -// * [`mapbox` (v10) implementation only] Enable/Disable the scale bar from appearing on the map -// */ -// scaleBarEnabled?: boolean; - -// /** -// * [`mapbox` (v10) implementation only] Adds scale bar offset, e.g. `{top: 8, left: 8}` will put the scale bar in top-left corner of the map -// */ -// scaleBarPosition?: OrnamentPositonProp; - -// /** -// * [Android only] Enable/Disable use of GLSurfaceView instead of TextureView. -// */ -// surfaceView?: boolean; - -// /** -// * [Android only] Experimental, call requestDisallowInterceptTouchEvent on parent with onTochEvent, this allows touch interaction to work -// * when embedded into a scroll view -// */ -// requestDisallowInterceptTouchEvent?: boolean; - -// /** -// * [`mapbox` (v10) implementation only] -// * Set map's label locale, e.g. { "locale": "es" } will localize labels to Spanish, { "locale": "current" } will localize labels to system locale. -// */ -// localizeLabels?: LocalizeLabels; - -// /** -// * Map press listener, gets called when a user presses the map -// */ -// onPress?: (feature: GeoJSON.Feature) => void; - -// /** -// * Map long press listener, gets called when a user long presses the map -// */ -// onLongPress?: (feature: GeoJSON.Feature) => void; - -// /** -// * , -// ) => void; - -// /** -// * -// * This event is triggered whenever the currently displayed map region is changing. -// * -// * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds -// */ -// onRegionIsChanging?: ( -// feature: GeoJSON.Feature, -// ) => void; - -// /** -// * -// * This event is triggered whenever the currently displayed map region finished changing. -// * -// * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds -// */ -// onRegionDidChange?: ( -// feature: GeoJSON.Feature, -// ) => void; - -// /** -// * v10 only, replaces onRegionIsChanging -// */ -// onCameraChanged?: (state: MapState) => void; - -// /** -// * v10 only, replaces onRegionDidChange -// */ -// onMapIdle?: (state: MapState) => void; - -// /** -// * This event is triggered when the map is about to start loading a new map style. -// */ -// onWillStartLoadingMap?: () => void; - -// /** -// * This is triggered when the map has successfully loaded a new map style. -// */ -// onDidFinishLoadingMap?: () => void; - -// /** -// * This event is triggered when the map has failed to load a new map style. On v10 it's deprecated and replaced by onMapLoadingError -// * @deprecated use onMapLoadingError -// */ -// onDidFailLoadingMap?: () => void; - -// /** -// * This event is tiggered when there is an error during map load. V10 only, replaces onDidFailLoadingMap, might be called multiple times and not exclusive with onDidFinishLoadingMap. -// */ -// onMapLoadingError?: () => void; - -// /** -// * This event is triggered when the map will start rendering a frame. -// */ -// onWillStartRenderingFrame?: () => void; - -// /** -// * This event is triggered when the map finished rendering a frame. -// */ -// onDidFinishRenderingFrame?: () => void; - -// /** -// * This event is triggered when the map fully finished rendering a frame. -// */ -// onDidFinishRenderingFrameFully?: () => void; - -// /** -// * This event is triggered when the map will start rendering the map. -// */ -// onWillStartRenderingMap?: () => void; - -// /** -// * This event is triggered when the map finished rendering the map. -// */ -// onDidFinishRenderingMap?: () => void; - -// /** -// * This event is triggered when the map fully finished rendering the map. -// */ -// onDidFinishRenderingMapFully?: () => void; - -// /** -// * This event is triggered when the user location is updated. -// */ -// onUserLocationUpdate?: (feature: Location) => void; - -// /** -// * This event is triggered when a style has finished loading. -// */ -// onDidFinishLoadingStyle?: () => void; - -// /** -// * The emitted frequency of regionwillchange events -// */ -// regionWillChangeDebounceTime?: number; - -// /** -// * The emitted frequency of regiondidchange events -// */ -// regionDidChangeDebounceTime?: number; -// }; - -// type CallbablePropKeys = -// | 'onRegionWillChange' -// | 'onRegionIsChanging' -// | 'onRegionDidChange' -// | 'onUserLocationUpdate' -// | 'onWillStartLoadingMap' -// | 'onMapLoadingError' -// | 'onDidFinishLoadingMap' -// | 'onDidFailLoadingMap' -// | 'onWillStartRenderingFrame' -// | 'onDidFinishRenderingFrame' -// | 'onDidFinishRenderingFrameFully' -// | 'onWillStartRenderingMap' -// | 'onDidFinishRenderingMap' -// | 'onDidFinishRenderingMapFully' -// | 'onDidFinishLoadingStyle' -// | 'onMapIdle' -// | 'onCameraChanged'; - -// type CallbablePropKeysWithoutOn = CallbablePropKeys extends `on${infer C}` -// ? C -// : never; - -// type Debounced = F & { clear(): void; flush(): void }; - -// /** -// * MapView backed by Mapbox Native GL -// */ -// class MapView extends NativeBridgeComponent( -// React.PureComponent, -// NATIVE_MODULE_NAME, -// ) { -// static defaultProps: Props = { -// projection: 'mercator', -// scrollEnabled: true, -// pitchEnabled: true, -// rotateEnabled: true, -// attributionEnabled: true, -// compassEnabled: false, -// compassFadeWhenNorth: false, -// logoEnabled: true, -// scaleBarEnabled: true, -// surfaceView: MGLModule.MapboxV10 ? true : false, -// requestDisallowInterceptTouchEvent: false, -// regionWillChangeDebounceTime: 10, -// regionDidChangeDebounceTime: 500, -// }; - -// deprecationLogged: { -// contentInset: boolean; -// regionDidChange: boolean; -// regionIsChanging: boolean; -// } = { -// contentInset: false, -// regionDidChange: false, -// regionIsChanging: false, -// }; -// logger: Logger; -// _onDebouncedRegionWillChange: Debounced< -// ( -// payload: GeoJSON.Feature< -// GeoJSON.Point, -// RegionPayload & { isAnimatingFromUserInteraction: boolean } -// >, -// ) => void -// >; -// _onDebouncedRegionDidChange: Debounced< -// ( -// payload: GeoJSON.Feature< -// GeoJSON.Point, -// RegionPayload & { isAnimatingFromUserInteraction: boolean } -// >, -// ) => void -// >; -// _nativeRef?: RCTMGLMapViewRefType; -// state: { -// isReady: boolean | null; -// region: null; -// width: number; -// height: number; -// isUserInteraction: boolean; -// }; - -// constructor(props: Props) { -// super(props); - -// this.logger = Logger.sharedInstance(); -// this.logger.start(); - -// this.state = { -// isReady: null, -// region: null, -// width: 0, -// height: 0, -// isUserInteraction: false, -// }; - -// this._onPress = this._onPress.bind(this); -// this._onLongPress = this._onLongPress.bind(this); -// this._onChange = this._onChange.bind(this); -// this._onLayout = this._onLayout.bind(this); -// this._onCameraChanged = this._onCameraChanged.bind(this); - -// // debounced map change methods -// this._onDebouncedRegionWillChange = debounce( -// this._onRegionWillChange.bind(this), -// props.regionWillChangeDebounceTime, -// true, -// ); - -// this._onDebouncedRegionDidChange = debounce( -// this._onRegionDidChange.bind(this), -// props.regionDidChangeDebounceTime, -// ); -// } - -// componentDidMount() { -// this._setHandledMapChangedEvents(this.props); -// } - -// componentWillUnmount() { -// this._onDebouncedRegionWillChange.clear(); -// this._onDebouncedRegionDidChange.clear(); -// this.logger.stop(); -// } - -// UNSAFE_componentWillReceiveProps(nextProps: Props) { -// this._setHandledMapChangedEvents(nextProps); -// } - -// _setHandledMapChangedEvents(props: Props) { -// if (isAndroid() || MGLModule.MapboxV10) { -// const events: string[] = []; - -// function addIfHasHandler(name: CallbablePropKeysWithoutOn) { -// if (props[`on${name}`] != null) { -// if (EventTypes[name] == null) { -// if (name === 'DidFailLoadingMap') { -// console.warn( -// `rnmapbox maps: on${name} is deprecated, please use onMapLoadingError`, -// ); -// } else { -// console.warn(`rnmapbox maps: ${name} is not supported`); -// } -// } else { -// events.push(EventTypes[name]); -// return true; -// } -// } -// return false; -// } - -// addIfHasHandler('RegionWillChange'); -// addIfHasHandler('RegionIsChanging'); -// addIfHasHandler('RegionDidChange'); -// addIfHasHandler('UserLocationUpdate'); -// addIfHasHandler('WillStartLoadingMap'); -// addIfHasHandler('DidFinishLoadingMap'); -// addIfHasHandler('MapLoadingError'); -// addIfHasHandler('DidFailLoadingMap'); -// addIfHasHandler('WillStartRenderingFrame'); -// addIfHasHandler('DidFinishRenderingFrame'); -// addIfHasHandler('DidFinishRenderingFrameFully'); -// addIfHasHandler('WillStartRenderingMap'); -// addIfHasHandler('DidFinishRenderingMap'); -// addIfHasHandler('DidFinishRenderingMapFully'); -// addIfHasHandler('DidFinishLoadingStyle'); - -// addIfHasHandler('CameraChanged'); -// addIfHasHandler('MapIdle'); - -// if (addIfHasHandler('RegionDidChange')) { -// if (!this.deprecationLogged.regionDidChange) { -// console.warn( -// 'onRegionDidChange is deprecated and will be removed in next release - please use onMapIdle. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', -// ); -// this.deprecationLogged.regionDidChange = true; -// } -// if (props.onMapIdle) { -// console.warn( -// 'rnmapbox/maps: only one of MapView.onRegionDidChange or onMapIdle is supported', -// ); -// } -// } -// if (addIfHasHandler('RegionIsChanging')) { -// if (!this.deprecationLogged.regionIsChanging) { -// console.warn( -// 'onRegionIsChanging is deprecated and will be removed in next release - please use onCameraChanged. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', -// ); -// this.deprecationLogged.regionIsChanging = true; -// } -// if (props.onCameraChanged) { -// console.warn( -// 'rnmapbox/maps: only one of MapView.onRegionIsChanging or onCameraChanged is supported', -// ); -// } -// } - -// if (props.onRegionWillChange) { -// console.warn( -// 'onRegionWillChange is deprecated and will be removed in v10 - please use onRegionIsChanging', -// ); -// } - -// this._runNativeCommand('setHandledMapChangedEvents', this._nativeRef, [ -// events, -// ]); -// } -// } - -// /** -// * Converts a geographic coordinate to a point in the given view’s coordinate system. -// * -// * @example -// * const pointInView = await this._map.getPointInView([-37.817070, 144.949901]); -// * -// * @param {Array} coordinate - A point expressed in the map view's coordinate system. -// * @return {Array} -// */ -// async getPointInView(coordinate: Position): Promise { -// const res = await this._runNative<{ pointInView: Position }>( -// 'getPointInView', -// [coordinate], -// ); -// return res.pointInView; -// } - -// /** -// * Converts a point in the given view’s coordinate system to a geographic coordinate. -// * -// * @example -// * const coordinate = await this._map.getCoordinateFromView([100, 100]); -// * -// * @param {Array} point - A point expressed in the given view’s coordinate system. -// * @return {Array} -// */ -// async getCoordinateFromView(point: Position): Promise { -// const res = await this._runNative<{ coordinateFromView: Position }>( -// 'getCoordinateFromView', -// [point], -// ); -// return res.coordinateFromView; -// } - -// /** -// * The coordinate bounds (ne, sw) visible in the user’s viewport. -// * -// * @example -// * const visibleBounds = await this._map.getVisibleBounds(); -// * -// * @return {Array} -// */ -// async getVisibleBounds(): Promise<[Position, Position]> { -// const res = await this._runNative<{ visibleBounds: [Position, Position] }>( -// 'getVisibleBounds', -// ); -// return res.visibleBounds; -// } - -// /** -// * Returns an array of rendered map features that intersect with a given point. -// * -// * @example -// * this._map.queryRenderedFeaturesAtPoint([30, 40], ['==', 'type', 'Point'], ['id1', 'id2']) -// * -// * @param {Array} coordinate - A point expressed in the map view’s coordinate system. -// * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. -// * @param {Array=} layerIDs - A array of layer id's to filter the features by -// * @return {FeatureCollection} -// */ - -// async queryRenderedFeaturesAtPoint( -// coordinate: Position, -// filter: FilterExpression | [] = [], -// layerIDs: string[] = [], -// ): Promise { -// if (!coordinate || coordinate.length < 2) { -// throw new Error('Must pass in valid coordinate[lng, lat]'); -// } - -// const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( -// 'queryRenderedFeaturesAtPoint', -// [coordinate, getFilter(filter), layerIDs], -// ); - -// if (isAndroid()) { -// return JSON.parse(res.data as unknown as string); -// } - -// return res.data as GeoJSON.FeatureCollection; -// } - -// /** -// * Returns an array of rendered map features that intersect with the given rectangle, -// * restricted to the given style layers and filtered by the given predicate. In v10, -// * passing an empty array will query the entire visible bounds of the map. -// * -// * @example -// * this._map.queryRenderedFeaturesInRect([30, 40, 20, 10], ['==', 'type', 'Point'], ['id1', 'id2']) -// * -// * @param {Array} bbox - A rectangle expressed in the map view’s coordinate system. For v10, this can be an empty array to query the visible map area. -// * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. -// * @param {Array=} layerIDs - A array of layer id's to filter the features by -// * @return {FeatureCollection} -// */ -// async queryRenderedFeaturesInRect( -// bbox: BBox | [], -// filter: FilterExpression | [] = [], -// layerIDs: string[] | null = null, -// ): Promise { -// if ( -// bbox != null && -// (bbox.length === 4 || (MGLModule.MapboxV10 && bbox.length === 0)) -// ) { -// const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( -// 'queryRenderedFeaturesInRect', -// [bbox, getFilter(filter), layerIDs], -// ); - -// if (isAndroid()) { -// return JSON.parse(res.data as unknown as string); -// } - -// return res.data; -// } else { -// throw new Error( -// 'Must pass in a valid bounding box: [top, right, bottom, left]. An empty array [] is also acceptable in v10.', -// ); -// } -// } - -// /** -// * Returns an array of GeoJSON Feature objects representing features within the specified vector tile or GeoJSON source that satisfy the query parameters. -// * -// * @example -// * this._map.querySourceFeatures('your-source-id', [], ['your-source-layer']) -// * -// * @param {String} sourceId - Style source identifier used to query for source features. -// * @param {Array=} filter - A filter to limit query results. -// * @param {Array=} sourceLayerIDs - The name of the source layers to query. For vector tile sources, this parameter is required. For GeoJSON sources, it is ignored. -// * @return {FeatureCollection} -// */ -// async querySourceFeatures( -// sourceId: string, -// filter: FilterExpression | [] = [], -// sourceLayerIDs: string[] = [], -// ): Promise { -// const args = [sourceId, getFilter(filter), sourceLayerIDs]; -// const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( -// 'querySourceFeatures', -// args, -// ); - -// if (isAndroid()) { -// return JSON.parse(res.data as unknown as string); -// } - -// return res.data; -// } - -// /** -// * Map camera will perform updates based on provided config. Deprecated use Camera#setCamera. -// * @deprecated use Camera#setCamera -// */ -// setCamera() { -// console.warn( -// 'MapView.setCamera is deprecated - please use Camera#setCamera', -// ); -// } - -// _runNative( -// methodName: string, -// args: NativeArg[] = [], -// ): Promise { -// return super._runNativeCommand( -// methodName, -// this._nativeRef as HostComponent | undefined, -// args, -// ); -// } - -// /** -// * Takes snapshot of map with current tiles and returns a URI to the image -// * @param {Boolean} writeToDisk If true will create a temp file, otherwise it is in base64 -// * @return {String} -// */ -// async takeSnap(writeToDisk = false): Promise { -// const res = await this._runNative<{ uri: string }>('takeSnap', [ -// writeToDisk, -// ]); -// return res.uri; -// } - -// /** -// * Returns the current zoom of the map view. -// * -// * @example -// * const zoom = await this._map.getZoom(); -// * -// * @return {Number} -// */ - -// async getZoom(): Promise { -// const res = await this._runNative<{ zoom: number }>('getZoom'); -// return res.zoom; -// } - -// /** -// * Returns the map's geographical centerpoint -// * -// * @example -// * const center = await this._map.getCenter(); -// * -// * @return {Array} Coordinates -// */ -// async getCenter(): Promise { -// const res = await this._runNative<{ center: Position }>('getCenter'); -// return res.center; -// } - -// /** -// * -// * Clears temporary map data from the data path defined in the given resource -// * options. Useful to reduce the disk usage or in case the disk cache contains -// * invalid data. -// * -// * v10 only -// */ -// async clearData(): Promise { -// if (!MGLModule.MapboxV10) { -// console.warn( -// 'RNMapbox: clearData is only implemented in v10 implementation or later', -// ); -// return; -// } -// await this._runNative('clearData'); -// } - -// /** -// * Queries the currently loaded data for elevation at a geographical location. -// * The elevation is returned in meters relative to mean sea-level. -// * Returns null if terrain is disabled or if terrain data for the location hasn't been loaded yet. -// * -// * @param {Array} coordinate - the coordinates to query elevation at -// * @return {Number} -// */ -// async queryTerrainElevation(coordinate: Position): Promise { -// const res = await this._runNative<{ data: number }>( -// 'queryTerrainElevation', -// [coordinate], -// ); -// return res.data; -// } - -// /** -// * Sets the visibility of all the layers referencing the specified `sourceLayerId` and/or `sourceId` -// * -// * @example -// * await this._map.setSourceVisibility(false, 'composite', 'building') -// * -// * @param {boolean} visible - Visibility of the layers -// * @param {String} sourceId - Identifier of the target source (e.g. 'composite') -// * @param {String=} sourceLayerId - Identifier of the target source-layer (e.g. 'building') -// */ -// setSourceVisibility( -// visible: boolean, -// sourceId: string, -// sourceLayerId: string | null = null, -// ) { -// this._runNative('setSourceVisibility', [ -// visible, -// sourceId, -// sourceLayerId, -// ]); -// } - -// /** -// * Show the attribution and telemetry action sheet. -// * If you implement a custom attribution button, you should add this action to the button. -// */ -// showAttribution() { -// return this._runNativeCommand('showAttribution', this._nativeRef); -// } - -// _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { -// if (isFunction(this.props.onPress)) { -// this.props.onPress(e.nativeEvent.payload); -// } -// } - -// _onLongPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { -// if (isFunction(this.props.onLongPress)) { -// this.props.onLongPress(e.nativeEvent.payload); -// } -// } - -// _onRegionWillChange( -// payload: GeoJSON.Feature< -// GeoJSON.Point, -// RegionPayload & { isAnimatingFromUserInteraction: boolean } -// >, -// ) { -// if (isFunction(this.props.onRegionWillChange)) { -// this.props.onRegionWillChange(payload); -// } -// this.setState({ -// isUserInteraction: payload.properties.isUserInteraction, -// isAnimatingFromUserInteraction: -// payload.properties.isAnimatingFromUserInteraction, -// }); -// } - -// _onRegionDidChange(payload: GeoJSON.Feature) { -// if (isFunction(this.props.onRegionDidChange)) { -// this.props.onRegionDidChange(payload); -// } -// this.setState({ region: payload }); -// } - -// _onCameraChanged(e: NativeSyntheticEvent<{ payload: MapState }>) { -// this.props.onCameraChanged?.(e.nativeEvent.payload); -// } - -// _onChange( -// e: NativeSyntheticEvent<{ -// type: string; -// payload: GeoJSON.Feature< -// GeoJSON.Point, -// RegionPayload & { isAnimatingFromUserInteraction: boolean } -// >; -// }>, -// ) { -// const { regionWillChangeDebounceTime, regionDidChangeDebounceTime } = -// this.props; -// const { type, payload } = e.nativeEvent; -// let propName: CallbablePropKeys | '' = ''; -// let deprecatedPropName: CallbablePropKeys | '' = ''; - -// switch (type) { -// case EventTypes.RegionWillChange: -// if (regionWillChangeDebounceTime && regionWillChangeDebounceTime > 0) { -// this._onDebouncedRegionWillChange(payload); -// } else { -// propName = 'onRegionWillChange'; -// } -// break; -// case EventTypes.RegionIsChanging: -// propName = 'onRegionIsChanging'; -// break; -// case EventTypes.RegionDidChange: -// if (regionDidChangeDebounceTime && regionDidChangeDebounceTime > 0) { -// this._onDebouncedRegionDidChange(payload); -// } else { -// propName = 'onRegionDidChange'; -// } -// break; -// case EventTypes.CameraChanged: -// propName = 'onCameraChanged'; -// break; -// case EventTypes.MapIdle: -// propName = 'onMapIdle'; -// break; -// case EventTypes.UserLocationUpdated: -// propName = 'onUserLocationUpdate'; -// break; -// case EventTypes.WillStartLoadingMap: -// propName = 'onWillStartLoadingMap'; -// break; -// case EventTypes.DidFinishLoadingMap: -// propName = 'onDidFinishLoadingMap'; -// break; -// case EventTypes.DidFailLoadingMap: -// propName = 'onDidFailLoadingMap'; -// break; -// case EventTypes.MapLoadingError: -// propName = 'onMapLoadingError'; -// deprecatedPropName = 'onDidFailLoadingMap'; -// break; -// case EventTypes.WillStartRenderingFrame: -// propName = 'onWillStartRenderingFrame'; -// break; -// case EventTypes.DidFinishRenderingFrame: -// propName = 'onDidFinishRenderingFrame'; -// break; -// case EventTypes.DidFinishRenderingFrameFully: -// propName = 'onDidFinishRenderingFrameFully'; -// break; -// case EventTypes.WillStartRenderingMap: -// propName = 'onWillStartRenderingMap'; -// break; -// case EventTypes.DidFinishRenderingMap: -// propName = 'onDidFinishRenderingMap'; -// break; -// case EventTypes.DidFinishRenderingMapFully: -// propName = 'onDidFinishRenderingMapFully'; -// break; -// case EventTypes.DidFinishLoadingStyle: -// propName = 'onDidFinishLoadingStyle'; -// break; -// default: -// console.warn('Unhandled event callback type', type); -// } - -// if (propName !== '') { -// this._handleOnChange(propName, payload); -// } -// if (deprecatedPropName !== '') { -// this._handleOnChange(deprecatedPropName, payload); -// } -// } - -// _onLayout(e: LayoutChangeEvent) { -// this.setState({ -// isReady: true, -// width: e.nativeEvent.layout.width, -// height: e.nativeEvent.layout.height, -// }); -// } - -// _handleOnChange(propName: CallbablePropKeys, payload: object) { -// const func = this.props[propName] as (payload: object) => void; -// if (func && isFunction(func)) { -// func(payload); -// } -// } - -// _getContentInset() { -// if (!this.props.contentInset) { -// return; -// } - -// if (MGLModule.MapboxV10) { -// if (!this.deprecationLogged.contentInset) { -// console.warn( -// '@rnmapbox/maps: contentInset is deprecated, use Camera padding instead.', -// ); -// this.deprecationLogged.contentInset = true; -// } -// } - -// if (!Array.isArray(this.props.contentInset)) { -// return [this.props.contentInset]; -// } - -// return this.props.contentInset; -// } - -// _setNativeRef(nativeRef: RCTMGLMapViewRefType) { -// this._nativeRef = nativeRef; -// super._runPendingNativeCommands(nativeRef); -// } - -// setNativeProps(props: NativeProps) { -// if (this._nativeRef) { -// this._nativeRef.setNativeProps(props); -// } -// } - -// _setStyleURL(props: Props) { -// // user set a styleURL, no need to alter props -// if (props.styleURL) { -// return; -// } - -// // user set styleJSON pass it to styleURL -// if (props.styleJSON && !props.styleURL) { -// props.styleURL = props.styleJSON; -// } - -// // user neither set styleJSON nor styleURL -// // set defaultStyleUrl -// if (!props.styleJSON || !props.styleURL) { -// props.styleURL = defaultStyleURL; -// } -// } - -// _setLocalizeLabels(props: Props) { -// if (!MGLModule.MapboxV10) { -// return; -// } -// if (typeof props.localizeLabels === 'boolean') { -// props.localizeLabels = { -// locale: 'current', -// }; -// } -// } - -// render() { -// const props = { -// ...this.props, -// contentInset: this._getContentInset(), -// style: styles.matchParent, -// }; - -// this._setStyleURL(props); -// this._setLocalizeLabels(props); - -// const callbacks = { -// ref: (nativeRef: RCTMGLMapViewRefType) => this._setNativeRef(nativeRef), -// onPress: this._onPress, -// onLongPress: this._onLongPress, -// onMapChange: this._onChange, -// onAndroidCallback: isAndroid() ? this._onAndroidCallback : undefined, -// onCameraChanged: this._onCameraChanged, -// }; - -// let mapView = null; -// if (isAndroid() && !this.props.surfaceView && this.state.isReady) { -// mapView = ( -// -// {this.props.children} -// -// ); -// } else if (this.state.isReady) { -// mapView = ( -// -// {this.props.children} -// -// ); -// } - -// return ( -// -// {mapView} -// -// ); -// } -// } - -// type NativeProps = Omit< -// Props, -// 'onPress' | 'onLongPress' | 'onCameraChanged' -// > & { -// onPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; -// onLongPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; -// onCameraChanged(event: NativeSyntheticEvent<{ payload: MapState }>): void; -// }; - -// type RCTMGLMapViewRefType = Component & Readonly; +import React, { Component } from 'react'; +import { + View, + StyleSheet, + NativeModules, + requireNativeComponent, + ViewProps, + NativeSyntheticEvent, + NativeMethods, + HostComponent, + LayoutChangeEvent, +} from 'react-native'; +import { debounce } from 'debounce'; + +import NativeMapView from '../specs/MBXMapViewNativeComponent'; +import { + isFunction, + isAndroid, + type NativeArg, + type OrnamentPositonProp, +} from '../utils'; +import { getFilter } from '../utils/filterUtils'; +import Logger from '../utils/Logger'; +import { FilterExpression } from '../utils/MapboxStyles'; +import { type Position } from '../types/Position'; +import { type Location } from '../modules/location/locationManager'; + +import NativeBridgeComponent from './NativeBridgeComponent'; + +const { MGLModule } = NativeModules; +const { EventTypes } = MGLModule; + +if (MGLModule == null) { + console.error( + 'Native part of Mapbox React Native libraries were not registered properly, double check our native installation guides.', + ); +} +if (!MGLModule.MapboxV10) { + console.warn( + '@rnmapbox/maps: Non v10 implementations are deprecated and will be removed in next version - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre', + ); +} + +export const NATIVE_MODULE_NAME = 'RCTMGLMapView'; + +export const ANDROID_TEXTURE_NATIVE_MODULE_NAME = 'RCTMGLAndroidTextureMapView'; + +const styles = StyleSheet.create({ + matchParent: { flex: 1 }, +}); + +const defaultStyleURL = MGLModule.StyleURL.Street; + +export type Point = { + x: number; + y: number; +}; + +type BBox = [number, number, number, number]; + +export type RegionPayload = { + zoomLevel: number; + heading: number; + animated: boolean; + isUserInteraction: boolean; + visibleBounds: GeoJSON.Position[]; + pitch: number; +}; + +/** + * v10 only + */ +export type MapState = { + properties: { + center: GeoJSON.Position; + bounds: { + ne: GeoJSON.Position; + sw: GeoJSON.Position; + }; + zoom: number; + heading: number; + pitch: number; + }; + gestures: { + isGestureActive: boolean; + }; + timestamp?: number; +}; + +/** + * label localization settings (v10 only). `true` is equivalent to current locale. + */ +type LocalizeLabels = + | { + /** locale code like `es` or `current` for the device's current locale */ + locale: string; + /** layer id to localize. If not specified, all layers will be localized */ + layerIds?: string[]; + } + | true; + +type Props = ViewProps & { + /** + * The distance from the edges of the map view’s frame to the edges of the map view’s logical viewport. + * @deprecated use Camera `padding` instead + */ + contentInset?: number | number[]; + + /** + * The projection used when rendering the map + */ + projection?: 'mercator' | 'globe'; + + /** + * Style URL for map - notice, if non is set it _will_ default to `Mapbox.StyleURL.Street` + */ + styleURL?: string; + + /** + * StyleJSON for map - according to TileJSON specs: https://github.com/mapbox/tilejson-spec + */ + styleJSON?: string; + + /** + * iOS: The preferred frame rate at which the map view is rendered. + * The default value for this property is MGLMapViewPreferredFramesPerSecondDefault, + * which will adaptively set the preferred frame rate based on the capability of + * the user’s device to maintain a smooth experience. This property can be set to arbitrary integer values. + * + * Android: The maximum frame rate at which the map view is rendered, but it can't exceed the ability of device hardware. + * This property can be set to arbitrary integer values. + */ + preferredFramesPerSecond?: number; + + /** + * Enable/Disable zoom on the map + */ + zoomEnabled?: boolean; + + /** + * Enable/Disable scroll on the map + */ + scrollEnabled?: boolean; + + /** + * Enable/Disable pitch on map + */ + pitchEnabled?: boolean; + + /** + * Enable/Disable rotation on map + */ + rotateEnabled?: boolean; + + /** + * The Mapbox terms of service, which governs the use of Mapbox-hosted vector tiles and styles, + * [requires](https://www.mapbox.com/help/how-attribution-works/) these copyright notices to accompany any map that features Mapbox-designed styles, OpenStreetMap data, or other Mapbox data such as satellite or terrain data. + * If that applies to this map view, do not hide this view or remove any notices from it. + * + * You are additionally [required](https://www.mapbox.com/help/how-mobile-apps-work/#telemetry) to provide users with the option to disable anonymous usage and location sharing (telemetry). + * If this view is hidden, you must implement this setting elsewhere in your app. See our website for [Android](https://www.mapbox.com/android-docs/map-sdk/overview/#telemetry-opt-out) and [iOS](https://www.mapbox.com/ios-sdk/#telemetry_opt_out) for implementation details. + * + * Enable/Disable attribution on map. For iOS you need to add MGLMapboxMetricsEnabledSettingShownInApp=YES + * to your Info.plist + */ + attributionEnabled?: boolean; + + /** + * Adds attribution offset, e.g. `{top: 8, left: 8}` will put attribution button in top-left corner of the map. By default on Android, the attribution with information icon (i) will be on the bottom left, while on iOS the mapbox logo will be on bottom left with information icon (i) on bottom right. Read more about mapbox attribution [here](https://docs.mapbox.com/help/getting-started/attribution/) + */ + attributionPosition?: OrnamentPositonProp; + + /** + * MapView's tintColor + */ + tintColor?: string | number[]; + + /** + * Enable/Disable the logo on the map. + */ + logoEnabled?: boolean; + + /** + * Adds logo offset, e.g. `{top: 8, left: 8}` will put the logo in top-left corner of the map + */ + logoPosition?: OrnamentPositonProp; + + /** + * Enable/Disable the compass from appearing on the map + */ + compassEnabled?: boolean; + + /** + * [`mapbox` (v10) implementation only] Enable/Disable if the compass should fade out when the map is pointing north + */ + compassFadeWhenNorth?: boolean; + + /** + * [`mapbox` (v10) implementation only] Adds compass offset, e.g. `{top: 8, left: 8}` will put the compass in top-left corner of the map + */ + compassPosition?: OrnamentPositonProp; + + /** + * Change corner of map the compass starts at. 0: TopLeft, 1: TopRight, 2: BottomLeft, 3: BottomRight + */ + compassViewPosition?: number; + + /** + * Add margins to the compass with x and y values + */ + compassViewMargins?: Point; + + /** + * [iOS, `mapbox` (v10) implementation only] A string referencing an image key. Requires an `Images` component. + */ + compassImage?: string; + + /** + * [`mapbox` (v10) implementation only] Enable/Disable the scale bar from appearing on the map + */ + scaleBarEnabled?: boolean; + + /** + * [`mapbox` (v10) implementation only] Adds scale bar offset, e.g. `{top: 8, left: 8}` will put the scale bar in top-left corner of the map + */ + scaleBarPosition?: OrnamentPositonProp; + + /** + * [Android only] Enable/Disable use of GLSurfaceView instead of TextureView. + */ + surfaceView?: boolean; + + /** + * [Android only] Experimental, call requestDisallowInterceptTouchEvent on parent with onTochEvent, this allows touch interaction to work + * when embedded into a scroll view + */ + requestDisallowInterceptTouchEvent?: boolean; + + /** + * [`mapbox` (v10) implementation only] + * Set map's label locale, e.g. { "locale": "es" } will localize labels to Spanish, { "locale": "current" } will localize labels to system locale. + */ + localizeLabels?: LocalizeLabels; + + /** + * Map press listener, gets called when a user presses the map + */ + onPress?: (feature: GeoJSON.Feature) => void; + + /** + * Map long press listener, gets called when a user long presses the map + */ + onLongPress?: (feature: GeoJSON.Feature) => void; + + /** + * , + ) => void; + + /** + * + * This event is triggered whenever the currently displayed map region is changing. + * + * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds + */ + onRegionIsChanging?: ( + feature: GeoJSON.Feature, + ) => void; + + /** + * + * This event is triggered whenever the currently displayed map region finished changing. + * + * @param {PointFeature} feature - The geojson point feature at the camera center, properties contains zoomLevel, visibleBounds + */ + onRegionDidChange?: ( + feature: GeoJSON.Feature, + ) => void; + + /** + * v10 only, replaces onRegionIsChanging + */ + onCameraChanged?: (state: MapState) => void; + + /** + * v10 only, replaces onRegionDidChange + */ + onMapIdle?: (state: MapState) => void; + + /** + * This event is triggered when the map is about to start loading a new map style. + */ + onWillStartLoadingMap?: () => void; + + /** + * This is triggered when the map has successfully loaded a new map style. + */ + onDidFinishLoadingMap?: () => void; + + /** + * This event is triggered when the map has failed to load a new map style. On v10 it's deprecated and replaced by onMapLoadingError + * @deprecated use onMapLoadingError + */ + onDidFailLoadingMap?: () => void; + + /** + * This event is tiggered when there is an error during map load. V10 only, replaces onDidFailLoadingMap, might be called multiple times and not exclusive with onDidFinishLoadingMap. + */ + onMapLoadingError?: () => void; + + /** + * This event is triggered when the map will start rendering a frame. + */ + onWillStartRenderingFrame?: () => void; + + /** + * This event is triggered when the map finished rendering a frame. + */ + onDidFinishRenderingFrame?: () => void; + + /** + * This event is triggered when the map fully finished rendering a frame. + */ + onDidFinishRenderingFrameFully?: () => void; + + /** + * This event is triggered when the map will start rendering the map. + */ + onWillStartRenderingMap?: () => void; + + /** + * This event is triggered when the map finished rendering the map. + */ + onDidFinishRenderingMap?: () => void; + + /** + * This event is triggered when the map fully finished rendering the map. + */ + onDidFinishRenderingMapFully?: () => void; + + /** + * This event is triggered when the user location is updated. + */ + onUserLocationUpdate?: (feature: Location) => void; + + /** + * This event is triggered when a style has finished loading. + */ + onDidFinishLoadingStyle?: () => void; + + /** + * The emitted frequency of regionwillchange events + */ + regionWillChangeDebounceTime?: number; + + /** + * The emitted frequency of regiondidchange events + */ + regionDidChangeDebounceTime?: number; +}; + +type CallbablePropKeys = + | 'onRegionWillChange' + | 'onRegionIsChanging' + | 'onRegionDidChange' + | 'onUserLocationUpdate' + | 'onWillStartLoadingMap' + | 'onMapLoadingError' + | 'onDidFinishLoadingMap' + | 'onDidFailLoadingMap' + | 'onWillStartRenderingFrame' + | 'onDidFinishRenderingFrame' + | 'onDidFinishRenderingFrameFully' + | 'onWillStartRenderingMap' + | 'onDidFinishRenderingMap' + | 'onDidFinishRenderingMapFully' + | 'onDidFinishLoadingStyle' + | 'onMapIdle' + | 'onCameraChanged'; + +type CallbablePropKeysWithoutOn = CallbablePropKeys extends `on${infer C}` + ? C + : never; + +type Debounced = F & { clear(): void; flush(): void }; + +/** + * MapView backed by Mapbox Native GL + */ +class MapView extends NativeBridgeComponent( + React.PureComponent, + NATIVE_MODULE_NAME, +) { + static defaultProps: Props = { + projection: 'mercator', + scrollEnabled: true, + pitchEnabled: true, + rotateEnabled: true, + attributionEnabled: true, + compassEnabled: false, + compassFadeWhenNorth: false, + logoEnabled: true, + scaleBarEnabled: true, + surfaceView: MGLModule.MapboxV10 ? true : false, + requestDisallowInterceptTouchEvent: false, + regionWillChangeDebounceTime: 10, + regionDidChangeDebounceTime: 500, + }; + + deprecationLogged: { + contentInset: boolean; + regionDidChange: boolean; + regionIsChanging: boolean; + } = { + contentInset: false, + regionDidChange: false, + regionIsChanging: false, + }; + logger: Logger; + _onDebouncedRegionWillChange: Debounced< + ( + payload: GeoJSON.Feature< + GeoJSON.Point, + RegionPayload & { isAnimatingFromUserInteraction: boolean } + >, + ) => void + >; + _onDebouncedRegionDidChange: Debounced< + ( + payload: GeoJSON.Feature< + GeoJSON.Point, + RegionPayload & { isAnimatingFromUserInteraction: boolean } + >, + ) => void + >; + _nativeRef?: RCTMGLMapViewRefType; + state: { + isReady: boolean | null; + region: null; + width: number; + height: number; + isUserInteraction: boolean; + }; + + constructor(props: Props) { + super(props); + + this.logger = Logger.sharedInstance(); + this.logger.start(); + + this.state = { + isReady: null, + region: null, + width: 0, + height: 0, + isUserInteraction: false, + }; + + this._onPress = this._onPress.bind(this); + this._onLongPress = this._onLongPress.bind(this); + this._onChange = this._onChange.bind(this); + this._onLayout = this._onLayout.bind(this); + this._onCameraChanged = this._onCameraChanged.bind(this); + + // debounced map change methods + this._onDebouncedRegionWillChange = debounce( + this._onRegionWillChange.bind(this), + props.regionWillChangeDebounceTime, + true, + ); + + this._onDebouncedRegionDidChange = debounce( + this._onRegionDidChange.bind(this), + props.regionDidChangeDebounceTime, + ); + } + + componentDidMount() { + this._setHandledMapChangedEvents(this.props); + } + + componentWillUnmount() { + this._onDebouncedRegionWillChange.clear(); + this._onDebouncedRegionDidChange.clear(); + this.logger.stop(); + } + + UNSAFE_componentWillReceiveProps(nextProps: Props) { + this._setHandledMapChangedEvents(nextProps); + } + + _setHandledMapChangedEvents(props: Props) { + if (isAndroid() || MGLModule.MapboxV10) { + const events: string[] = []; + + function addIfHasHandler(name: CallbablePropKeysWithoutOn) { + if (props[`on${name}`] != null) { + if (EventTypes[name] == null) { + if (name === 'DidFailLoadingMap') { + console.warn( + `rnmapbox maps: on${name} is deprecated, please use onMapLoadingError`, + ); + } else { + console.warn(`rnmapbox maps: ${name} is not supported`); + } + } else { + events.push(EventTypes[name]); + return true; + } + } + return false; + } + + addIfHasHandler('RegionWillChange'); + addIfHasHandler('RegionIsChanging'); + addIfHasHandler('RegionDidChange'); + addIfHasHandler('UserLocationUpdate'); + addIfHasHandler('WillStartLoadingMap'); + addIfHasHandler('DidFinishLoadingMap'); + addIfHasHandler('MapLoadingError'); + addIfHasHandler('DidFailLoadingMap'); + addIfHasHandler('WillStartRenderingFrame'); + addIfHasHandler('DidFinishRenderingFrame'); + addIfHasHandler('DidFinishRenderingFrameFully'); + addIfHasHandler('WillStartRenderingMap'); + addIfHasHandler('DidFinishRenderingMap'); + addIfHasHandler('DidFinishRenderingMapFully'); + addIfHasHandler('DidFinishLoadingStyle'); + + addIfHasHandler('CameraChanged'); + addIfHasHandler('MapIdle'); + + if (addIfHasHandler('RegionDidChange')) { + if (!this.deprecationLogged.regionDidChange) { + console.warn( + 'onRegionDidChange is deprecated and will be removed in next release - please use onMapIdle. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', + ); + this.deprecationLogged.regionDidChange = true; + } + if (props.onMapIdle) { + console.warn( + 'rnmapbox/maps: only one of MapView.onRegionDidChange or onMapIdle is supported', + ); + } + } + if (addIfHasHandler('RegionIsChanging')) { + if (!this.deprecationLogged.regionIsChanging) { + console.warn( + 'onRegionIsChanging is deprecated and will be removed in next release - please use onCameraChanged. https://github.com/rnmapbox/maps/wiki/Deprecated-RegionIsDidChange', + ); + this.deprecationLogged.regionIsChanging = true; + } + if (props.onCameraChanged) { + console.warn( + 'rnmapbox/maps: only one of MapView.onRegionIsChanging or onCameraChanged is supported', + ); + } + } + + if (props.onRegionWillChange) { + console.warn( + 'onRegionWillChange is deprecated and will be removed in v10 - please use onRegionIsChanging', + ); + } + + this._runNativeCommand('setHandledMapChangedEvents', this._nativeRef, [ + events, + ]); + } + } + + /** + * Converts a geographic coordinate to a point in the given view’s coordinate system. + * + * @example + * const pointInView = await this._map.getPointInView([-37.817070, 144.949901]); + * + * @param {Array} coordinate - A point expressed in the map view's coordinate system. + * @return {Array} + */ + async getPointInView(coordinate: Position): Promise { + const res = await this._runNative<{ pointInView: Position }>( + 'getPointInView', + [coordinate], + ); + return res.pointInView; + } + + /** + * Converts a point in the given view’s coordinate system to a geographic coordinate. + * + * @example + * const coordinate = await this._map.getCoordinateFromView([100, 100]); + * + * @param {Array} point - A point expressed in the given view’s coordinate system. + * @return {Array} + */ + async getCoordinateFromView(point: Position): Promise { + const res = await this._runNative<{ coordinateFromView: Position }>( + 'getCoordinateFromView', + [point], + ); + return res.coordinateFromView; + } + + /** + * The coordinate bounds (ne, sw) visible in the user’s viewport. + * + * @example + * const visibleBounds = await this._map.getVisibleBounds(); + * + * @return {Array} + */ + async getVisibleBounds(): Promise<[Position, Position]> { + const res = await this._runNative<{ visibleBounds: [Position, Position] }>( + 'getVisibleBounds', + ); + return res.visibleBounds; + } + + /** + * Returns an array of rendered map features that intersect with a given point. + * + * @example + * this._map.queryRenderedFeaturesAtPoint([30, 40], ['==', 'type', 'Point'], ['id1', 'id2']) + * + * @param {Array} coordinate - A point expressed in the map view’s coordinate system. + * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. + * @param {Array=} layerIDs - A array of layer id's to filter the features by + * @return {FeatureCollection} + */ + + async queryRenderedFeaturesAtPoint( + coordinate: Position, + filter: FilterExpression | [] = [], + layerIDs: string[] = [], + ): Promise { + if (!coordinate || coordinate.length < 2) { + throw new Error('Must pass in valid coordinate[lng, lat]'); + } + + const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( + 'queryRenderedFeaturesAtPoint', + [coordinate, getFilter(filter), layerIDs], + ); + + if (isAndroid()) { + return JSON.parse(res.data as unknown as string); + } + + return res.data as GeoJSON.FeatureCollection; + } + + /** + * Returns an array of rendered map features that intersect with the given rectangle, + * restricted to the given style layers and filtered by the given predicate. In v10, + * passing an empty array will query the entire visible bounds of the map. + * + * @example + * this._map.queryRenderedFeaturesInRect([30, 40, 20, 10], ['==', 'type', 'Point'], ['id1', 'id2']) + * + * @param {Array} bbox - A rectangle expressed in the map view’s coordinate system. For v10, this can be an empty array to query the visible map area. + * @param {Array=} filter - A set of strings that correspond to the names of layers defined in the current style. Only the features contained in these layers are included in the returned array. + * @param {Array=} layerIDs - A array of layer id's to filter the features by + * @return {FeatureCollection} + */ + async queryRenderedFeaturesInRect( + bbox: BBox | [], + filter: FilterExpression | [] = [], + layerIDs: string[] | null = null, + ): Promise { + if ( + bbox != null && + (bbox.length === 4 || (MGLModule.MapboxV10 && bbox.length === 0)) + ) { + const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( + 'queryRenderedFeaturesInRect', + [bbox, getFilter(filter), layerIDs], + ); + + if (isAndroid()) { + return JSON.parse(res.data as unknown as string); + } + + return res.data; + } else { + throw new Error( + 'Must pass in a valid bounding box: [top, right, bottom, left]. An empty array [] is also acceptable in v10.', + ); + } + } + + /** + * Returns an array of GeoJSON Feature objects representing features within the specified vector tile or GeoJSON source that satisfy the query parameters. + * + * @example + * this._map.querySourceFeatures('your-source-id', [], ['your-source-layer']) + * + * @param {String} sourceId - Style source identifier used to query for source features. + * @param {Array=} filter - A filter to limit query results. + * @param {Array=} sourceLayerIDs - The name of the source layers to query. For vector tile sources, this parameter is required. For GeoJSON sources, it is ignored. + * @return {FeatureCollection} + */ + async querySourceFeatures( + sourceId: string, + filter: FilterExpression | [] = [], + sourceLayerIDs: string[] = [], + ): Promise { + const args = [sourceId, getFilter(filter), sourceLayerIDs]; + const res = await this._runNative<{ data: GeoJSON.FeatureCollection }>( + 'querySourceFeatures', + args, + ); + + if (isAndroid()) { + return JSON.parse(res.data as unknown as string); + } + + return res.data; + } + + /** + * Map camera will perform updates based on provided config. Deprecated use Camera#setCamera. + * @deprecated use Camera#setCamera + */ + setCamera() { + console.warn( + 'MapView.setCamera is deprecated - please use Camera#setCamera', + ); + } + + _runNative( + methodName: string, + args: NativeArg[] = [], + ): Promise { + return super._runNativeCommand( + methodName, + this._nativeRef as HostComponent | undefined, + args, + ); + } + + /** + * Takes snapshot of map with current tiles and returns a URI to the image + * @param {Boolean} writeToDisk If true will create a temp file, otherwise it is in base64 + * @return {String} + */ + async takeSnap(writeToDisk = false): Promise { + const res = await this._runNative<{ uri: string }>('takeSnap', [ + writeToDisk, + ]); + return res.uri; + } + + /** + * Returns the current zoom of the map view. + * + * @example + * const zoom = await this._map.getZoom(); + * + * @return {Number} + */ + + async getZoom(): Promise { + const res = await this._runNative<{ zoom: number }>('getZoom'); + return res.zoom; + } + + /** + * Returns the map's geographical centerpoint + * + * @example + * const center = await this._map.getCenter(); + * + * @return {Array} Coordinates + */ + async getCenter(): Promise { + const res = await this._runNative<{ center: Position }>('getCenter'); + return res.center; + } + + /** + * + * Clears temporary map data from the data path defined in the given resource + * options. Useful to reduce the disk usage or in case the disk cache contains + * invalid data. + * + * v10 only + */ + async clearData(): Promise { + if (!MGLModule.MapboxV10) { + console.warn( + 'RNMapbox: clearData is only implemented in v10 implementation or later', + ); + return; + } + await this._runNative('clearData'); + } + + /** + * Queries the currently loaded data for elevation at a geographical location. + * The elevation is returned in meters relative to mean sea-level. + * Returns null if terrain is disabled or if terrain data for the location hasn't been loaded yet. + * + * @param {Array} coordinate - the coordinates to query elevation at + * @return {Number} + */ + async queryTerrainElevation(coordinate: Position): Promise { + const res = await this._runNative<{ data: number }>( + 'queryTerrainElevation', + [coordinate], + ); + return res.data; + } + + /** + * Sets the visibility of all the layers referencing the specified `sourceLayerId` and/or `sourceId` + * + * @example + * await this._map.setSourceVisibility(false, 'composite', 'building') + * + * @param {boolean} visible - Visibility of the layers + * @param {String} sourceId - Identifier of the target source (e.g. 'composite') + * @param {String=} sourceLayerId - Identifier of the target source-layer (e.g. 'building') + */ + setSourceVisibility( + visible: boolean, + sourceId: string, + sourceLayerId: string | null = null, + ) { + this._runNative('setSourceVisibility', [ + visible, + sourceId, + sourceLayerId, + ]); + } + + /** + * Show the attribution and telemetry action sheet. + * If you implement a custom attribution button, you should add this action to the button. + */ + showAttribution() { + return this._runNativeCommand('showAttribution', this._nativeRef); + } + + _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { + if (isFunction(this.props.onPress)) { + this.props.onPress(e.nativeEvent.payload); + } + } + + _onLongPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { + if (isFunction(this.props.onLongPress)) { + this.props.onLongPress(e.nativeEvent.payload); + } + } + + _onRegionWillChange( + payload: GeoJSON.Feature< + GeoJSON.Point, + RegionPayload & { isAnimatingFromUserInteraction: boolean } + >, + ) { + if (isFunction(this.props.onRegionWillChange)) { + this.props.onRegionWillChange(payload); + } + this.setState({ + isUserInteraction: payload.properties.isUserInteraction, + isAnimatingFromUserInteraction: + payload.properties.isAnimatingFromUserInteraction, + }); + } + + _onRegionDidChange(payload: GeoJSON.Feature) { + if (isFunction(this.props.onRegionDidChange)) { + this.props.onRegionDidChange(payload); + } + this.setState({ region: payload }); + } + + _onCameraChanged(e: NativeSyntheticEvent<{ payload: MapState }>) { + this.props.onCameraChanged?.(e.nativeEvent.payload); + } + + _onChange( + e: NativeSyntheticEvent<{ + type: string; + payload: GeoJSON.Feature< + GeoJSON.Point, + RegionPayload & { isAnimatingFromUserInteraction: boolean } + >; + }>, + ) { + const { regionWillChangeDebounceTime, regionDidChangeDebounceTime } = + this.props; + const { type, payload } = e.nativeEvent; + let propName: CallbablePropKeys | '' = ''; + let deprecatedPropName: CallbablePropKeys | '' = ''; + + switch (type) { + case EventTypes.RegionWillChange: + if (regionWillChangeDebounceTime && regionWillChangeDebounceTime > 0) { + this._onDebouncedRegionWillChange(payload); + } else { + propName = 'onRegionWillChange'; + } + break; + case EventTypes.RegionIsChanging: + propName = 'onRegionIsChanging'; + break; + case EventTypes.RegionDidChange: + if (regionDidChangeDebounceTime && regionDidChangeDebounceTime > 0) { + this._onDebouncedRegionDidChange(payload); + } else { + propName = 'onRegionDidChange'; + } + break; + case EventTypes.CameraChanged: + propName = 'onCameraChanged'; + break; + case EventTypes.MapIdle: + propName = 'onMapIdle'; + break; + case EventTypes.UserLocationUpdated: + propName = 'onUserLocationUpdate'; + break; + case EventTypes.WillStartLoadingMap: + propName = 'onWillStartLoadingMap'; + break; + case EventTypes.DidFinishLoadingMap: + propName = 'onDidFinishLoadingMap'; + break; + case EventTypes.DidFailLoadingMap: + propName = 'onDidFailLoadingMap'; + break; + case EventTypes.MapLoadingError: + propName = 'onMapLoadingError'; + deprecatedPropName = 'onDidFailLoadingMap'; + break; + case EventTypes.WillStartRenderingFrame: + propName = 'onWillStartRenderingFrame'; + break; + case EventTypes.DidFinishRenderingFrame: + propName = 'onDidFinishRenderingFrame'; + break; + case EventTypes.DidFinishRenderingFrameFully: + propName = 'onDidFinishRenderingFrameFully'; + break; + case EventTypes.WillStartRenderingMap: + propName = 'onWillStartRenderingMap'; + break; + case EventTypes.DidFinishRenderingMap: + propName = 'onDidFinishRenderingMap'; + break; + case EventTypes.DidFinishRenderingMapFully: + propName = 'onDidFinishRenderingMapFully'; + break; + case EventTypes.DidFinishLoadingStyle: + propName = 'onDidFinishLoadingStyle'; + break; + default: + console.warn('Unhandled event callback type', type); + } + + if (propName !== '') { + this._handleOnChange(propName, payload); + } + if (deprecatedPropName !== '') { + this._handleOnChange(deprecatedPropName, payload); + } + } + + _onLayout(e: LayoutChangeEvent) { + this.setState({ + isReady: true, + width: e.nativeEvent.layout.width, + height: e.nativeEvent.layout.height, + }); + } + + _handleOnChange(propName: CallbablePropKeys, payload: object) { + const func = this.props[propName] as (payload: object) => void; + if (func && isFunction(func)) { + func(payload); + } + } + + _getContentInset() { + if (!this.props.contentInset) { + return; + } + + if (MGLModule.MapboxV10) { + if (!this.deprecationLogged.contentInset) { + console.warn( + '@rnmapbox/maps: contentInset is deprecated, use Camera padding instead.', + ); + this.deprecationLogged.contentInset = true; + } + } + + if (!Array.isArray(this.props.contentInset)) { + return [this.props.contentInset]; + } + + return this.props.contentInset; + } + + _setNativeRef(nativeRef: RCTMGLMapViewRefType) { + this._nativeRef = nativeRef; + super._runPendingNativeCommands(nativeRef); + } + + setNativeProps(props: NativeProps) { + if (this._nativeRef) { + this._nativeRef.setNativeProps(props); + } + } + + _setStyleURL(props: Props) { + // user set a styleURL, no need to alter props + if (props.styleURL) { + return; + } + + // user set styleJSON pass it to styleURL + if (props.styleJSON && !props.styleURL) { + props.styleURL = props.styleJSON; + } + + // user neither set styleJSON nor styleURL + // set defaultStyleUrl + if (!props.styleJSON || !props.styleURL) { + props.styleURL = defaultStyleURL; + } + } + + _setLocalizeLabels(props: Props) { + if (!MGLModule.MapboxV10) { + return; + } + if (typeof props.localizeLabels === 'boolean') { + props.localizeLabels = { + locale: 'current', + }; + } + } + + render() { + const props = { + ...this.props, + contentInset: this._getContentInset(), + style: styles.matchParent, + }; + + this._setStyleURL(props); + this._setLocalizeLabels(props); + + const callbacks = { + ref: (nativeRef: RCTMGLMapViewRefType) => this._setNativeRef(nativeRef), + onPress: this._onPress, + onLongPress: this._onLongPress, + onMapChange: this._onChange, + onAndroidCallback: isAndroid() ? this._onAndroidCallback : undefined, + onCameraChanged: this._onCameraChanged, + }; + + let mapView = null; + if (isAndroid() && !this.props.surfaceView && this.state.isReady) { + mapView = ( + + {this.props.children} + + ); + } else if (this.state.isReady) { + mapView = ( + + {this.props.children} + + ); + } + + return ( + + {mapView} + + ); + } +} + +type NativeProps = Omit< + Props, + 'onPress' | 'onLongPress' | 'onCameraChanged' +> & { + onPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; + onLongPress(event: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>): void; + onCameraChanged(event: NativeSyntheticEvent<{ payload: MapState }>): void; +}; + +type RCTMGLMapViewRefType = Component & Readonly; // const RCTMGLMapView = requireNativeComponent(NATIVE_MODULE_NAME); +// TODO: figure out how to pick the correct implementation +const RCTMGLMapView = NativeMapView; -// let RCTMGLAndroidTextureMapView: typeof RCTMGLMapView; -// if (isAndroid()) { -// RCTMGLAndroidTextureMapView = requireNativeComponent( -// ANDROID_TEXTURE_NATIVE_MODULE_NAME, -// ); -// } +let RCTMGLAndroidTextureMapView: any; +if (isAndroid()) { + RCTMGLAndroidTextureMapView = requireNativeComponent( + ANDROID_TEXTURE_NATIVE_MODULE_NAME, + ); +} -// export default MapView; +export default MapView; diff --git a/src/specs/MBXMapViewNativeComponent.ts b/src/specs/MBXMapViewNativeComponent.ts index e51bcd358..4bee50863 100644 --- a/src/specs/MBXMapViewNativeComponent.ts +++ b/src/specs/MBXMapViewNativeComponent.ts @@ -4,45 +4,122 @@ import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNati import { WithDefault, DirectEventHandler, + BubblingEventHandler, + Int32, } from 'react-native/Libraries/Types/CodegenTypes'; -/// see -// https://github.com/react-native-webview/react-native-webview/blob/681aac4fe7e35834264daa01b67a9893c4a9ebe7/src/RNCWebViewNativeComponent.ts#L4 -// for complex example - +type OnCameraChangedEventType = { payload: string }; type OnPressEventType = { payload: string }; -type OnWillStartLoadingType = { payload: boolean }; +type OnMapChangeEventType = { payload: boolean }; + +// UnsafeObject is exported from CodegenTypes but parser expects UnsafeMixed? +type UnsafeObject = UnsafeMixed; export interface NativeProps extends ViewProps { - // add other props here - contentInset?: ReadonlyArray; + onCameraChanged?: DirectEventHandler; + + attributionEnabled?: boolean; + attributionPosition?: UnsafeObject; + + logoEnabled?: boolean; + logoPosition?: UnsafeObject; + + compassEnabled?: boolean; + compassFadeWhenNorth?: boolean; + compassPosition?: UnsafeObject; + compassViewPosition?: Int32; + compassViewMargins?: ReadonlyArray; + compassImage?: string; + + scaleBarEnabled?: boolean; + scaleBarPosition?: UnsafeObject; + + zoomEnabled?: boolean; + scrollEnabled?: boolean; + rotateEnabled?: boolean; + pitchEnabled?: boolean; projection?: WithDefault<'mercator' | 'globe', 'mercator'>; + localizeLabels?: UnsafeObject; styleURL?: string; - onWillStartLoadingMap?: DirectEventHandler; - - onPress?: DirectEventHandler; - // + onPress?: BubblingEventHandler; + onLongPress?: BubblingEventHandler; + onMapChange?: BubblingEventHandler; } -type MapViewViewType = HostComponent; - -export interface NativeCommands { - sayHello: ( - viewRef: React.ElementRef, - message: string, - ) => void; - setHandledMapChangedEvents: ( - viewRef: React.ElementRef, - events: string, // ReadonlyArray, - ) => void; -} +// TODO: figure out how to please the 3 different parsers and native at once + +// type MapViewViewType = HostComponent; + +// export interface NativeCommands { +// takeSnap: ( +// viewRef: React.ElementRef, +// writeToDisk: boolean, +// ) => Promise; +// queryTerrainElevation: ( +// viewRef: React.ElementRef, +// coordinates: ReadonlyArray, +// ) => Promise; +// setSourceVisibility: ( +// viewRef: React.ElementRef, +// visible: boolean, +// sourceId: string, +// sourceLayerId: string, +// ) => Promise; +// getCenter: ( +// viewRef: React.ElementRef, +// ) => Promise; +// getCoordinateFromView: ( +// viewRef: React.ElementRef, +// atPoint: ReadonlyArray, +// ) => Promise; +// getPointInView: ( +// viewRef: React.ElementRef, +// atCoordinate: ReadonlyArray, +// ) => Promise; +// getZoom: ( +// viewRef: React.ElementRef, +// ) => Promise; +// getVisibleBounds: ( +// viewRef: React.ElementRef, +// ) => Promise; +// queryRenderedFeaturesAtPoint: ( +// viewRef: React.ElementRef, +// atPoint: ReadonlyArray, +// withFilter: ReadonlyArray, +// withLayerIDs: ReadonlyArray, +// ) => Promise; +// queryRenderedFeaturesInRect: ( +// viewRef: React.ElementRef, +// withBBox: ReadonlyArray, +// withFilter: ReadonlyArray, +// withLayerIDs: ReadonlyArray, +// ) => Promise; +// setHandledMapChangedEvents: ( +// viewRef: React.ElementRef, +// events: ReadonlyArray, +// ) => void; +// clearData: (viewRef: React.ElementRef) => void; +// } -export const Commands: NativeCommands = codegenNativeCommands({ - supportedCommands: ['sayHello', 'setHandledMapChangedEvents'], -}); +// export const Commands: NativeCommands = codegenNativeCommands({ +// supportedCommands: [ +// 'takeSnap', +// 'queryTerrainElevation', +// 'setSourceVisibility', +// 'getCenter', +// 'getCoordinateFromView', +// 'getPointInView', +// 'getZoom', +// 'getVisibleBounds', +// 'queryRenderedFeaturesAtPoint', +// 'queryRenderedFeaturesInRect', +// 'setHandledMapChangedEvents', +// 'clearData', +// ], +// }); export default codegenNativeComponent( 'MBXMapView', From 01477067602786c11dff0ce28e3f26b700e3601c Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 28 Aug 2023 10:28:37 +0200 Subject: [PATCH 05/33] Use one view manager? --- example/ios/Podfile.lock | 24 ++-- ios/RCTMGL-v10/MBXMapViewManager.m | 105 +++++++++++++++-- ...wManager.swift => MBXMapViewManager.swift} | 10 +- ios/RCTMGL-v10/RCTMGLMapViewManager.m | 107 ------------------ src/components/MapView.tsx | 2 +- 5 files changed, 114 insertions(+), 134 deletions(-) rename ios/RCTMGL-v10/{RCTMGLMapViewManager.swift => MBXMapViewManager.swift} (98%) delete mode 100644 ios/RCTMGL-v10/RCTMGLMapViewManager.m diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 9432d347b..1b6a8eb29 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -338,12 +338,8 @@ PODS: - React-jsinspector (0.71.7) - React-logger (0.71.7): - glog - - react-native-safe-area-context (4.6.4): - - RCT-Folly - - RCTRequired - - RCTTypeSafety + - react-native-safe-area-context (4.7.1): - React-Core - - ReactCommon/turbomodule/core - React-perflogger (0.71.7) - React-RCTActionSheet (0.71.7): - React-Core/RCTActionSheetHeaders (= 0.71.7) @@ -428,20 +424,20 @@ PODS: - React-jsi (= 0.71.7) - React-logger (= 0.71.7) - React-perflogger (= 0.71.7) - - RNCAsyncStorage (1.19.0): + - RNCAsyncStorage (1.19.2): - React-Core - - rnmapbox-maps (10.0.12-rc.0): + - rnmapbox-maps (10.0.12-rc.3): - MapboxMaps (~> 10.15.0) - React - React-Core - - rnmapbox-maps/DynamicLibrary (= 10.0.12-rc.0) + - rnmapbox-maps/DynamicLibrary (= 10.0.12-rc.3) - Turf - - rnmapbox-maps/DynamicLibrary (10.0.12-rc.0): + - rnmapbox-maps/DynamicLibrary (10.0.12-rc.3): - MapboxMaps (~> 10.15.0) - React - React-Core - Turf - - RNScreens (3.22.0): + - RNScreens (3.24.0): - React-Core - React-RCTImage - RNSVG (12.5.1): @@ -664,7 +660,7 @@ SPEC CHECKSUMS: React-jsiexecutor: eaa5f71eb8f6861cf0e57f1a0f52aeb020d9e18e React-jsinspector: 9885f6f94d231b95a739ef7bb50536fb87ce7539 React-logger: 3f8ebad1be1bf3299d1ab6d7f971802d7395c7ef - react-native-safe-area-context: 68b07eabfb0d14547d36f6929c0e98d818064f02 + react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2 React-perflogger: 2d505bbe298e3b7bacdd9e542b15535be07220f6 React-RCTActionSheet: 0e96e4560bd733c9b37efbf68f5b1a47615892fb React-RCTAnimation: fd138e26f120371c87e406745a27535e2c8a04ef @@ -678,9 +674,9 @@ SPEC CHECKSUMS: React-RCTVibration: 08f132cad9896458776f37c112e71d60aef1c6ae React-runtimeexecutor: c5c89f8f543842dd864b63ded1b0bbb9c9445328 ReactCommon: dbfbe2f7f3c5ce4ce44f43f2fd0d5950d1eb67c5 - RNCAsyncStorage: 4b98ac3c64efa4e35c1197cb0c5ca5e9f5d4c666 - rnmapbox-maps: 8be8b4f7531f261ec1799978ebcb3aa4fa2a280a - RNScreens: 68fd1060f57dd1023880bf4c05d74784b5392789 + RNCAsyncStorage: f57e929cd7757f2cb3dd8186d123c09e8281a1ad + rnmapbox-maps: 0660e2b651eea7aa9c2e51440ec55fc491d2eb16 + RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7 RNSVG: d7d7bc8229af3842c9cfc3a723c815a52cdd1105 RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 diff --git a/ios/RCTMGL-v10/MBXMapViewManager.m b/ios/RCTMGL-v10/MBXMapViewManager.m index fba715ff9..e352cc5a5 100644 --- a/ios/RCTMGL-v10/MBXMapViewManager.m +++ b/ios/RCTMGL-v10/MBXMapViewManager.m @@ -1,16 +1,107 @@ +#import #import -// used only to register the view in UIManager and generate view config -// probably can be deleted once static view configs and bridgeless are a thing +@interface RCT_EXTERN_REMAP_MODULE(MBXMapView, MBXMapViewManager, RCTViewManager) -@interface MBXMapViewManager : RCTViewManager +RCT_EXPORT_VIEW_PROPERTY(onCameraChanged, RCTDirectEventBlock) -@end +RCT_REMAP_VIEW_PROPERTY(attributionEnabled, reactAttributionEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(attributionPosition, reactAttributionPosition, NSDictionary) + +RCT_REMAP_VIEW_PROPERTY(logoEnabled, reactLogoEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(logoPosition, reactLogoPosition, NSDictionary) + +RCT_REMAP_VIEW_PROPERTY(compassEnabled, reactCompassEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(compassFadeWhenNorth, reactCompassFadeWhenNorth, BOOL) +RCT_REMAP_VIEW_PROPERTY(compassPosition, reactCompassPosition, NSDictionary) +RCT_REMAP_VIEW_PROPERTY(compassViewPosition, reactCompassViewPosition, NSInteger) +RCT_REMAP_VIEW_PROPERTY(compassViewMargins, reactCompassViewMargins, CGPoint) +RCT_REMAP_VIEW_PROPERTY(compassImage, reactCompassImage, NSString) + +RCT_REMAP_VIEW_PROPERTY(scaleBarEnabled, reactScaleBarEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(scaleBarPosition, reactScaleBarPosition, NSDictionary) + +RCT_REMAP_VIEW_PROPERTY(zoomEnabled, reactZoomEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(scrollEnabled, reactScrollEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(rotateEnabled, reactRotateEnabled, BOOL) +RCT_REMAP_VIEW_PROPERTY(pitchEnabled, reactPitchEnabled, BOOL) + +RCT_REMAP_VIEW_PROPERTY(projection, reactProjection, NSString) +RCT_REMAP_VIEW_PROPERTY(localizeLabels, reactLocalizeLabels, NSDictionary) + +RCT_REMAP_VIEW_PROPERTY(styleURL, reactStyleURL, NSString) +RCT_REMAP_VIEW_PROPERTY(onPress, reactOnPress, RCTBubblingEventBlock) +RCT_REMAP_VIEW_PROPERTY(onLongPress, reactOnLongPress, RCTBubblingEventBlock) +RCT_REMAP_VIEW_PROPERTY(onMapChange, reactOnMapChange, RCTBubblingEventBlock) + +RCT_EXTERN_METHOD(takeSnap:(nonnull NSNumber*)reactTag + writeToDisk:(BOOL)writeToDisk + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(queryTerrainElevation:(nonnull NSNumber*)reactTag + coordinates: (nonnull NSArray*)coordinates + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(setSourceVisibility:(nonnull NSNumber *)reactTag + visible:(BOOL)visible + sourceId:(nonnull NSString*)sourceId + sourceLayerId:(nullable NSString*)sourceLayerId + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(getCenter:(nonnull NSNumber*)reactTag + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(getCoordinateFromView:(nonnull NSNumber*)reactTag + atPoint:(CGPoint)point + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(getPointInView:(nonnull NSNumber*)reactTag + atCoordinate:(NSArray*)coordinate + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(getZoom:(nonnull NSNumber*)reactTag + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(getVisibleBounds:(nonnull NSNumber*)reactTag + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(queryRenderedFeaturesAtPoint:(nonnull NSNumber*)reactTag + atPoint:(NSArray*)point + withFilter:(NSArray*)filter + withLayerIDs:(NSArray*)layerIDs + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(queryRenderedFeaturesInRect:(nonnull NSNumber*)reactTag + withBBox:(NSArray*)bbox + withFilter:(NSArray*)filter + withLayerIDs:(NSArray*)layerIDs + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) -@implementation MBXMapViewManager +RCT_EXTERN_METHOD(querySourceFeatures:(nonnull NSNumber*)reactTag + withSourceId:(NSString*)sourceId + withFilter:(NSArray)filter + withSourceLayerIds:(NSArray*)sourceLayerIds + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) -RCT_EXPORT_MODULE(MBXMapView) +RCT_EXTERN_METHOD(setHandledMapChangedEvents:(nonnull NSNumber*)reactTag + events:(NSArray*)events + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) -RCT_EXPORT_VIEW_PROPERTY(attributionEnabled, BOOL) +RCT_EXTERN_METHOD(clearData: (nonnull NSNumber*)reactTag + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject + ) @end diff --git a/ios/RCTMGL-v10/RCTMGLMapViewManager.swift b/ios/RCTMGL-v10/MBXMapViewManager.swift similarity index 98% rename from ios/RCTMGL-v10/RCTMGLMapViewManager.swift rename to ios/RCTMGL-v10/MBXMapViewManager.swift index edddaa6fd..883a60038 100644 --- a/ios/RCTMGL-v10/RCTMGLMapViewManager.swift +++ b/ios/RCTMGL-v10/MBXMapViewManager.swift @@ -1,7 +1,7 @@ import MapboxMaps -@objc(RCTMGLMapViewManager) -class RCTMGLMapViewManager: RCTViewManager { +@objc(MBXMapViewManager) +class MBXMapViewManager: RCTViewManager { @objc override static func requiresMainQueueSetup() -> Bool { return true @@ -19,7 +19,7 @@ class RCTMGLMapViewManager: RCTViewManager { // MARK: helpers -extension RCTMGLMapViewManager { +extension MBXMapViewManager { func withMapView( _ reactTag: NSNumber, name: String, @@ -59,7 +59,7 @@ extension RCTMGLMapViewManager { // MARK: - react methods -extension RCTMGLMapViewManager { +extension MBXMapViewManager { @objc func takeSnap(_ reactTag: NSNumber, writeToDisk: Bool, @@ -175,7 +175,7 @@ extension RCTMGLMapViewManager { // MARK: - queryRenderedFeatures -extension RCTMGLMapViewManager { +extension MBXMapViewManager { @objc func queryRenderedFeaturesAtPoint( _ reactTag: NSNumber, diff --git a/ios/RCTMGL-v10/RCTMGLMapViewManager.m b/ios/RCTMGL-v10/RCTMGLMapViewManager.m deleted file mode 100644 index cb0c04797..000000000 --- a/ios/RCTMGL-v10/RCTMGLMapViewManager.m +++ /dev/null @@ -1,107 +0,0 @@ -#import -#import - -@interface RCT_EXTERN_REMAP_MODULE(RCTMGLMapView, RCTMGLMapViewManager, RCTViewManager) - -RCT_EXPORT_VIEW_PROPERTY(onCameraChanged, RCTDirectEventBlock) - -RCT_REMAP_VIEW_PROPERTY(attributionEnabled, reactAttributionEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(attributionPosition, reactAttributionPosition, NSDictionary) - -RCT_REMAP_VIEW_PROPERTY(logoEnabled, reactLogoEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(logoPosition, reactLogoPosition, NSDictionary) - -RCT_REMAP_VIEW_PROPERTY(compassEnabled, reactCompassEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(compassFadeWhenNorth, reactCompassFadeWhenNorth, BOOL) -RCT_REMAP_VIEW_PROPERTY(compassPosition, reactCompassPosition, NSDictionary) -RCT_REMAP_VIEW_PROPERTY(compassViewPosition, reactCompassViewPosition, NSInteger) -RCT_REMAP_VIEW_PROPERTY(compassViewMargins, reactCompassViewMargins, CGPoint) -RCT_REMAP_VIEW_PROPERTY(compassImage, reactCompassImage, NSString) - -RCT_REMAP_VIEW_PROPERTY(scaleBarEnabled, reactScaleBarEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(scaleBarPosition, reactScaleBarPosition, NSDictionary) - -RCT_REMAP_VIEW_PROPERTY(zoomEnabled, reactZoomEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(scrollEnabled, reactScrollEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(rotateEnabled, reactRotateEnabled, BOOL) -RCT_REMAP_VIEW_PROPERTY(pitchEnabled, reactPitchEnabled, BOOL) - -RCT_REMAP_VIEW_PROPERTY(projection, reactProjection, NSString) -RCT_REMAP_VIEW_PROPERTY(localizeLabels, reactLocalizeLabels, NSDictionary) - -RCT_REMAP_VIEW_PROPERTY(styleURL, reactStyleURL, NSString) -RCT_REMAP_VIEW_PROPERTY(onPress, reactOnPress, RCTBubblingEventBlock) -RCT_REMAP_VIEW_PROPERTY(onLongPress, reactOnLongPress, RCTBubblingEventBlock) -RCT_REMAP_VIEW_PROPERTY(onMapChange, reactOnMapChange, RCTBubblingEventBlock) - -RCT_EXTERN_METHOD(takeSnap:(nonnull NSNumber*)reactTag - writeToDisk:(BOOL)writeToDisk - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(queryTerrainElevation:(nonnull NSNumber*)reactTag - coordinates: (nonnull NSArray*)coordinates - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(setSourceVisibility:(nonnull NSNumber *)reactTag - visible:(BOOL)visible - sourceId:(nonnull NSString*)sourceId - sourceLayerId:(nullable NSString*)sourceLayerId - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getCenter:(nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getCoordinateFromView:(nonnull NSNumber*)reactTag - atPoint:(CGPoint)point - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getPointInView:(nonnull NSNumber*)reactTag - atCoordinate:(NSArray*)coordinate - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getZoom:(nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getVisibleBounds:(nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(queryRenderedFeaturesAtPoint:(nonnull NSNumber*)reactTag - atPoint:(NSArray*)point - withFilter:(NSArray*)filter - withLayerIDs:(NSArray*)layerIDs - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(queryRenderedFeaturesInRect:(nonnull NSNumber*)reactTag - withBBox:(NSArray*)bbox - withFilter:(NSArray*)filter - withLayerIDs:(NSArray*)layerIDs - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(querySourceFeatures:(nonnull NSNumber*)reactTag - withSourceId:(NSString*)sourceId - withFilter:(NSArray)filter - withSourceLayerIds:(NSArray*)sourceLayerIds - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(setHandledMapChangedEvents:(nonnull NSNumber*)reactTag - events:(NSArray*)events - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(clearData: (nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject - ) - -@end diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index 855f446e6..4ed88a19e 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -41,7 +41,7 @@ if (!MGLModule.MapboxV10) { ); } -export const NATIVE_MODULE_NAME = 'RCTMGLMapView'; +export const NATIVE_MODULE_NAME = 'MBXMapView'; export const ANDROID_TEXTURE_NATIVE_MODULE_NAME = 'RCTMGLAndroidTextureMapView'; From 5785b8833963186b218ac47f442a49dc4c800cad Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 28 Aug 2023 14:21:23 +0200 Subject: [PATCH 06/33] Update spec --- src/specs/MBXMapViewNativeComponent.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/specs/MBXMapViewNativeComponent.ts b/src/specs/MBXMapViewNativeComponent.ts index 4bee50863..f2424f391 100644 --- a/src/specs/MBXMapViewNativeComponent.ts +++ b/src/specs/MBXMapViewNativeComponent.ts @@ -15,6 +15,11 @@ type OnMapChangeEventType = { payload: boolean }; // UnsafeObject is exported from CodegenTypes but parser expects UnsafeMixed? type UnsafeObject = UnsafeMixed; +type Point = { + x: Int32; + y: Int32; +}; + export interface NativeProps extends ViewProps { onCameraChanged?: DirectEventHandler; @@ -28,7 +33,7 @@ export interface NativeProps extends ViewProps { compassFadeWhenNorth?: boolean; compassPosition?: UnsafeObject; compassViewPosition?: Int32; - compassViewMargins?: ReadonlyArray; + compassViewMargins?: Point; compassImage?: string; scaleBarEnabled?: boolean; @@ -39,6 +44,8 @@ export interface NativeProps extends ViewProps { rotateEnabled?: boolean; pitchEnabled?: boolean; + requestDisallowInterceptTouchEvent?: boolean; + projection?: WithDefault<'mercator' | 'globe', 'mercator'>; localizeLabels?: UnsafeObject; From 09bb480dbff892506abb4015b0ed088bcc2756fb Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 28 Aug 2023 14:21:46 +0200 Subject: [PATCH 07/33] Start android --- android/build.gradle | 15 +++ .../mapview/RCTMGLMapViewManager.kt | 117 ++++++++++++------ 2 files changed, 93 insertions(+), 39 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index fadbded33..fffb0bd17 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -5,6 +5,14 @@ def safeExtGet(prop, fallback) { rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback } +def isNewArchitectureEnabled() { + // To opt-in for the New Architecture, you can either: + // - Set `newArchEnabled` to true inside the `gradle.properties` file + // - Invoke gradle with `-newArchEnabled=true` + // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true` + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + // expo plugin if (rootProject.ext.has('expoRNMapboxMapsImpl')) { rootProject.ext.set('RNMapboxMapsImpl', rootProject.ext.get('expoRNMapboxMapsImpl')) @@ -25,6 +33,13 @@ buildscript { } } +if (isNewArchitectureEnabled()) { + apply plugin: 'com.facebook.react' + + react { + codegenJavaPackageName = "com.mapbox.rctmgl" + } +} apply plugin: 'com.android.library' if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") { diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt index 9490f984b..e473fb349 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt @@ -11,6 +11,10 @@ import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.annotations.ReactProp import com.mapbox.rctmgl.events.constants.EventKeys import com.facebook.react.common.MapBuilder +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.viewmanagers.MBXMapViewManagerDelegate +import com.facebook.react.viewmanagers.MBXMapViewManagerInterface +import com.mapbox.maps.MapInitOptions import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName import com.mapbox.maps.plugin.gestures.gestures import com.mapbox.maps.plugin.logo.logo @@ -43,8 +47,19 @@ interface CommandResponse { } open class RCTMGLMapViewManager(context: ReactApplicationContext) : - AbstractEventEmitter(context) { + AbstractEventEmitter(context), MBXMapViewManagerInterface { private val mViews: MutableMap + + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = MBXMapViewManagerDelegate(this) + } + + override fun getDelegate(): ViewManagerDelegate? { + return mDelegate + } + override fun getName(): String { return REACT_CLASS } @@ -105,7 +120,7 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : // region React Props @ReactProp(name = "projection") - fun setProjection(mapView: RCTMGLMapView, projection: String?) { + override fun setProjection(mapView: RCTMGLMapView, projection: String?) { mapView.setReactProjection( if (projection == "globe") ProjectionName.GLOBE else ProjectionName.MERCATOR ) } @@ -117,7 +132,7 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : } @ReactProp(name = "styleURL") - fun setStyleURL(mapView: RCTMGLMapView, styleURL: String?) { + override fun setStyleURL(mapView: RCTMGLMapView, styleURL: String?) { mapView.setReactStyleURL(styleURL!!) } @@ -127,7 +142,7 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : } @ReactProp(name = "zoomEnabled") - fun setZoomEnabled(map: RCTMGLMapView, zoomEnabled: Boolean) { + override fun setZoomEnabled(map: RCTMGLMapView, zoomEnabled: Boolean) { val mapView = map.mapView mapView.gestures.pinchToZoomEnabled = zoomEnabled mapView.gestures.doubleTouchToZoomOutEnabled = zoomEnabled @@ -135,66 +150,66 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : } @ReactProp(name = "scrollEnabled") - fun setScrollEnabled(map: RCTMGLMapView, scrollEnabled: Boolean) { + override fun setScrollEnabled(map: RCTMGLMapView, scrollEnabled: Boolean) { val mapView = map.mapView mapView.gestures.scrollEnabled = scrollEnabled } @ReactProp(name = "pitchEnabled") - fun setPitchEnabled(map: RCTMGLMapView, pitchEnabled: Boolean) { + override fun setPitchEnabled(map: RCTMGLMapView, pitchEnabled: Boolean) { val mapView = map.mapView mapView.gestures.pitchEnabled = pitchEnabled } @ReactProp(name = "rotateEnabled") - fun setRotateEnabled(map: RCTMGLMapView, rotateEnabled: Boolean) { + override fun setRotateEnabled(map: RCTMGLMapView, rotateEnabled: Boolean) { val mapView = map.mapView mapView.gestures.rotateEnabled = rotateEnabled } @ReactProp(name = "attributionEnabled") - fun setAttributionEnabled(mapView: RCTMGLMapView?, attributionEnabled: Boolean?) { - mapView!!.setReactAttributionEnabled(attributionEnabled); + override fun setAttributionEnabled(mapView: RCTMGLMapView, attributionEnabled: Boolean) { + mapView.setReactAttributionEnabled(attributionEnabled) } @ReactProp(name = "attributionPosition") - fun setAttributionPosition(mapView: RCTMGLMapView?, attributionPosition: ReadableMap?) { - mapView!!.setReactAttributionPosition(attributionPosition); + fun setAttributionPosition(mapView: RCTMGLMapView, attributionPosition: ReadableMap) { + mapView.setReactAttributionPosition(attributionPosition) } @ReactProp(name = "attributionViewMargins") - fun setAttributionViewMargins(mapView: RCTMGLMapView?, scaleBarMargins: ReadableMap?) { - mapView!!.setReactAttributionViewMargins(scaleBarMargins!!); + fun setAttributionViewMargins(mapView: RCTMGLMapView, scaleBarMargins: ReadableMap) { + mapView.setReactAttributionViewMargins(scaleBarMargins) } @ReactProp(name = "attributionViewPosition") - fun setAttributionViewPosition(mapView: RCTMGLMapView?, scaleBarPosition: Int) { - mapView!!.setReactAttributionViewPosition(scaleBarPosition!!) + fun setAttributionViewPosition(mapView: RCTMGLMapView, scaleBarPosition: Int) { + mapView.setReactAttributionViewPosition(scaleBarPosition) } @ReactProp(name = "logoEnabled") - fun setLogoEnabled(mapView: RCTMGLMapView?, logoEnabled: Boolean?) { - mapView!!.setReactLogoEnabled(logoEnabled); + override fun setLogoEnabled(mapView: RCTMGLMapView, logoEnabled: Boolean) { + mapView.setReactLogoEnabled(logoEnabled) } @ReactProp(name = "logoPosition") - fun setLogoPosition(mapView: RCTMGLMapView?, logoPosition: ReadableMap?) { - mapView!!.setReactLogoPosition(logoPosition); + fun setLogoPosition(mapView: RCTMGLMapView, logoPosition: ReadableMap?) { + mapView.setReactLogoPosition(logoPosition) } @ReactProp(name = "scaleBarEnabled") - fun setScaleBarEnabled(mapView: RCTMGLMapView?, scaleBarEnabled: Boolean) { - mapView!!.setReactScaleBarEnabled(scaleBarEnabled); + override fun setScaleBarEnabled(mapView: RCTMGLMapView, scaleBarEnabled: Boolean) { + mapView.setReactScaleBarEnabled(scaleBarEnabled) } @ReactProp(name = "scaleBarViewMargins") - fun setScaleBarViewMargins(mapView: RCTMGLMapView?, scaleBarMargins: ReadableMap?) { - mapView!!.setReactScaleBarViewMargins(scaleBarMargins!!); + fun setScaleBarViewMargins(mapView: RCTMGLMapView, scaleBarMargins: ReadableMap) { + mapView.setReactScaleBarViewMargins(scaleBarMargins) } @ReactProp(name = "scaleBarViewPosition") - fun setScaleBarViewPosition(mapView: RCTMGLMapView?, scaleBarPosition: Int) { - mapView!!.setReactScaleBarViewPosition(scaleBarPosition!!) + fun setScaleBarViewPosition(mapView: RCTMGLMapView, scaleBarPosition: Int) { + mapView.setReactScaleBarViewPosition(scaleBarPosition) } @ReactProp(name = "scaleBarPosition") @@ -203,45 +218,69 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : } @ReactProp(name = "compassEnabled") - fun setCompassEnabled(mapView: RCTMGLMapView?, compassEnabled: Boolean) { - mapView!!.setReactCompassEnabled(compassEnabled); + override fun setCompassEnabled(mapView: RCTMGLMapView, compassEnabled: Boolean) { + mapView.setReactCompassEnabled(compassEnabled) } @ReactProp(name = "compassFadeWhenNorth") - fun setCompassFadeWhenNorth(mapView: RCTMGLMapView?, compassFadeWhenNorth: Boolean) { - mapView!!.setReactCompassFadeWhenNorth(compassFadeWhenNorth!!); + override fun setCompassFadeWhenNorth(mapView: RCTMGLMapView, compassFadeWhenNorth: Boolean) { + mapView.setReactCompassFadeWhenNorth(compassFadeWhenNorth) } @ReactProp(name = "compassViewMargins") - fun setCompassViewMargins(mapView: RCTMGLMapView?, compassViewMargins: ReadableMap?) { - mapView!!.setReactCompassViewMargins(compassViewMargins!!); + override fun setCompassViewMargins(mapView: RCTMGLMapView, compassViewMargins: ReadableMap?) { + mapView.setReactCompassViewMargins(compassViewMargins ?: return) } @ReactProp(name = "compassViewPosition") - fun setCompassViewPosition(mapView: RCTMGLMapView?, compassViewPosition: Int) { - mapView!!.setReactCompassViewPosition(compassViewPosition!!) + override fun setCompassViewPosition(mapView: RCTMGLMapView, compassViewPosition: Int) { + mapView.setReactCompassViewPosition(compassViewPosition) } @ReactProp(name = "compassPosition") - fun setCompassPosition(mapView: RCTMGLMapView?, compassMargins: ReadableMap) { - mapView!!.setReactCompassPosition(compassMargins) + fun setCompassPosition(mapView: RCTMGLMapView, compassMargins: ReadableMap) { + mapView.setReactCompassPosition(compassMargins) } @ReactProp(name = "contentInset") - fun setContentInset(mapView: RCTMGLMapView?, array: ReadableArray?) { + fun setContentInset(mapView: RCTMGLMapView, array: ReadableArray) { //mapView.setReactContentInset(array); } @ReactProp(name = "tintColor", customType = "Color") - fun setTintColor(mapView: RCTMGLMapView?, tintColor: Int?) { + fun setTintColor(mapView: RCTMGLMapView, tintColor: Int) { //mapView.setTintColor(tintColor); } @ReactProp(name = "requestDisallowInterceptTouchEvent") - fun setRequestDisallowInterceptTouchEvent(mapView: RCTMGLMapView, requestDisallowInterceptTouchEvent: Boolean) { + override fun setRequestDisallowInterceptTouchEvent(mapView: RCTMGLMapView, requestDisallowInterceptTouchEvent: Boolean) { mapView.requestDisallowInterceptTouchEvent = requestDisallowInterceptTouchEvent } + override fun setAttributionPosition(view: RCTMGLMapView, value: Dynamic) { + this.setLocalizeLabels(view, value.asMap()) + } + + override fun setLogoPosition(view: RCTMGLMapView, value: Dynamic) { + this.setLogoPosition(view, value.asMap()) + } + + override fun setCompassPosition(view: RCTMGLMapView, value: Dynamic) { + this.setCompassPosition(view, value.asMap()) + } + + override fun setCompassImage(view: RCTMGLMapView, value: String?) { + // TODO: No-op on Android? + } + + override fun setScaleBarPosition(view: RCTMGLMapView, value: Dynamic) { + // TODO: should this call setScaleBarViewPosition? + } + + override fun setLocalizeLabels(view: RCTMGLMapView, value: Dynamic) { + this.setLocalizeLabels(view, value.asMap()) + } + //endregion //region Custom Events override fun customEvents(): Map? { @@ -409,7 +448,7 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : companion object { const val LOG_TAG = "RCTMGLMapViewManager" - const val REACT_CLASS = "RCTMGLMapView" + const val REACT_CLASS = "MBXMapView" } init { From 81130bfc553c103edef2de912f9530ea6f3ef717 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 28 Aug 2023 14:22:25 +0200 Subject: [PATCH 08/33] Convert dynamic position to dict --- fabricexample/ios/Podfile.lock | 8 ++++---- ios/RCTMGL-v10/MBXMapView.h | 1 + ios/RCTMGL-v10/MBXMapView.swift | 4 ++++ ios/RCTMGL-v10/MBXMapViewComponentView.mm | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock index 0525186de..66f30b298 100644 --- a/fabricexample/ios/Podfile.lock +++ b/fabricexample/ios/Podfile.lock @@ -1007,13 +1007,13 @@ PODS: - React-jsi (= 0.72.4) - React-logger (= 0.72.4) - React-perflogger (= 0.72.4) - - rnmapbox-maps (10.0.12-rc.3): + - rnmapbox-maps (10.0.12): - MapboxMaps (~> 10.15.0) - React - React-Core - - rnmapbox-maps/DynamicLibrary (= 10.0.12-rc.3) + - rnmapbox-maps/DynamicLibrary (= 10.0.12) - Turf - - rnmapbox-maps/DynamicLibrary (10.0.12-rc.3): + - rnmapbox-maps/DynamicLibrary (10.0.12): - hermes-engine - MapboxMaps (~> 10.15.0) - RCT-Folly (= 2021.07.22.00) @@ -1232,7 +1232,7 @@ SPEC CHECKSUMS: React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d - rnmapbox-maps: 0421180d3c876686f95e02fde625f4b073885c49 + rnmapbox-maps: dbaa77c7b8afec28f333c7d7ed3e57cd266acbc2 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h index 4904d55cf..77850b328 100644 --- a/ios/RCTMGL-v10/MBXMapView.h +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -2,6 +2,7 @@ @protocol MBXMapViewProtocol - (void)setAttributionEnabled:(BOOL)enabled; +- (void)setAttributionPosition:(NSDictionary*)position; @end @interface MBXMapViewFactory diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift index 3df06cf88..9de1704c7 100644 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -13,6 +13,10 @@ open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { public func setAttributionEnabled(_ enabled: Bool) { self.setReactAttributionEnabled(enabled) } + + public func setAttributionPosition(_ position: [String : NSNumber]!) { + self.setReactAttributionPosition(position) + } } @objc(MBXMapViewFactory) diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index 6167e7b19..5c734c323 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -56,11 +56,26 @@ + (ComponentDescriptorProvider)componentDescriptorProvider return concreteComponentDescriptorProvider(); } +- (NSDictionary*)convertPositionToDictionary:(const folly::dynamic*)position { + NSMutableDictionary* result = [[NSMutableDictionary alloc] init]; + + if (!position->isNull()) { + for (auto& pair : position->items()) { + NSString* key = [NSString stringWithUTF8String:pair.first.getString().c_str()]; + NSNumber* value = [[NSNumber alloc] initWithInt:pair.second.getDouble()]; + [result setValue:value forKey:key]; + } + } + + return result; +} + - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps { const auto &newProps = *std::static_pointer_cast(props); [_view setAttributionEnabled:newProps.attributionEnabled]; + [_view setAttributionPosition:[self convertPositionToDictionary:&newProps.attributionPosition]]; [super updateProps:props oldProps:oldProps]; } From 08fceb563acbd6a739bef1ed3f49cac64477ab4a Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 28 Aug 2023 17:44:14 +0200 Subject: [PATCH 09/33] Set iOS props --- ios/RCTMGL-v10/MBXMapView.h | 22 +++++++ ios/RCTMGL-v10/MBXMapView.swift | 74 ++++++++++++++++++++++- ios/RCTMGL-v10/MBXMapViewComponentView.mm | 39 ++++++++++++ src/specs/MBXMapViewNativeComponent.ts | 7 ++- 4 files changed, 139 insertions(+), 3 deletions(-) diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h index 77850b328..a2c52b8ae 100644 --- a/ios/RCTMGL-v10/MBXMapView.h +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -3,6 +3,28 @@ @protocol MBXMapViewProtocol - (void)setAttributionEnabled:(BOOL)enabled; - (void)setAttributionPosition:(NSDictionary*)position; +- (void)setLogoEnabled:(BOOL)enabled; +- (void)setLogoPosition:(NSDictionary*)position; + +- (void)setCompassEnabled:(BOOL)enabled; +- (void)setCompassFadeWhenNorth:(BOOL)enabled; +- (void)setCompassPosition:(NSDictionary*)position; +- (void)setCompassViewPosition:(NSInteger)position; +- (void)setCompassViewMargins:(CGPoint)position; +- (void)setCompassImage:(NSString*)position; + +- (void)setScaleBarEnabled:(BOOL)enabled; +- (void)setScaleBarPosition:(NSDictionary*)position; + +- (void)setZoomEnabled:(BOOL)enabled; +- (void)setScrollEnabled:(BOOL)enabled; +- (void)setRotateEnabled:(BOOL)enabled; +- (void)setPitchEnabled:(BOOL)enabled; + +- (void)setProjection:(NSString*)projection; +- (void)setLocalizeLabels:(NSDictionary*)labels; +- (void)setStyleUrl:(NSString*)url; + @end @interface MBXMapViewFactory diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift index 9de1704c7..83e3a58f6 100644 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -14,8 +14,76 @@ open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { self.setReactAttributionEnabled(enabled) } - public func setAttributionPosition(_ position: [String : NSNumber]!) { - self.setReactAttributionPosition(position) + public func setAttributionPosition(_ position: [String : NSNumber]!) { + self.setReactAttributionPosition(position) + } + + public func setLogoEnabled(_ enabled: Bool) { + self.setReactLogoEnabled(enabled) + } + + public func setLogoPosition(_ position: [String : NSNumber]!) { + self.setReactLogoPosition(position) + } + + public func setCompassEnabled(_ enabled: Bool) { + self.setReactCompassEnabled(enabled) + } + + public func setCompassFadeWhenNorth(_ enabled: Bool) { + self.setReactCompassFadeWhenNorth(enabled) + } + + public func setCompassPosition(_ position: [String : NSNumber]!) { + self.setReactCompassPosition(position) + } + + public func setCompassViewPosition(_ position: NSInteger) { + self.setReactCompassViewPosition(position) + } + + public func setCompassViewMargins(_ margins: CGPoint) { + self.setReactCompassViewMargins(margins) + } + + public func setCompassImage(_ position: String) { + self.setReactCompassImage(position) + } + + public func setScaleBarEnabled(_ enabled: Bool) { + self.setReactScaleBarEnabled(enabled) + } + + public func setScaleBarPosition(_ position: [String : NSNumber]!) { + self.setReactScaleBarPosition(position) + } + + public func setZoomEnabled(_ enabled: Bool) { + self.setReactZoomEnabled(enabled) + } + + public func setRotateEnabled(_ enabled: Bool) { + self.setReactRotateEnabled(enabled) + } + + public func setScrollEnabled(_ enabled: Bool) { + self.setReactScrollEnabled(enabled) + } + + public func setPitchEnabled(_ enabled: Bool) { + self.setReactPitchEnabled(enabled) + } + + public func setProjection(_ projection: String) { + self.setReactProjection(projection) + } + + public func setLocalizeLabels(_ labels: [AnyHashable : Any]) { + self.setReactLocalizeLabels(labels as NSDictionary) + } + + public func setStyleUrl(_ url: String) { + self.setReactStyleURL(url) } } @@ -26,3 +94,5 @@ open class MBXMapViewFactory : NSObject { return MBXMapView(frame: frame, eventDispatcher: eventDispatcher) } } + +@objc(MAAAAAAAAAAAAAAAAap) public extension MapView {} diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index 5c734c323..6df216bdd 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -70,12 +70,51 @@ - (NSDictionary*)convertPositionToDictionary:(const folly::dynamic*)position { return result; } +- (NSDictionary*)convertLocalizeLabels:(const MBXMapViewLocalizeLabelsStruct*)labels { + NSMutableDictionary* result = [[NSMutableDictionary alloc] init]; + NSMutableArray* ids = [[NSMutableArray alloc] init]; + + [result setValue:[NSString stringWithUTF8String:labels->locale.c_str()] forKey:@"locale"]; + + for (auto& layerId : labels->layerIds) { + NSString* value = [NSString stringWithUTF8String:layerId.c_str()]; + [ids addObject:value]; + } + + [result setValue:ids forKey:@"layerIds"]; + + return result; +} + - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps { const auto &newProps = *std::static_pointer_cast(props); [_view setAttributionEnabled:newProps.attributionEnabled]; [_view setAttributionPosition:[self convertPositionToDictionary:&newProps.attributionPosition]]; + + [_view setLogoEnabled:newProps.logoEnabled]; + [_view setLogoPosition:[self convertPositionToDictionary:&newProps.logoPosition]]; + + [_view setCompassEnabled:newProps.compassEnabled]; + [_view setCompassFadeWhenNorth:newProps.compassFadeWhenNorth]; + [_view setCompassPosition:[self convertPositionToDictionary:&newProps.compassPosition]]; + [_view setCompassViewPosition:newProps.compassViewPosition]; + [_view setCompassViewMargins:CGPointMake(newProps.compassViewMargins.x, newProps.compassViewMargins.y)]; + [_view setCompassImage:[NSString stringWithUTF8String:newProps.compassImage.c_str()]]; + + [_view setScaleBarEnabled:newProps.scaleBarEnabled]; + [_view setScaleBarPosition:[self convertPositionToDictionary:&newProps.scaleBarPosition]]; + + [_view setZoomEnabled:newProps.zoomEnabled]; + [_view setScrollEnabled:newProps.scrollEnabled]; + [_view setRotateEnabled:newProps.rotateEnabled]; + [_view setPitchEnabled:newProps.pitchEnabled]; + + [_view setProjection:newProps.projection == MBXMapViewProjection::Mercator ? @"mercator" : @"globe"]; + [_view setLocalizeLabels:[self convertLocalizeLabels:&newProps.localizeLabels]]; + [_view setStyleUrl:[NSString stringWithUTF8String:newProps.styleURL.c_str()]]; + [super updateProps:props oldProps:oldProps]; } diff --git a/src/specs/MBXMapViewNativeComponent.ts b/src/specs/MBXMapViewNativeComponent.ts index f2424f391..8634c1848 100644 --- a/src/specs/MBXMapViewNativeComponent.ts +++ b/src/specs/MBXMapViewNativeComponent.ts @@ -20,6 +20,11 @@ type Point = { y: Int32; }; +type LocalizeLabels = { + locale: string; + layerIds?: string[]; +}; + export interface NativeProps extends ViewProps { onCameraChanged?: DirectEventHandler; @@ -47,7 +52,7 @@ export interface NativeProps extends ViewProps { requestDisallowInterceptTouchEvent?: boolean; projection?: WithDefault<'mercator' | 'globe', 'mercator'>; - localizeLabels?: UnsafeObject; + localizeLabels?: LocalizeLabels; styleURL?: string; From 287c7e2d60a1acdc0bb76e2be6d832e46f50b586 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 29 Aug 2023 12:31:33 +0200 Subject: [PATCH 10/33] Update spec --- .../mapview/RCTMGLMapViewManager.kt | 8 ++----- src/specs/MBXMapViewNativeComponent.ts | 24 +++++++++---------- src/specs/codegenUtils.ts | 4 ++++ 3 files changed, 17 insertions(+), 19 deletions(-) create mode 100644 src/specs/codegenUtils.ts diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt index e473fb349..27cbdb318 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt @@ -125,7 +125,7 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : } @ReactProp(name = "localizeLabels") - fun setLocalizeLabels(mapView: RCTMGLMapView, localeMap: ReadableMap?) { + override fun setLocalizeLabels(mapView: RCTMGLMapView, localeMap: ReadableMap?) { val locale = localeMap?.getString("locale") val layerIds = localeMap?.getArray("layerIds")?.toArrayList()?.mapNotNull {it?.toString()} mapView.setReactLocalizeLabels(locale, layerIds) @@ -258,7 +258,7 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : } override fun setAttributionPosition(view: RCTMGLMapView, value: Dynamic) { - this.setLocalizeLabels(view, value.asMap()) + this.setAttributionPosition(view, value.asMap()) } override fun setLogoPosition(view: RCTMGLMapView, value: Dynamic) { @@ -277,10 +277,6 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : // TODO: should this call setScaleBarViewPosition? } - override fun setLocalizeLabels(view: RCTMGLMapView, value: Dynamic) { - this.setLocalizeLabels(view, value.asMap()) - } - //endregion //region Custom Events override fun customEvents(): Map? { diff --git a/src/specs/MBXMapViewNativeComponent.ts b/src/specs/MBXMapViewNativeComponent.ts index 8634c1848..e67854408 100644 --- a/src/specs/MBXMapViewNativeComponent.ts +++ b/src/specs/MBXMapViewNativeComponent.ts @@ -4,16 +4,14 @@ import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNati import { WithDefault, DirectEventHandler, - BubblingEventHandler, Int32, } from 'react-native/Libraries/Types/CodegenTypes'; -type OnCameraChangedEventType = { payload: string }; -type OnPressEventType = { payload: string }; -type OnMapChangeEventType = { payload: boolean }; +import type { UnsafeMixed } from './codegenUtils'; -// UnsafeObject is exported from CodegenTypes but parser expects UnsafeMixed? -type UnsafeObject = UnsafeMixed; +type OnCameraChangedEventType = { type: string; payload: string }; +type OnPressEventType = { type: string; payload: string }; +type OnMapChangeEventType = { type: string; payload: string }; type Point = { x: Int32; @@ -29,20 +27,20 @@ export interface NativeProps extends ViewProps { onCameraChanged?: DirectEventHandler; attributionEnabled?: boolean; - attributionPosition?: UnsafeObject; + attributionPosition?: UnsafeMixed; logoEnabled?: boolean; - logoPosition?: UnsafeObject; + logoPosition?: UnsafeMixed; compassEnabled?: boolean; compassFadeWhenNorth?: boolean; - compassPosition?: UnsafeObject; + compassPosition?: UnsafeMixed; compassViewPosition?: Int32; compassViewMargins?: Point; compassImage?: string; scaleBarEnabled?: boolean; - scaleBarPosition?: UnsafeObject; + scaleBarPosition?: UnsafeMixed; zoomEnabled?: boolean; scrollEnabled?: boolean; @@ -56,9 +54,9 @@ export interface NativeProps extends ViewProps { styleURL?: string; - onPress?: BubblingEventHandler; - onLongPress?: BubblingEventHandler; - onMapChange?: BubblingEventHandler; + onPress?: DirectEventHandler; + onLongPress?: DirectEventHandler; + onMapChange?: DirectEventHandler; } // TODO: figure out how to please the 3 different parsers and native at once diff --git a/src/specs/codegenUtils.ts b/src/specs/codegenUtils.ts new file mode 100644 index 000000000..d3b0c3d44 --- /dev/null +++ b/src/specs/codegenUtils.ts @@ -0,0 +1,4 @@ +// codegen will generate folly::dynamic in place of this type, but it's not exported by RN +// since codegen doesn't really follow imports, this way we can trick it into generating the correct type +// while keeping typescript happy +export type UnsafeMixed = any; From a05160a98761de040ae5211064a0cfaf1f25f4fc Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 29 Aug 2023 12:32:32 +0200 Subject: [PATCH 11/33] Update Android event emitter --- .../com/mapbox/rctmgl/components/AbstractEventEmitter.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt index 180ded8a4..3b8c8ec6c 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt @@ -5,11 +5,10 @@ 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.UIManagerHelper 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. @@ -47,7 +46,7 @@ abstract class AbstractEventEmitter(reactApplicationContext: Rea } override fun addEventEmitters(context: ThemedReactContext, view: T) { - mEventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher + mEventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view!!.id) } override fun getExportedCustomDirectEventTypeConstants(): Map? { From 585dbf4f8a0329abbe0f9397a6da9f9fd52b84c9 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 29 Aug 2023 12:33:46 +0200 Subject: [PATCH 12/33] iOS events shenanigans --- ios/RCTMGL-v10/MBXMapView.h | 4 + ios/RCTMGL-v10/MBXMapView.swift | 21 ++++- ios/RCTMGL-v10/MBXMapViewComponentView.mm | 99 ++++++++++++++++++++--- src/components/MapView.tsx | 31 ++++++- 4 files changed, 136 insertions(+), 19 deletions(-) diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h index a2c52b8ae..3971ac68c 100644 --- a/ios/RCTMGL-v10/MBXMapView.h +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -25,6 +25,10 @@ - (void)setLocalizeLabels:(NSDictionary*)labels; - (void)setStyleUrl:(NSString*)url; +- (void)setOnPress:(RCTBubblingEventBlock)callback; +- (void)setOnLongPress:(RCTBubblingEventBlock)callback; +- (void)setOnMapChange:(RCTBubblingEventBlock)callback; + @end @interface MBXMapViewFactory diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift index 83e3a58f6..75ccc9d58 100644 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -85,14 +85,29 @@ open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { public func setStyleUrl(_ url: String) { self.setReactStyleURL(url) } + + public func setOnPress(_ callback: @escaping RCTBubblingEventBlock) { + self.setReactOnPress(callback) + } + + public func setOnLongPress(_ callback: @escaping RCTBubblingEventBlock) { + self.setReactOnLongPress(callback) + } + + public func setOnMapChange(_ callback: @escaping RCTBubblingEventBlock) { + self.setReactOnMapChange(callback) + } } @objc(MBXMapViewFactory) open class MBXMapViewFactory : NSObject { @objc static func create(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) -> MBXMapViewProtocol { - return MBXMapView(frame: frame, eventDispatcher: eventDispatcher) + let view = MBXMapView(frame: frame, eventDispatcher: eventDispatcher) + + // just need to pass something, it won't really be used on fabric, but it's used to create events (it won't impact sending them) + view.reactTag = -1; + + return view } } - -@objc(MAAAAAAAAAAAAAAAAap) public extension MapView {} diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index 6df216bdd..a3c2ce94e 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -16,16 +16,27 @@ using namespace facebook::react; @interface MBXMapViewComponentView () +- (void)dispatchCameraChangedEvent:(NSDictionary*)event; @end @interface MBXMapViewEventDispatcher : NSObject @end -@implementation MBXMapViewEventDispatcher +@implementation MBXMapViewEventDispatcher { + MBXMapViewComponentView* _componentView; +} + +- (instancetype)initWithComponentView:(MBXMapViewComponentView*)componentView { + if (self = [super init]) { + _componentView = componentView; + } + + return self; +} -// TODO: figure out how to use this custom dispatcher to bridge the new cpp event emitter and swift impl - (void)sendEvent:(id)event { - NSLog(@"attepmt to send map event: %@", event.eventName); + NSDictionary* payload = [event arguments][2]; + [_componentView dispatchCameraChangedEvent:payload]; } @end @@ -40,8 +51,47 @@ - (instancetype)initWithFrame:(CGRect)frame if (self = [super initWithFrame:frame]) { static const auto defaultProps = std::make_shared(); _props = defaultProps; - _eventDispatcher = [[MBXMapViewEventDispatcher alloc] init]; + _eventDispatcher = [[MBXMapViewEventDispatcher alloc] initWithComponentView:self]; _view = [MBXMapViewFactory createWithFrame:frame eventDispatcher:_eventDispatcher]; + + // capture weak self reference to prevent retain cycle + __weak __typeof__(self) weakSelf = self; + + [_view setOnPress:^(NSDictionary* event) { + __typeof__(self) strongSelf = weakSelf; + + if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { + const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; + std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onPress({type, json}); + } + }]; + + [_view setOnLongPress:^(NSDictionary* event) { + __typeof__(self) strongSelf = weakSelf; + + if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { + const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; + std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onLongPress({type, json}); + } + }]; + + [_view setOnMapChange:^(NSDictionary* event) { + __typeof__(self) strongSelf = weakSelf; + + if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { + const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; + std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onMapChange({type, json}); + } + }]; + +// [_view setOnCameraChange:^(NSDictionary* event) { +// __typeof__(self) strongSelf = weakSelf; +// +// if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { +// const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; +// std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onCameraChanged({type, json}); +// } +// }]; self.contentView = _view; } @@ -49,11 +99,29 @@ - (instancetype)initWithFrame:(CGRect)frame return self; } -#pragma mark - RCTComponentViewProtocol +- (void)dispatchCameraChangedEvent:(NSDictionary*)event { + const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; + std::dynamic_pointer_cast(self->_eventEmitter)->onCameraChanged({type, json}); +} -+ (ComponentDescriptorProvider)componentDescriptorProvider -{ - return concreteComponentDescriptorProvider(); ++ (std::tuple)stringifyEventData:(NSDictionary*)event { + std::string type = [event valueForKey:@"type"] == nil ? "" : std::string([[event valueForKey:@"type"] UTF8String]); + std::string json = "{}"; + + NSError *error; + NSData *jsonData = nil; + + if ([event valueForKey:@"payload"] != nil) { + jsonData = [NSJSONSerialization dataWithJSONObject:[event valueForKey:@"payload"] + options:0 + error:&error]; + } + + if (jsonData) { + json = std::string([[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] UTF8String]); + } + + return {type, json}; } - (NSDictionary*)convertPositionToDictionary:(const folly::dynamic*)position { @@ -86,10 +154,16 @@ - (NSDictionary*)convertLocalizeLabels:(const MBXMapViewLocalizeLabelsStruct*)la return result; } +#pragma mark - RCTComponentViewProtocol + ++ (ComponentDescriptorProvider)componentDescriptorProvider +{ + return concreteComponentDescriptorProvider(); +} + - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps { const auto &newProps = *std::static_pointer_cast(props); - [_view setAttributionEnabled:newProps.attributionEnabled]; [_view setAttributionPosition:[self convertPositionToDictionary:&newProps.attributionPosition]]; @@ -112,10 +186,11 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & [_view setPitchEnabled:newProps.pitchEnabled]; [_view setProjection:newProps.projection == MBXMapViewProjection::Mercator ? @"mercator" : @"globe"]; - [_view setLocalizeLabels:[self convertLocalizeLabels:&newProps.localizeLabels]]; [_view setStyleUrl:[NSString stringWithUTF8String:newProps.styleURL.c_str()]]; - - + + if (!newProps.localizeLabels.locale.empty()) { + [_view setLocalizeLabels:[self convertLocalizeLabels:&newProps.localizeLabels]]; + } [super updateProps:props oldProps:oldProps]; } @end diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index 4ed88a19e..8372505c3 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -851,13 +851,25 @@ class MapView extends NativeBridgeComponent( _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { if (isFunction(this.props.onPress)) { - this.props.onPress(e.nativeEvent.payload); + const { payload } = e.nativeEvent; + + if (typeof payload === 'string') { + this.props.onPress(JSON.parse(payload)); + } else { + this.props.onPress(payload); + } } } _onLongPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { if (isFunction(this.props.onLongPress)) { - this.props.onLongPress(e.nativeEvent.payload); + const { payload } = e.nativeEvent; + + if (typeof payload === 'string') { + this.props.onLongPress(JSON.parse(payload)); + } else { + this.props.onLongPress(payload); + } } } @@ -885,7 +897,13 @@ class MapView extends NativeBridgeComponent( } _onCameraChanged(e: NativeSyntheticEvent<{ payload: MapState }>) { - this.props.onCameraChanged?.(e.nativeEvent.payload); + const { payload } = e.nativeEvent; + + if (typeof payload === 'string') { + this.props.onCameraChanged?.(JSON.parse(payload)); + } else { + this.props.onCameraChanged?.(payload); + } } _onChange( @@ -899,7 +917,12 @@ class MapView extends NativeBridgeComponent( ) { const { regionWillChangeDebounceTime, regionDidChangeDebounceTime } = this.props; - const { type, payload } = e.nativeEvent; + const { type } = e.nativeEvent; + const payload = + typeof e.nativeEvent.payload === 'string' + ? JSON.parse(e.nativeEvent.payload) + : e.nativeEvent.payload; + let propName: CallbablePropKeys | '' = ''; let deprecatedPropName: CallbablePropKeys | '' = ''; From e89206a68c435cfcce4eec9e78bebbda344dada8 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 30 Aug 2023 11:47:14 +0200 Subject: [PATCH 13/33] Use module instead of native commands on new arch --- ios/RCTMGL-v10/MBXMapView.h | 2 + ios/RCTMGL-v10/MBXMapView.swift | 5 ++ ios/RCTMGL-v10/MBXMapViewComponentView.h | 5 ++ ios/RCTMGL-v10/MBXMapViewComponentView.mm | 7 +- ios/RCTMGL-v10/MBXMapViewModule.h | 11 +++ ios/RCTMGL-v10/MBXMapViewModule.mm | 100 ++++++++++++++++++++++ src/components/MapView.tsx | 35 +++++++- src/specs/MBXMapViewNativeComponent.ts | 73 ---------------- src/specs/NativeMapViewModule.ts | 48 +++++++++++ 9 files changed, 210 insertions(+), 76 deletions(-) create mode 100644 ios/RCTMGL-v10/MBXMapViewModule.h create mode 100644 ios/RCTMGL-v10/MBXMapViewModule.mm create mode 100644 src/specs/NativeMapViewModule.ts diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h index 3971ac68c..f49b81653 100644 --- a/ios/RCTMGL-v10/MBXMapView.h +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -29,6 +29,8 @@ - (void)setOnLongPress:(RCTBubblingEventBlock)callback; - (void)setOnMapChange:(RCTBubblingEventBlock)callback; +- (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve; + @end @interface MBXMapViewFactory diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift index 75ccc9d58..ca071b1a4 100644 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -97,6 +97,11 @@ open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { public func setOnMapChange(_ callback: @escaping RCTBubblingEventBlock) { self.setReactOnMapChange(callback) } + + public func takeSnap(_ writeToDisk: Bool, resolve: RCTPromiseResolveBlock!) { + let uri = self.takeSnap(writeToDisk: writeToDisk) + resolve(["uri": uri.absoluteString]) + } } @objc(MBXMapViewFactory) diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.h b/ios/RCTMGL-v10/MBXMapViewComponentView.h index 9b349fc23..92ef74e3a 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.h +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.h @@ -2,12 +2,17 @@ #import +#import #import NS_ASSUME_NONNULL_BEGIN @interface MBXMapViewComponentView : RCTViewComponentView +- (void)dispatchCameraChangedEvent:(NSDictionary*)event; + +- (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve; + @end NS_ASSUME_NONNULL_END diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index a3c2ce94e..a1e23e76b 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -2,7 +2,6 @@ #import "MBXMapViewComponentView.h" -#import #import #import @@ -16,7 +15,6 @@ using namespace facebook::react; @interface MBXMapViewComponentView () -- (void)dispatchCameraChangedEvent:(NSDictionary*)event; @end @interface MBXMapViewEventDispatcher : NSObject @@ -154,6 +152,10 @@ - (NSDictionary*)convertLocalizeLabels:(const MBXMapViewLocalizeLabelsStruct*)la return result; } +- (void)takeSnap:(BOOL)writeToDisk resolve:(id)resolve { + [_view takeSnap:writeToDisk resolve:resolve]; +} + #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider @@ -193,6 +195,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & } [super updateProps:props oldProps:oldProps]; } + @end Class MBXMapViewCls(void) diff --git a/ios/RCTMGL-v10/MBXMapViewModule.h b/ios/RCTMGL-v10/MBXMapViewModule.h new file mode 100644 index 000000000..cc4de2afd --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapViewModule.h @@ -0,0 +1,11 @@ +#ifdef RCT_NEW_ARCH_ENABLED +#import "rnmapbox_maps.h" + +#import +#import + +@interface MBXMapViewModule : NSObject + +@end + +#endif diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm new file mode 100644 index 000000000..e232ed57c --- /dev/null +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -0,0 +1,100 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#import "MBXMapViewModule.h" +#import "MBXMapViewComponentView.h" + +@implementation MBXMapViewModule + +RCT_EXPORT_MODULE(); + +#ifdef RCT_NEW_ARCH_ENABLED +@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED; +#endif // RCT_NEW_ARCH_ENABLED +@synthesize bridge = _bridge; + +- (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(MBXMapViewComponentView*))block reject:(RCTPromiseRejectBlock)reject +{ + dispatch_async(dispatch_get_main_queue(), ^{ + MBXMapViewComponentView* view = [self.viewRegistry_DEPRECATED viewForReactTag:viewRef]; + + if (view != nil) { + block(view); + } else { + reject(@"takeSnap", [NSString stringWithFormat:@"Unknown find reactTag: %@", viewRef], nil); + } + }); +} + + +- (void)takeSnap:(NSNumber*)viewRef writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +{ + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view){ + [view takeSnap:writeToDisk resolve:resolve]; + } reject:reject]; +} + +- (void)clearData:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"clearData", @"not implemented yet", nil); +} + + +- (void)getCenter:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"getCenter", @"not implemented yet", nil); +} + + +- (void)getCoordinateFromView:(double)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"getCoordinateFromView", @"not implemented yet", nil); +} + + +- (void)getPointInView:(double)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"getPointInView", @"not implemented yet", nil); +} + + +- (void)getVisibleBounds:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"getVisibleBounds", @"not implemented yet", nil); +} + + +- (void)getZoom:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"getZoom", @"not implemented yet", nil); +} + + +- (void)queryRenderedFeaturesAtPoint:(double)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"queryRenderedFeaturesAtPoint", @"not implemented yet", nil); +} + + +- (void)queryRenderedFeaturesInRect:(double)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"queryRenderedFeaturesInRect", @"not implemented yet", nil); +} + + +- (void)queryTerrainElevation:(double)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"queryTerrainElevation", @"not implemented yet", nil); +} + + +- (void)setHandledMapChangedEvents:(double)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"setHandledMapChangedEvents", @"not implemented yet", nil); +} + + +- (void)setSourceVisibility:(double)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + reject(@"setSourceVisibility", @"not implemented yet", nil); +} + + +// Thanks to this guard, we won't compile this code when we build for the old architecture. +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + +@end + +#endif // RCT_NEW_ARCH_ENABLED diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index 8372505c3..be8f03c3f 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -9,10 +9,12 @@ import { NativeMethods, HostComponent, LayoutChangeEvent, + findNodeHandle, } from 'react-native'; import { debounce } from 'debounce'; import NativeMapView from '../specs/MBXMapViewNativeComponent'; +import NativeMapViewModule from '../specs/NativeMapViewModule'; import { isFunction, isAndroid, @@ -739,7 +741,7 @@ class MapView extends NativeBridgeComponent( methodName: string, args: NativeArg[] = [], ): Promise { - return super._runNativeCommand( + return this._runNativeCommand( methodName, this._nativeRef as HostComponent | undefined, args, @@ -849,6 +851,37 @@ class MapView extends NativeBridgeComponent( return this._runNativeCommand('showAttribution', this._nativeRef); } + _runNativeCommand( + methodName: string, + nativeRef: RefType | undefined, + args?: NativeArg[], + ): Promise { + if (NativeMapViewModule) { + // when this method is called after component mounts, the ref is not yet set + // schedule it to be called after a timeout + if (!this._nativeRef) { + return new Promise((resolve) => setTimeout(resolve, 1)).then(() => { + return this._runNativeCommand(methodName, this._nativeRef, args); + }); + } + + const handle = findNodeHandle(nativeRef as any); + + // @ts-expect-error TS says that string cannot be used to index NativeMapViewModule. + // It can, it's just not pretty. + return NativeMapViewModule[methodName]?.( + handle, + ...(args ?? []), + ) as Promise; + } else { + return super._runNativeCommand( + methodName, + nativeRef, + args, + ); + } + } + _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { if (isFunction(this.props.onPress)) { const { payload } = e.nativeEvent; diff --git a/src/specs/MBXMapViewNativeComponent.ts b/src/specs/MBXMapViewNativeComponent.ts index e67854408..68377ed44 100644 --- a/src/specs/MBXMapViewNativeComponent.ts +++ b/src/specs/MBXMapViewNativeComponent.ts @@ -1,5 +1,4 @@ import type { HostComponent, ViewProps } from 'react-native'; -import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands'; import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; import { WithDefault, @@ -59,78 +58,6 @@ export interface NativeProps extends ViewProps { onMapChange?: DirectEventHandler; } -// TODO: figure out how to please the 3 different parsers and native at once - -// type MapViewViewType = HostComponent; - -// export interface NativeCommands { -// takeSnap: ( -// viewRef: React.ElementRef, -// writeToDisk: boolean, -// ) => Promise; -// queryTerrainElevation: ( -// viewRef: React.ElementRef, -// coordinates: ReadonlyArray, -// ) => Promise; -// setSourceVisibility: ( -// viewRef: React.ElementRef, -// visible: boolean, -// sourceId: string, -// sourceLayerId: string, -// ) => Promise; -// getCenter: ( -// viewRef: React.ElementRef, -// ) => Promise; -// getCoordinateFromView: ( -// viewRef: React.ElementRef, -// atPoint: ReadonlyArray, -// ) => Promise; -// getPointInView: ( -// viewRef: React.ElementRef, -// atCoordinate: ReadonlyArray, -// ) => Promise; -// getZoom: ( -// viewRef: React.ElementRef, -// ) => Promise; -// getVisibleBounds: ( -// viewRef: React.ElementRef, -// ) => Promise; -// queryRenderedFeaturesAtPoint: ( -// viewRef: React.ElementRef, -// atPoint: ReadonlyArray, -// withFilter: ReadonlyArray, -// withLayerIDs: ReadonlyArray, -// ) => Promise; -// queryRenderedFeaturesInRect: ( -// viewRef: React.ElementRef, -// withBBox: ReadonlyArray, -// withFilter: ReadonlyArray, -// withLayerIDs: ReadonlyArray, -// ) => Promise; -// setHandledMapChangedEvents: ( -// viewRef: React.ElementRef, -// events: ReadonlyArray, -// ) => void; -// clearData: (viewRef: React.ElementRef) => void; -// } - -// export const Commands: NativeCommands = codegenNativeCommands({ -// supportedCommands: [ -// 'takeSnap', -// 'queryTerrainElevation', -// 'setSourceVisibility', -// 'getCenter', -// 'getCoordinateFromView', -// 'getPointInView', -// 'getZoom', -// 'getVisibleBounds', -// 'queryRenderedFeaturesAtPoint', -// 'queryRenderedFeaturesInRect', -// 'setHandledMapChangedEvents', -// 'clearData', -// ], -// }); - export default codegenNativeComponent( 'MBXMapView', ) as HostComponent; diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts new file mode 100644 index 000000000..a30227237 --- /dev/null +++ b/src/specs/NativeMapViewModule.ts @@ -0,0 +1,48 @@ +/* eslint-disable @typescript-eslint/ban-types */ +import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport'; +import { Int32 } from 'react-native/Libraries/Types/CodegenTypes'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + takeSnap: (viewRef: Int32 | null, writeToDisk: boolean) => Promise; + queryTerrainElevation: ( + viewRef: Int32, + coordinates: ReadonlyArray, + ) => Promise; + setSourceVisibility: ( + viewRef: Int32, + visible: boolean, + sourceId: string, + sourceLayerId: string, + ) => Promise; + getCenter: (viewRef: Int32) => Promise; + getCoordinateFromView: ( + viewRef: Int32, + atPoint: ReadonlyArray, + ) => Promise; + getPointInView: ( + viewRef: Int32, + atCoordinate: ReadonlyArray, + ) => Promise; + getZoom: (viewRef: Int32) => Promise; + getVisibleBounds: (viewRef: Int32) => Promise; + queryRenderedFeaturesAtPoint: ( + viewRef: Int32, + atPoint: ReadonlyArray, + withFilter: ReadonlyArray, + withLayerIDs: ReadonlyArray, + ) => Promise; + queryRenderedFeaturesInRect: ( + viewRef: Int32, + withBBox: ReadonlyArray, + withFilter: ReadonlyArray, + withLayerIDs: ReadonlyArray, + ) => Promise; + setHandledMapChangedEvents: ( + viewRef: Int32, + events: ReadonlyArray, + ) => Promise; + clearData: (viewRef: Int32) => Promise; +} + +export default TurboModuleRegistry.get('MBXMapViewModule'); From 2ae88423353925aea2875d66caf4838f6cb9ae85 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 30 Aug 2023 14:10:40 +0200 Subject: [PATCH 14/33] Implement all methods --- ios/RCTMGL-v10/MBXMapView.h | 12 + ios/RCTMGL-v10/MBXMapView.swift | 104 ++++++++- ios/RCTMGL-v10/MBXMapViewComponentView.h | 12 + ios/RCTMGL-v10/MBXMapViewComponentView.mm | 60 ++++- ios/RCTMGL-v10/MBXMapViewManager.swift | 256 +++++++++++++++------- ios/RCTMGL-v10/MBXMapViewModule.mm | 77 +++++-- src/specs/NativeMapViewModule.ts | 27 ++- 7 files changed, 424 insertions(+), 124 deletions(-) diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h index f49b81653..0891e83c4 100644 --- a/ios/RCTMGL-v10/MBXMapView.h +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -30,6 +30,18 @@ - (void)setOnMapChange:(RCTBubblingEventBlock)callback; - (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve; +- (void)clearData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getCenter:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getCoordinateFromView:(CGPoint)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getPointInView:(NSArray*)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getVisibleBounds:(RCTPromiseResolveBlock)resolve; +- (void)getZoom:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)queryRenderedFeaturesAtPoint:(NSArray*)point withFilter:(NSArray* _Nullable)filter withLayerIDs:(NSArray* _Nullable)layerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)queryRenderedFeaturesInRect:(NSArray* _Nonnull)bbox withFilter:(NSArray* _Nullable)filter withLayerIDs:(NSArray* _Nullable)layerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)queryTerrainElevation:(NSArray* _Nonnull)coordinates resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)setHandledMapChangedEvents:(NSArray* _Nonnull)events resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)setSourceVisibility:(BOOL)visible sourceId:(NSString* _Nonnull)sourceId sourceLayerId:(NSString* _Nullable)sourceLayerId resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; @end diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift index ca071b1a4..7491498be 100644 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -98,9 +98,109 @@ open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { self.setReactOnMapChange(callback) } + + private func withMapboxMap( + name: String, + rejecter: @escaping RCTPromiseRejectBlock, + fn: @escaping (_: MapboxMap) -> Void) -> Void + { + guard let mapboxMap = self.mapboxMap else { + RCTMGLLogError("MapboxMap is not yet available"); + rejecter(name, "Map not loaded yet", nil) + return; + } + + fn(mapboxMap) + } + public func takeSnap(_ writeToDisk: Bool, resolve: RCTPromiseResolveBlock!) { - let uri = self.takeSnap(writeToDisk: writeToDisk) - resolve(["uri": uri.absoluteString]) + MBXMapViewManager.takeSnap(self, writeToDisk: writeToDisk, resolver: resolve) + } + + public func clearData(_ resolve: RCTPromiseResolveBlock!, reject: RCTPromiseRejectBlock!) { + MBXMapViewManager.clearData(self, resolver: resolve, rejecter: reject) + } + + public func getCenter(_ resolve: RCTPromiseResolveBlock!, reject: RCTPromiseRejectBlock!) { + withMapboxMap(name: "getCenter", rejecter: reject) { map in + MBXMapViewManager.getCenter(map, resolver: resolve) + } + } + + public func getCoordinateFromView(_ point: CGPoint, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + withMapboxMap(name: "getCoordinateFromView", rejecter: reject) { map in + MBXMapViewManager.getCoordinateFromView(map, atPoint: point, resolver: resolve) + } + } + + public func getPointInView(_ coordinate: [NSNumber], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + withMapboxMap(name: "getPointInView", rejecter: reject) { map in + MBXMapViewManager.getPointInView(map, atCoordinate: coordinate, resolver: resolve) + } + } + + public func getVisibleBounds(_ resolve: RCTPromiseResolveBlock!) { + MBXMapViewManager.getVisibleBounds(self, resolver: resolve) + } + + public func getZoom(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + withMapboxMap(name: "getZoom", rejecter: reject) { map in + MBXMapViewManager.getZoom(map, resolver: resolve) + } + } + + public func queryRenderedFeatures( + atPoint point: [NSNumber], + withFilter filter: [Any]?, + withLayerIDs layerIDs: [String]?, + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock) { + withMapboxMap(name: "queryRenderedFeaturesAtPoint", rejecter: reject) { map in + MBXMapViewManager.queryRenderedFeaturesAtPoint(map, atPoint: point, withFilter: filter, withLayerIDs: layerIDs, resolver: resolve, rejecter: reject) + } + } + + public func queryRenderedFeatures( + inRect bbox: [NSNumber], + withFilter filter: [Any]?, + withLayerIDs layerIDs: [String]?, + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock) { + MBXMapViewManager.queryRenderedFeaturesInRect(self, withBBox: bbox, withFilter: filter, withLayerIDs: layerIDs, resolver: resolve, rejecter: reject) + } + + public func queryTerrainElevation( + _ coordinates: [NSNumber], + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock + ) { + MBXMapViewManager.queryTerrainElevation(self, coordinates: coordinates, resolver: resolve, rejecter: reject) + } + + public func setHandledMapChangedEvents( + _ events: [String], + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock) { + MBXMapViewManager.setHandledMapChangedEvents(self, events: events, resolver: resolve, rejecter: reject) + } + + public func setSourceVisibility( + _ visible: Bool, + sourceId: String, + sourceLayerId: String?, + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock) { + MBXMapViewManager.setSourceVisibility(self, visible: visible, sourceId: sourceId, sourceLayerId: sourceLayerId, resolver: resolve, rejecter: reject) + } + + func querySourceFeatures( + _ reactTag: NSNumber, + withSourceId sourceId: String, + withFilter filter: [Any]?, + withSourceLayerIds sourceLayerIds: [String]?, + resolve: @escaping RCTPromiseResolveBlock, + reject: @escaping RCTPromiseRejectBlock) -> Void { + MBXMapViewManager.querySourceFeatures(self, withSourceId: sourceId, withFilter: filter, withSourceLayerIds: sourceLayerIds, resolver: resolve, rejecter: reject) } } diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.h b/ios/RCTMGL-v10/MBXMapViewComponentView.h index 92ef74e3a..de8e300ac 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.h +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.h @@ -12,6 +12,18 @@ NS_ASSUME_NONNULL_BEGIN - (void)dispatchCameraChangedEvent:(NSDictionary*)event; - (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve; +- (void)clearData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getCenter:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getCoordinateFromView:(CGPoint)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getPointInView:(NSArray*)coordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)getVisibleBounds:(RCTPromiseResolveBlock)resolve; +- (void)getZoom:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)queryRenderedFeaturesAtPoint:(NSArray*)point withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)queryRenderedFeaturesInRect:(NSArray*)bbox withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)queryTerrainElevation:(NSArray*)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)setHandledMapChangedEvents:(NSArray*)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)setSourceVisibility:(BOOL)visible sourceId:(NSString*)sourceId sourceLayerId:(NSString*)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; +- (void)querySourceFeatures:sourceId:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; @end diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index a1e23e76b..3b49c79cf 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -81,15 +81,6 @@ - (instancetype)initWithFrame:(CGRect)frame std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onMapChange({type, json}); } }]; - -// [_view setOnCameraChange:^(NSDictionary* event) { -// __typeof__(self) strongSelf = weakSelf; -// -// if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { -// const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; -// std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onCameraChanged({type, json}); -// } -// }]; self.contentView = _view; } @@ -152,10 +143,59 @@ - (NSDictionary*)convertLocalizeLabels:(const MBXMapViewLocalizeLabelsStruct*)la return result; } -- (void)takeSnap:(BOOL)writeToDisk resolve:(id)resolve { +- (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve { [_view takeSnap:writeToDisk resolve:resolve]; } +- (void)clearData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view clearData:resolve reject:reject]; +} + +- (void)getCenter:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view getCenter:resolve reject:reject]; +} + +- (void)getCoordinateFromView:(CGPoint)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view getCoordinateFromView:point resolve:resolve reject:reject]; +} + +- (void)getPointInView:(NSArray*)coordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view getPointInView:coordinate resolve:resolve reject:reject]; +} + +- (void)getVisibleBounds:(RCTPromiseResolveBlock)resolve { + [_view getVisibleBounds:resolve]; +} + +- (void)getZoom:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view getZoom:resolve reject:reject]; +} + +- (void)queryRenderedFeaturesAtPoint:(NSArray*)point withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view queryRenderedFeaturesAtPoint:point withFilter:filter withLayerIDs:layerIDs resolve:resolve reject:reject]; +} + +- (void)queryRenderedFeaturesInRect:(NSArray*)bbox withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view queryRenderedFeaturesInRect:bbox withFilter:filter withLayerIDs:layerIDs resolve:resolve reject:reject]; +} + +- (void)queryTerrainElevation:(NSArray*)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view queryTerrainElevation:coordinates resolve:resolve reject:reject]; +} + +- (void)setHandledMapChangedEvents:(NSArray*)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view setHandledMapChangedEvents:events resolve:resolve reject:reject]; +} + +- (void)setSourceVisibility:(BOOL)visible sourceId:(NSString*)sourceId sourceLayerId:(NSString*)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [_view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; +} + +- (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject { + [_view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; +} + + #pragma mark - RCTComponentViewProtocol + (ComponentDescriptorProvider)componentDescriptorProvider diff --git a/ios/RCTMGL-v10/MBXMapViewManager.swift b/ios/RCTMGL-v10/MBXMapViewManager.swift index 883a60038..651c452af 100644 --- a/ios/RCTMGL-v10/MBXMapViewManager.swift +++ b/ios/RCTMGL-v10/MBXMapViewManager.swift @@ -60,6 +60,13 @@ extension MBXMapViewManager { // MARK: - react methods extension MBXMapViewManager { + static func takeSnap(_ view: RCTMGLMapView, + writeToDisk: Bool, + resolver: @escaping RCTPromiseResolveBlock) { + let uri = view.takeSnap(writeToDisk: writeToDisk) + resolver(["uri": uri.absoluteString]) + } + @objc func takeSnap(_ reactTag: NSNumber, writeToDisk: Bool, @@ -67,11 +74,23 @@ extension MBXMapViewManager { rejecter: @escaping RCTPromiseRejectBlock ) -> Void { withMapView(reactTag, name:"takeSnap", rejecter: rejecter) { view in - let uri = view.takeSnap(writeToDisk: writeToDisk) - resolver(["uri": uri.absoluteString]) + MBXMapViewManager.takeSnap(view, writeToDisk: writeToDisk, resolver: resolver) } } + static func queryTerrainElevation(_ view: RCTMGLMapView, + coordinates: [NSNumber], + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock + ) -> Void { + let result = view.queryTerrainElevation(coordinates: coordinates) + if let result = result { + resolver(["data": NSNumber(value: result)]) + } else { + resolver(nil) + } + } + @objc func queryTerrainElevation(_ reactTag: NSNumber, coordinates: [NSNumber], @@ -79,14 +98,19 @@ extension MBXMapViewManager { rejecter: @escaping RCTPromiseRejectBlock ) -> Void { withMapView(reactTag, name:"queryTerrainElevation", rejecter: rejecter) { view in - let result = view.queryTerrainElevation(coordinates: coordinates) - if let result = result { - resolver(["data": NSNumber(value: result)]) - } else { - resolver(nil) - } + MBXMapViewManager.queryTerrainElevation(view, coordinates: coordinates, resolver: resolver, rejecter: rejecter) } } + + static func setSourceVisibility(_ view: RCTMGLMapView, + visible: Bool, + sourceId: String, + sourceLayerId: String?, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) -> Void { + view.setSourceVisibility(visible, sourceId: sourceId, sourceLayerId:sourceLayerId) + resolver(nil) + } @objc func setSourceVisibility(_ reactTag: NSNumber, @@ -96,22 +120,33 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { withMapView(reactTag, name:"setSourceVisibility", rejecter: rejecter) { view in - view.setSourceVisibility(visible, sourceId: sourceId, sourceLayerId:sourceLayerId) - resolver(nil) + MBXMapViewManager.setSourceVisibility(view, visible: visible, sourceId: sourceId, sourceLayerId: sourceLayerId, resolver: resolver, rejecter: rejecter) } } + static func getCenter(_ map: MapboxMap, resolver: @escaping RCTPromiseResolveBlock) { + resolver(["center": [ + map.cameraState.center.longitude, + map.cameraState.center.latitude + ]]) + } + @objc func getCenter(_ reactTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { withMapboxMap(reactTag, name:"getCenter", rejecter: rejecter) { mapboxMap in - resolver(["center": [ - mapboxMap.cameraState.center.longitude, - mapboxMap.cameraState.center.latitude - ]]) + MBXMapViewManager.getCenter(mapboxMap, resolver: resolver) } } + + static func getCoordinateFromView( + _ map: MapboxMap, + atPoint point: CGPoint, + resolver: @escaping RCTPromiseResolveBlock) { + let coordinates = map.coordinate(for: point) + resolver(["coordinateFromView": [coordinates.longitude, coordinates.latitude]]) + } @objc func getCoordinateFromView( @@ -120,10 +155,18 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { withMapboxMap(reactTag, name:"getCoordinateFromView", rejecter: rejecter) { mapboxMap in - let coordinates = mapboxMap.coordinate(for: point) - resolver(["coordinateFromView": [coordinates.longitude, coordinates.latitude]]) + MBXMapViewManager.getCoordinateFromView(mapboxMap, atPoint: point, resolver: resolver) } } + + static func getPointInView( + _ map: MapboxMap, + atCoordinate coordinate: [NSNumber], + resolver: @escaping RCTPromiseResolveBlock) { + let coordinate = CLLocationCoordinate2DMake(coordinate[1].doubleValue, coordinate[0].doubleValue) + let point = map.point(for: coordinate) + resolver(["pointInView": [(point.x), (point.y)]]) + } @objc func getPointInView( @@ -132,12 +175,21 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { withMapboxMap(reactTag, name:"getPointInView", rejecter: rejecter) { mapboxMap in - let coordinate = CLLocationCoordinate2DMake(coordinate[1].doubleValue, coordinate[0].doubleValue) - let point = mapboxMap.point(for: coordinate) - resolver(["pointInView": [(point.x), (point.y)]]) + MBXMapViewManager.getPointInView(mapboxMap, atCoordinate: coordinate, resolver: resolver) } } + static func setHandledMapChangedEvents( + _ view: RCTMGLMapView, + events: [String], + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) { + view.handleMapChangedEvents = Set(events.compactMap { + RCTMGLEvent.EventType(rawValue: $0) + }) + resolver(nil); + } + @objc func setHandledMapChangedEvents( _ reactTag: NSNumber, @@ -145,12 +197,15 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { withMapView(reactTag, name:"setHandledMapChangedEvents", rejecter: rejecter) { mapView in - mapView.handleMapChangedEvents = Set(events.compactMap { - RCTMGLEvent.EventType(rawValue: $0) - }) - resolver(nil); + MBXMapViewManager.setHandledMapChangedEvents(mapView, events: events, resolver: resolver, rejecter: rejecter) } } + + static func getZoom( + _ map: MapboxMap, + resolver: @escaping RCTPromiseResolveBlock) { + resolver(["zoom": map.cameraState.zoom]) + } @objc func getZoom( @@ -158,17 +213,23 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { withMapboxMap(reactTag, name:"getZoom", rejecter: rejecter) { mapboxMap in - resolver(["zoom": mapboxMap.cameraState.zoom]) + MBXMapViewManager.getZoom(mapboxMap, resolver: resolver) } } + static func getVisibleBounds( + _ view: RCTMGLMapView, + resolver: @escaping RCTPromiseResolveBlock) { + resolver(["visibleBounds": view.mapboxMap.coordinateBounds(for: view.bounds).toArray()]) + } + @objc func getVisibleBounds( _ reactTag: NSNumber, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { withMapView(reactTag, name:"getVisibleBounds", rejecter: rejecter) { mapView in - resolver(["visibleBounds": mapView.mapboxMap.coordinateBounds(for: mapView.bounds).toArray()]) + MBXMapViewManager.getVisibleBounds(mapView, resolver: resolver) } } } @@ -176,21 +237,19 @@ extension MBXMapViewManager { // MARK: - queryRenderedFeatures extension MBXMapViewManager { - @objc - func queryRenderedFeaturesAtPoint( - _ reactTag: NSNumber, - atPoint point: [NSNumber], - withFilter filter: [Any]?, - withLayerIDs layerIDs: [String]?, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapboxMap(reactTag, name:"queryRenderedFeaturesAtPoint", rejecter: rejecter) { mapboxMap in + static func queryRenderedFeaturesAtPoint( + _ map: MapboxMap, + atPoint point: [NSNumber], + withFilter filter: [Any]?, + withLayerIDs layerIDs: [String]?, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) -> Void { let point = CGPoint(x: CGFloat(point[0].floatValue), y: CGFloat(point[1].floatValue)) logged("queryRenderedFeaturesAtPoint.option", rejecter: rejecter) { let options = try RenderedQueryOptions(layerIds: (layerIDs ?? []).isEmpty ? nil : layerIDs, filter: filter?.asExpression()) - mapboxMap.queryRenderedFeatures(with: point, options: options) { result in + map.queryRenderedFeatures(with: point, options: options) { result in switch result { case .success(let features): resolver([ @@ -202,10 +261,51 @@ extension MBXMapViewManager { rejecter("queryRenderedFeaturesAtPoint","failed to query features", error) } } - } + } + } + + @objc + func queryRenderedFeaturesAtPoint( + _ reactTag: NSNumber, + atPoint point: [NSNumber], + withFilter filter: [Any]?, + withLayerIDs layerIDs: [String]?, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) -> Void { + withMapboxMap(reactTag, name:"queryRenderedFeaturesAtPoint", rejecter: rejecter) { mapboxMap in + MBXMapViewManager.queryRenderedFeaturesAtPoint(mapboxMap, atPoint: point, withFilter: filter, withLayerIDs: layerIDs, resolver: resolver, rejecter: rejecter) } } + static func queryRenderedFeaturesInRect( + _ map: RCTMGLMapView, + withBBox bbox: [NSNumber], + withFilter filter: [Any]?, + withLayerIDs layerIDs: [String]?, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) -> Void { + let top = bbox.isEmpty ? 0.0 : CGFloat(bbox[0].floatValue) + let right = bbox.isEmpty ? 0.0 : CGFloat(bbox[1].floatValue) + let bottom = bbox.isEmpty ? 0.0 : CGFloat(bbox[2].floatValue) + let left = bbox.isEmpty ? 0.0 : CGFloat(bbox[3].floatValue) + let rect = bbox.isEmpty ? CGRect(x: 0.0, y: 0.0, width: map.bounds.size.width, height: map.bounds.size.height) : CGRect(x: [left,right].min()!, y: [top,bottom].min()!, width: abs(right-left), height: abs(bottom-top)) + logged("queryRenderedFeaturesInRect.option", rejecter: rejecter) { + let options = try RenderedQueryOptions(layerIds: layerIDs?.isEmpty ?? true ? nil : layerIDs, filter: filter?.asExpression()) + map.mapboxMap.queryRenderedFeatures(with: rect, options: options) { result in + switch result { + case .success(let features): + resolver([ + "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in + logged("queryRenderedFeaturesInRect.queriedfeature.map") { try queriedFeature.feature.toJSON() } + }] + ]) + case .failure(let error): + rejecter("queryRenderedFeaturesInRect","failed to query features", error) + } + } + } + } + @objc func queryRenderedFeaturesInRect( _ reactTag: NSNumber, @@ -215,28 +315,34 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { withMapView(reactTag, name:"queryRenderedFeaturesInRect", rejecter: rejecter) { mapView in - let top = bbox.isEmpty ? 0.0 : CGFloat(bbox[0].floatValue) - let right = bbox.isEmpty ? 0.0 : CGFloat(bbox[1].floatValue) - let bottom = bbox.isEmpty ? 0.0 : CGFloat(bbox[2].floatValue) - let left = bbox.isEmpty ? 0.0 : CGFloat(bbox[3].floatValue) - let rect = bbox.isEmpty ? CGRect(x: 0.0, y: 0.0, width: mapView.bounds.size.width, height: mapView.bounds.size.height) : CGRect(x: [left,right].min()!, y: [top,bottom].min()!, width: abs(right-left), height: abs(bottom-top)) - logged("queryRenderedFeaturesInRect.option", rejecter: rejecter) { - let options = try RenderedQueryOptions(layerIds: layerIDs?.isEmpty ?? true ? nil : layerIDs, filter: filter?.asExpression()) - mapView.mapboxMap.queryRenderedFeatures(with: rect, options: options) { result in - switch result { - case .success(let features): - resolver([ - "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in - logged("queryRenderedFeaturesInRect.queriedfeature.map") { try queriedFeature.feature.toJSON() } - }] - ]) - case .failure(let error): - rejecter("queryRenderedFeaturesInRect","failed to query features", error) - } + MBXMapViewManager.queryRenderedFeaturesInRect(mapView, withBBox: bbox, withFilter: filter, withLayerIDs: layerIDs, resolver: resolver, rejecter: rejecter) + } + } + + static func querySourceFeatures( + _ map: RCTMGLMapView, + withSourceId sourceId: String, + withFilter filter: [Any]?, + withSourceLayerIds sourceLayerIds: [String]?, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) -> Void { + let sourceLayerIds = sourceLayerIds?.isEmpty ?? true ? nil : sourceLayerIds + logged("querySourceFeatures.option", rejecter: rejecter) { + let options = SourceQueryOptions(sourceLayerIds: sourceLayerIds, filter: filter ?? Exp(arguments: [])) + map.mapboxMap.querySourceFeatures(for: sourceId, options: options) { result in + switch result { + case .success(let features): + resolver([ + "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in + logged("querySourceFeatures.queriedfeature.map") { try queriedFeature.feature.toJSON() } + }] as [String : Any] + ]) + case .failure(let error): + rejecter("querySourceFeatures", "failed to query source features: \(error.localizedDescription)", error) } } } - } + } @objc func querySourceFeatures( @@ -247,25 +353,25 @@ extension MBXMapViewManager { resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { withMapView(reactTag, name:"querySourceFeatures", rejecter: rejecter) { mapView in - let sourceLayerIds = sourceLayerIds?.isEmpty ?? true ? nil : sourceLayerIds - logged("querySourceFeatures.option", rejecter: rejecter) { - let options = SourceQueryOptions(sourceLayerIds: sourceLayerIds, filter: filter ?? Exp(arguments: [])) - mapView.mapboxMap.querySourceFeatures(for: sourceId, options: options) { result in - switch result { - case .success(let features): - resolver([ - "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in - logged("querySourceFeatures.queriedfeature.map") { try queriedFeature.feature.toJSON() } - }] as [String : Any] - ]) - case .failure(let error): - rejecter("querySourceFeatures", "failed to query source features: \(error.localizedDescription)", error) - } - } - } + MBXMapViewManager.querySourceFeatures(mapView, withSourceId: sourceId, withFilter: filter, withSourceLayerIds: sourceLayerIds, resolver: resolver, rejecter: rejecter) } } + + static func clearData( + _ view: RCTMGLMapView, + resolver:@escaping RCTPromiseResolveBlock, + rejecter:@escaping RCTPromiseRejectBlock + ) { + view.mapboxMap.clearData { error in + if let error = error { + rejecter("clearData","failed to clearData: \(error.localizedDescription)", error) + } else { + resolver(nil) + } + } + } + @objc func clearData( _ reactTag: NSNumber, @@ -273,13 +379,7 @@ extension MBXMapViewManager { rejecter: @escaping RCTPromiseRejectBlock ) { withMapView(reactTag, name:"clearDataPath", rejecter: rejecter) { mapView in - mapView.mapboxMap.clearData { error in - if let error = error { - rejecter("clearData","failed to clearData: \(error.localizedDescription)", error) - } else { - resolver(nil) - } - } + MBXMapViewManager.clearData(mapView, resolver: resolver, rejecter: rejecter) } } } diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index e232ed57c..7cecca5a9 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -28,63 +28,94 @@ - (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(MBXMapViewCompon - (void)takeSnap:(NSNumber*)viewRef writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view){ + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view takeSnap:writeToDisk resolve:resolve]; } reject:reject]; } -- (void)clearData:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"clearData", @"not implemented yet", nil); +- (void)clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view clearData:resolve reject:reject]; + } reject:reject]; } -- (void)getCenter:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"getCenter", @"not implemented yet", nil); +- (void)getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view getCenter:resolve reject:reject]; + } reject:reject]; } -- (void)getCoordinateFromView:(double)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"getCoordinateFromView", @"not implemented yet", nil); +- (void)getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + NSNumber* a = [atPoint objectAtIndex:0]; + NSNumber* b = [atPoint objectAtIndex:1]; + + [view getCoordinateFromView:CGPointMake(a.floatValue, b.floatValue) resolve:resolve reject:reject]; + } reject:reject]; } -- (void)getPointInView:(double)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"getPointInView", @"not implemented yet", nil); +- (void)getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view getPointInView:atCoordinate resolve:resolve reject:reject]; + } reject:reject]; } -- (void)getVisibleBounds:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"getVisibleBounds", @"not implemented yet", nil); +- (void)getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view getVisibleBounds:resolve]; + } reject:reject]; } -- (void)getZoom:(double)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"getZoom", @"not implemented yet", nil); +- (void)getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view getZoom:resolve reject:reject]; + } reject:reject]; } -- (void)queryRenderedFeaturesAtPoint:(double)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"queryRenderedFeaturesAtPoint", @"not implemented yet", nil); +- (void)queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view queryRenderedFeaturesAtPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; + } reject:reject]; } -- (void)queryRenderedFeaturesInRect:(double)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"queryRenderedFeaturesInRect", @"not implemented yet", nil); +- (void)queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view queryRenderedFeaturesInRect:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; + } reject:reject]; } -- (void)queryTerrainElevation:(double)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"queryTerrainElevation", @"not implemented yet", nil); +- (void)queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view queryTerrainElevation:coordinates resolve:resolve reject:reject]; + } reject:reject]; } -- (void)setHandledMapChangedEvents:(double)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"setHandledMapChangedEvents", @"not implemented yet", nil); +- (void)setHandledMapChangedEvents:(NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view setHandledMapChangedEvents:events resolve:resolve reject:reject]; + } reject:reject]; } -- (void)setSourceVisibility:(double)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - reject(@"setSourceVisibility", @"not implemented yet", nil); +- (void)setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; + } reject:reject]; +} + +- (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject { + [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; + } reject:reject]; } diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index a30227237..ab2965a20 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -6,43 +6,48 @@ import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { takeSnap: (viewRef: Int32 | null, writeToDisk: boolean) => Promise; queryTerrainElevation: ( - viewRef: Int32, + viewRef: Int32 | null, coordinates: ReadonlyArray, ) => Promise; setSourceVisibility: ( - viewRef: Int32, + viewRef: Int32 | null, visible: boolean, sourceId: string, sourceLayerId: string, ) => Promise; - getCenter: (viewRef: Int32) => Promise; + getCenter: (viewRef: Int32 | null) => Promise; getCoordinateFromView: ( - viewRef: Int32, + viewRef: Int32 | null, atPoint: ReadonlyArray, ) => Promise; getPointInView: ( - viewRef: Int32, + viewRef: Int32 | null, atCoordinate: ReadonlyArray, ) => Promise; - getZoom: (viewRef: Int32) => Promise; - getVisibleBounds: (viewRef: Int32) => Promise; + getZoom: (viewRef: Int32 | null) => Promise; + getVisibleBounds: (viewRef: Int32 | null) => Promise; queryRenderedFeaturesAtPoint: ( - viewRef: Int32, + viewRef: Int32 | null, atPoint: ReadonlyArray, withFilter: ReadonlyArray, withLayerIDs: ReadonlyArray, ) => Promise; queryRenderedFeaturesInRect: ( - viewRef: Int32, + viewRef: Int32 | null, withBBox: ReadonlyArray, withFilter: ReadonlyArray, withLayerIDs: ReadonlyArray, ) => Promise; setHandledMapChangedEvents: ( - viewRef: Int32, + viewRef: Int32 | null, events: ReadonlyArray, ) => Promise; - clearData: (viewRef: Int32) => Promise; + clearData: (viewRef: Int32 | null) => Promise; + querySourceFeatures: ( + viewRef: Int32 | null, + withFilter: ReadonlyArray, + withSourceLayerIDs: ReadonlyArray, + ) => Promise; } export default TurboModuleRegistry.get('MBXMapViewModule'); From d07804f4241fba7637009266039257e517cda52e Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Wed, 30 Aug 2023 14:58:51 +0200 Subject: [PATCH 15/33] I've figured it out :) --- src/utils/index.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/utils/index.ts b/src/utils/index.ts index 10f9e0e15..8d0f10ada 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -71,10 +71,6 @@ export function runNativeCommand( nativeRef: any, args: NativeArg[], ): Promise { - throw new Error( - `TODO: figure out what this method actually does and do it in a way that doesn't instantly crash on the new arch`, - ); - const handle = findNodeHandle(nativeRef); if (!handle) { throw new Error(`Could not find handle for native ref ${module}.${name}`); From 329af5eb04d7716cff9d2614cef749799693d927 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Thu, 31 Aug 2023 17:10:23 +0200 Subject: [PATCH 16/33] Begin android module --- android/build.gradle | 5 +- .../com/mapbox/rctmgl/RCTMGLPackage.java | 121 +++++++++-- .../components/mapview/NativeMapViewModule.kt | 192 ++++++++++++++++++ .../components/mapview/RCTMGLMapView.kt | 6 + .../mapview/RCTMGLMapViewManager.kt | 4 + 5 files changed, 312 insertions(+), 16 deletions(-) create mode 100644 android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt diff --git a/android/build.gradle b/android/build.gradle index fffb0bd17..3c0a15d45 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -35,10 +35,6 @@ buildscript { if (isNewArchitectureEnabled()) { apply plugin: 'com.facebook.react' - - react { - codegenJavaPackageName = "com.mapbox.rctmgl" - } } apply plugin: 'com.android.library' @@ -91,6 +87,7 @@ android { targetSdkVersion safeExtGet('targetSdkVersion', 26) versionCode 1 versionName "1.0" + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() } compileOptions { diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java b/android/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java index cc3418978..5648c6e87 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java +++ b/android/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java @@ -1,14 +1,21 @@ package com.mapbox.rctmgl; +import androidx.annotation.Nullable; + import com.facebook.react.ReactPackage; +import com.facebook.react.TurboReactPackage; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.uimanager.ViewManager; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.mapbox.rctmgl.components.camera.RCTMGLCameraManager; @@ -18,6 +25,7 @@ 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.NativeMapViewModule; import com.mapbox.rctmgl.components.mapview.RCTMGLMapViewManager; import com.mapbox.rctmgl.components.mapview.RCTMGLAndroidTextureMapViewManager; import com.mapbox.rctmgl.components.styles.atmosphere.RCTMGLAtmosphereManager; @@ -49,20 +57,27 @@ import com.mapbox.rctmgl.modules.RCTMGLModule; -public class RCTMGLPackage implements ReactPackage { +public class RCTMGLPackage extends TurboReactPackage { + @Nullable @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; + public NativeModule getModule(String s, ReactApplicationContext reactApplicationContext) { + switch (s) { + case RCTMGLModule.REACT_CLASS: + return new RCTMGLModule(reactApplicationContext); + case RCTMGLLocationModule.REACT_CLASS: + return new RCTMGLLocationModule(reactApplicationContext); + case RCTMGLOfflineModule.REACT_CLASS: + return new RCTMGLOfflineModule(reactApplicationContext); + case RCTMGLSnapshotModule.REACT_CLASS: + return new RCTMGLSnapshotModule(reactApplicationContext); + case RCTMGLLogging.REACT_CLASS: + return new RCTMGLLogging(reactApplicationContext); + case NativeMapViewModule.NAME: + return new NativeMapViewModule(reactApplicationContext); + } + + return null; } @Deprecated @@ -115,4 +130,86 @@ public List createViewManagers(ReactApplicationContext reactApplica return managers; } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + + moduleInfos.put( + RCTMGLModule.REACT_CLASS, + new ReactModuleInfo( + RCTMGLModule.REACT_CLASS, + RCTMGLModule.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + false // isTurboModule + )); + + moduleInfos.put( + RCTMGLLocationModule.REACT_CLASS, + new ReactModuleInfo( + RCTMGLLocationModule.REACT_CLASS, + RCTMGLLocationModule.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + false // isTurboModule + )); + + moduleInfos.put( + RCTMGLOfflineModule.REACT_CLASS, + new ReactModuleInfo( + RCTMGLOfflineModule.REACT_CLASS, + RCTMGLOfflineModule.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + false // isTurboModule + )); + + moduleInfos.put( + RCTMGLSnapshotModule.REACT_CLASS, + new ReactModuleInfo( + RCTMGLSnapshotModule.REACT_CLASS, + RCTMGLSnapshotModule.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + false // isTurboModule + )); + + moduleInfos.put( + RCTMGLLogging.REACT_CLASS, + new ReactModuleInfo( + RCTMGLLogging.REACT_CLASS, + RCTMGLLogging.REACT_CLASS, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants + false, // isCxxModule + false // isTurboModule + )); + + moduleInfos.put( + NativeMapViewModule.NAME, + new ReactModuleInfo( + NativeMapViewModule.NAME, + NativeMapViewModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + )); + + return moduleInfos; + }; + } } diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt new file mode 100644 index 000000000..8c1a10723 --- /dev/null +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -0,0 +1,192 @@ +package com.mapbox.rctmgl.components.mapview + +import com.facebook.react.ReactApplication +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableArray +import com.facebook.react.fabric.FabricUIManager +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.common.UIManagerType +import com.mapbox.rctmgl.NativeMapViewModuleSpec +import com.mapbox.rctmgl.utils.ConvertUtils +import com.mapbox.rctmgl.utils.ExpressionParser +import com.mapbox.rctmgl.utils.extensions.toCoordinate +import com.mapbox.rctmgl.utils.extensions.toScreenCoordinate + +class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModuleSpec(context) { + private fun withMapViewManagerOnUIThread(viewRef: Double?, fn: (RCTMGLMapView) -> Unit) { + if (viewRef == null) { + return + } + + // returns null when called too early :/, maybe fixable +// val manager = UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) as FabricUIManager +// val view = manager.resolveView(viewRef.toInt()) + + reactApplicationContext.runOnUiQueueThread { + val viewManagers = + (reactApplicationContext.applicationContext as ReactApplication) + .reactNativeHost + .reactInstanceManager + .getOrCreateViewManagers(reactApplicationContext) + .filterIsInstance() + + for (viewManager in viewManagers) { + val view = viewManager.getByReactTag(viewRef.toInt()) ?: continue + + fn(view) + break + } + } + } + + override fun takeSnap(viewRef: Double?, writeToDisk: Boolean, promise: Promise) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.takeSnap("", writeToDisk) + + promise.resolve(null) + } + } + + override fun queryTerrainElevation( + viewRef: Double?, + coordinates: ReadableArray, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.queryTerrainElevation("", coordinates.getDouble(0), coordinates.getDouble(1)) + + promise.resolve(null) + } + } + + override fun setSourceVisibility( + viewRef: Double?, + visible: Boolean, + sourceId: String, + sourceLayerId: String?, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + it.setSourceVisibility(visible, sourceId, sourceLayerId) + + promise.resolve(null) + } + } + + override fun getCenter(viewRef: Double?, promise: Promise) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.getCenter("") + + promise.resolve(null) + } + } + + override fun getCoordinateFromView( + viewRef: Double?, + atPoint: ReadableArray, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.getCoordinateFromView("", atPoint.toScreenCoordinate()) + + promise.resolve(null) + } + } + + override fun getPointInView(viewRef: Double?, atCoordinate: ReadableArray, promise: Promise) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.getPointInView("", atCoordinate.toCoordinate()) + + promise.resolve(null) + } + } + + override fun getZoom(viewRef: Double?, promise: Promise) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.getZoom("") + + promise.resolve(null) + } + } + + override fun getVisibleBounds(viewRef: Double?, promise: Promise) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.getVisibleBounds("") + + promise.resolve(null) + } + } + + override fun queryRenderedFeaturesAtPoint( + viewRef: Double?, + atPoint: ReadableArray, + withFilter: ReadableArray, + withLayerIDs: ReadableArray, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + val layerIds = ConvertUtils.toStringList(withLayerIDs) + it.queryRenderedFeaturesAtPoint( + "", + ConvertUtils.toPointF(atPoint), + ExpressionParser.from(withFilter), + if (layerIds.size == 0) null else layerIds + ) + + promise.resolve(null) + } + } + + override fun queryRenderedFeaturesInRect( + viewRef: Double?, + withBBox: ReadableArray, + withFilter: ReadableArray, + withLayerIDs: ReadableArray, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + val layerIds = ConvertUtils.toStringList(withLayerIDs) + it.queryRenderedFeaturesInRect( + "", + ConvertUtils.toRectF(withBBox), + ExpressionParser.from(withFilter), + if (layerIds.size == 0) null else layerIds + ) + + promise.resolve(null) + } + } + + override fun setHandledMapChangedEvents( + viewRef: Double?, + events: ReadableArray, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + it.setHandledMapChangedEvents(events?.asArrayString() ?: emptyArray()) + promise.resolve(null) + } + } + + override fun clearData(viewRef: Double?, promise: Promise) { + withMapViewManagerOnUIThread(viewRef) { + // TODO: callbackID + it.clearData("") + promise.resolve(null) + } + } + + companion object { + const val NAME = "MBXMapViewModule" + } +} \ No newline at end of file diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt index e5f63e2a1..ecfbef1e7 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt @@ -208,6 +208,12 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV return mapView.getMapboxMap() } + override fun setId(id: Int) { + super.setId(id) + + mManager.setViewForReactTag(id, this) + } + val pointAnnotationManager: PointAnnotationManager? get() { if (mPointAnnotationManager == null) { diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt index 27cbdb318..8c440e3ff 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt @@ -118,6 +118,10 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : return mViews[reactTag] } + fun setViewForReactTag(reactTag: Int, mapView: RCTMGLMapView) { + mViews[reactTag] = mapView + } + // region React Props @ReactProp(name = "projection") override fun setProjection(mapView: RCTMGLMapView, projection: String?) { From d02bdb1a5c03100650e89d17a67e45d6dace123c Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 10:31:54 +0200 Subject: [PATCH 17/33] Make android commands work --- .../components/mapview/NativeMapViewModule.kt | 70 +++++++++++-------- ios/RCTMGL-v10/MBXMapViewModule.mm | 24 +++---- src/components/MapView.tsx | 15 ++++ src/components/NativeBridgeComponent.tsx | 5 ++ src/specs/NativeMapViewModule.ts | 22 ++++-- src/utils/index.ts | 16 +++++ 6 files changed, 105 insertions(+), 47 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index 8c1a10723..962a44216 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -4,9 +4,6 @@ import com.facebook.react.ReactApplication import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray -import com.facebook.react.fabric.FabricUIManager -import com.facebook.react.uimanager.UIManagerHelper -import com.facebook.react.uimanager.common.UIManagerType import com.mapbox.rctmgl.NativeMapViewModuleSpec import com.mapbox.rctmgl.utils.ConvertUtils import com.mapbox.rctmgl.utils.ExpressionParser @@ -40,10 +37,9 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun takeSnap(viewRef: Double?, writeToDisk: Boolean, promise: Promise) { + override fun takeSnap(viewRef: Double?, command: String, writeToDisk: Boolean, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.takeSnap("", writeToDisk) + it.takeSnap(command, writeToDisk) promise.resolve(null) } @@ -51,12 +47,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun queryTerrainElevation( viewRef: Double?, + command: String, coordinates: ReadableArray, promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.queryTerrainElevation("", coordinates.getDouble(0), coordinates.getDouble(1)) + it.queryTerrainElevation(command, coordinates.getDouble(0), coordinates.getDouble(1)) promise.resolve(null) } @@ -64,6 +60,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun setSourceVisibility( viewRef: Double?, + command: String, visible: Boolean, sourceId: String, sourceLayerId: String?, @@ -76,10 +73,9 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun getCenter(viewRef: Double?, promise: Promise) { + override fun getCenter(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.getCenter("") + it.getCenter(command) promise.resolve(null) } @@ -87,39 +83,36 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun getCoordinateFromView( viewRef: Double?, + command: String, atPoint: ReadableArray, promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.getCoordinateFromView("", atPoint.toScreenCoordinate()) + it.getCoordinateFromView(command, atPoint.toScreenCoordinate()) promise.resolve(null) } } - override fun getPointInView(viewRef: Double?, atCoordinate: ReadableArray, promise: Promise) { + override fun getPointInView(viewRef: Double?, command: String, atCoordinate: ReadableArray, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.getPointInView("", atCoordinate.toCoordinate()) + it.getPointInView(command, atCoordinate.toCoordinate()) promise.resolve(null) } } - override fun getZoom(viewRef: Double?, promise: Promise) { + override fun getZoom(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.getZoom("") + it.getZoom(command) promise.resolve(null) } } - override fun getVisibleBounds(viewRef: Double?, promise: Promise) { + override fun getVisibleBounds(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.getVisibleBounds("") + it.getVisibleBounds(command) promise.resolve(null) } @@ -127,16 +120,16 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun queryRenderedFeaturesAtPoint( viewRef: Double?, + command: String, atPoint: ReadableArray, withFilter: ReadableArray, withLayerIDs: ReadableArray, promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID val layerIds = ConvertUtils.toStringList(withLayerIDs) it.queryRenderedFeaturesAtPoint( - "", + command, ConvertUtils.toPointF(atPoint), ExpressionParser.from(withFilter), if (layerIds.size == 0) null else layerIds @@ -148,16 +141,16 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun queryRenderedFeaturesInRect( viewRef: Double?, + command: String, withBBox: ReadableArray, withFilter: ReadableArray, withLayerIDs: ReadableArray, promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID val layerIds = ConvertUtils.toStringList(withLayerIDs) it.queryRenderedFeaturesInRect( - "", + command, ConvertUtils.toRectF(withBBox), ExpressionParser.from(withFilter), if (layerIds.size == 0) null else layerIds @@ -169,19 +162,36 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun setHandledMapChangedEvents( viewRef: Double?, + command: String, events: ReadableArray, promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - it.setHandledMapChangedEvents(events?.asArrayString() ?: emptyArray()) + it.setHandledMapChangedEvents(events.asArrayString() ?: emptyArray()) promise.resolve(null) } } - override fun clearData(viewRef: Double?, promise: Promise) { + override fun clearData(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - // TODO: callbackID - it.clearData("") + it.clearData(command) + promise.resolve(null) + } + } + + override fun querySourceFeatures( + viewRef: Double?, + command: String, + withFilter: ReadableArray, + withSourceLayerIDs: ReadableArray, + promise: Promise + ) { + withMapViewManagerOnUIThread(viewRef) { + it.querySourceFeatures( + command, + ExpressionParser.from(withFilter), + if (withSourceLayerIDs.size == 0) null else withSourceLayerIDs + ) promise.resolve(null) } } diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index 7cecca5a9..3eb452f4d 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -26,28 +26,28 @@ - (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(MBXMapViewCompon } -- (void)takeSnap:(NSNumber*)viewRef writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +- (void)takeSnap:(NSNumber*)viewRef command:(NSString *)command writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view takeSnap:writeToDisk resolve:resolve]; } reject:reject]; } -- (void)clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)clearData:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view clearData:resolve reject:reject]; } reject:reject]; } -- (void)getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getCenter:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getCenter:resolve reject:reject]; } reject:reject]; } -- (void)getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getCoordinateFromView:(NSNumber*)viewRef command:(NSString *)command atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { NSNumber* a = [atPoint objectAtIndex:0]; NSNumber* b = [atPoint objectAtIndex:1]; @@ -57,56 +57,56 @@ - (void)getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint reso } -- (void)getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getPointInView:(NSNumber*)viewRef command:(NSString *)command atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getPointInView:atCoordinate resolve:resolve reject:reject]; } reject:reject]; } -- (void)getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getVisibleBounds:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getVisibleBounds:resolve]; } reject:reject]; } -- (void)getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getZoom:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getZoom:resolve reject:reject]; } reject:reject]; } -- (void)queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)queryRenderedFeaturesAtPoint:(NSNumber*)viewRef command:(NSString *)command atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view queryRenderedFeaturesAtPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; } reject:reject]; } -- (void)queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)queryRenderedFeaturesInRect:(NSNumber*)viewRef command:(NSString *)command withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view queryRenderedFeaturesInRect:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; } reject:reject]; } -- (void)queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)queryTerrainElevation:(NSNumber*)viewRef command:(NSString *)command coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view queryTerrainElevation:coordinates resolve:resolve reject:reject]; } reject:reject]; } -- (void)setHandledMapChangedEvents:(NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)setHandledMapChangedEvents:(NSNumber*)viewRef command:(NSString *)command events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view setHandledMapChangedEvents:events resolve:resolve reject:reject]; } reject:reject]; } -- (void)setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)setSourceVisibility:(NSNumber*)viewRef command:(NSString *)command visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; } reject:reject]; diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index be8f03c3f..e444ba08d 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -20,6 +20,7 @@ import { isAndroid, type NativeArg, type OrnamentPositonProp, + getCommandName, } from '../utils'; import { getFilter } from '../utils/filterUtils'; import Logger from '../utils/Logger'; @@ -867,10 +868,24 @@ class MapView extends NativeBridgeComponent( const handle = findNodeHandle(nativeRef as any); + if (isAndroid()) { + return new Promise((resolve, reject) => { + const callbackID = `${methodName}_${this._nextCallbackIncrement()}`; + this._addAddAndroidCallback(callbackID, resolve, reject); + + NativeMapViewModule[methodName]?.( + handle, + callbackID, + ...(args ?? []), + ); + }); + } + // @ts-expect-error TS says that string cannot be used to index NativeMapViewModule. // It can, it's just not pretty. return NativeMapViewModule[methodName]?.( handle, + '', ...(args ?? []), ) as Promise; } else { diff --git a/src/components/NativeBridgeComponent.tsx b/src/components/NativeBridgeComponent.tsx index 3d2e7cbf4..a4ec70e15 100644 --- a/src/components/NativeBridgeComponent.tsx +++ b/src/components/NativeBridgeComponent.tsx @@ -110,6 +110,11 @@ const NativeBridgeComponent = < args, ); } + + _nextCallbackIncrement() { + callbackIncrement += 1; + return callbackIncrement; + } }; export default NativeBridgeComponent; diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index ab2965a20..2ce47c4df 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -4,47 +4,59 @@ import { Int32 } from 'react-native/Libraries/Types/CodegenTypes'; import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { - takeSnap: (viewRef: Int32 | null, writeToDisk: boolean) => Promise; + takeSnap: ( + viewRef: Int32 | null, + command: string, + writeToDisk: boolean, + ) => Promise; queryTerrainElevation: ( viewRef: Int32 | null, + command: string, coordinates: ReadonlyArray, ) => Promise; setSourceVisibility: ( viewRef: Int32 | null, + command: string, visible: boolean, sourceId: string, sourceLayerId: string, ) => Promise; - getCenter: (viewRef: Int32 | null) => Promise; + getCenter: (viewRef: Int32 | null, command: string) => Promise; getCoordinateFromView: ( viewRef: Int32 | null, + command: string, atPoint: ReadonlyArray, ) => Promise; getPointInView: ( viewRef: Int32 | null, + command: string, atCoordinate: ReadonlyArray, ) => Promise; - getZoom: (viewRef: Int32 | null) => Promise; - getVisibleBounds: (viewRef: Int32 | null) => Promise; + getZoom: (viewRef: Int32 | null, command: string) => Promise; + getVisibleBounds: (viewRef: Int32 | null, command: string) => Promise; queryRenderedFeaturesAtPoint: ( viewRef: Int32 | null, + command: string, atPoint: ReadonlyArray, withFilter: ReadonlyArray, withLayerIDs: ReadonlyArray, ) => Promise; queryRenderedFeaturesInRect: ( viewRef: Int32 | null, + command: string, withBBox: ReadonlyArray, withFilter: ReadonlyArray, withLayerIDs: ReadonlyArray, ) => Promise; setHandledMapChangedEvents: ( viewRef: Int32 | null, + command: string, events: ReadonlyArray, ) => Promise; - clearData: (viewRef: Int32 | null) => Promise; + clearData: (viewRef: Int32 | null, command: string) => Promise; querySourceFeatures: ( viewRef: Int32 | null, + command: string, withFilter: ReadonlyArray, withSourceLayerIDs: ReadonlyArray, ) => Promise; diff --git a/src/utils/index.ts b/src/utils/index.ts index 8d0f10ada..37dc15f44 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -99,6 +99,22 @@ export function runNativeCommand( return managerInstance[name](handle, ...args); } +export function getCommandName(module: string, name: string): string { + if (!isAndroid()) { + return ''; // unused on iOS + } + + const managerInstance = getAndroidManagerInstance(module); + + if (!managerInstance) { + throw new Error(`Could not find ${module}`); + } + + const { Commands } = managerInstance; + + return Commands._useCommandName ? name : Commands[name]; +} + export function cloneReactChildrenWithProps( children: Parameters[0], propsToAdd: { [key: string]: string } = {}, From 1bae7b1e658ada7a68225f8b852f0f0111f5b58c Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 10:56:46 +0200 Subject: [PATCH 18/33] Update Android module to resolve promises with data --- .../components/mapview/NativeMapViewModule.kt | 105 ++++++++++++------ .../components/mapview/RCTMGLMapView.kt | 78 ++++++------- src/components/MapView.tsx | 13 --- 3 files changed, 111 insertions(+), 85 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index 962a44216..c6c03ad5d 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -4,6 +4,10 @@ import com.facebook.react.ReactApplication import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.WritableNativeMap +import com.facebook.react.fabric.FabricUIManager +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.common.UIManagerType import com.mapbox.rctmgl.NativeMapViewModuleSpec import com.mapbox.rctmgl.utils.ConvertUtils import com.mapbox.rctmgl.utils.ExpressionParser @@ -39,9 +43,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun takeSnap(viewRef: Double?, command: String, writeToDisk: Boolean, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - it.takeSnap(command, writeToDisk) - - promise.resolve(null) + it.takeSnap(writeToDisk) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -52,9 +59,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - it.queryTerrainElevation(command, coordinates.getDouble(0), coordinates.getDouble(1)) - - promise.resolve(null) + it.queryTerrainElevation(coordinates.getDouble(0), coordinates.getDouble(1)) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -75,9 +85,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun getCenter(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - it.getCenter(command) - - promise.resolve(null) + it.getCenter { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -88,33 +101,45 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - it.getCoordinateFromView(command, atPoint.toScreenCoordinate()) - - promise.resolve(null) + it.getCoordinateFromView(atPoint.toScreenCoordinate()) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } override fun getPointInView(viewRef: Double?, command: String, atCoordinate: ReadableArray, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - it.getPointInView(command, atCoordinate.toCoordinate()) - - promise.resolve(null) + it.getPointInView(atCoordinate.toCoordinate()) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } override fun getZoom(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - it.getZoom(command) - - promise.resolve(null) + it.getZoom { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } override fun getVisibleBounds(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - it.getVisibleBounds(command) - - promise.resolve(null) + it.getVisibleBounds { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -128,14 +153,17 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul ) { withMapViewManagerOnUIThread(viewRef) { val layerIds = ConvertUtils.toStringList(withLayerIDs) + it.queryRenderedFeaturesAtPoint( - command, ConvertUtils.toPointF(atPoint), ExpressionParser.from(withFilter), if (layerIds.size == 0) null else layerIds - ) - - promise.resolve(null) + ) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -149,14 +177,17 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul ) { withMapViewManagerOnUIThread(viewRef) { val layerIds = ConvertUtils.toStringList(withLayerIDs) + it.queryRenderedFeaturesInRect( - command, ConvertUtils.toRectF(withBBox), ExpressionParser.from(withFilter), if (layerIds.size == 0) null else layerIds - ) - - promise.resolve(null) + ) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -174,8 +205,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun clearData(viewRef: Double?, command: String, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { - it.clearData(command) - promise.resolve(null) + it.clearData { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } @@ -191,8 +226,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul command, ExpressionParser.from(withFilter), if (withSourceLayerIDs.size == 0) null else withSourceLayerIDs - ) - promise.resolve(null) + ) { fillData -> + with(WritableNativeMap()) { + fillData(this) + promise.resolve(this) + } + } } } diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt index ecfbef1e7..bb18e3a89 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt @@ -224,9 +224,9 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV mPointAnnotationManager = mapView.annotations.createPointAnnotationManager(AnnotationConfig(layerId = "rctmgl-mapview-annotations")) mPointAnnotationManager?.addClickListener(OnPointAnnotationClickListener { pointAnnotation -> - onMarkerClick(pointAnnotation) - false - } + onMarkerClick(pointAnnotation) + false + } ) mPointAnnotationManager?.addDragListener(object : OnPointAnnotationDragListener { override fun onAnnotationDragStarted(_annotation: Annotation<*>) { @@ -242,7 +242,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV reactAnnotation?.let { it.onDragStart() } } - override fun onAnnotationDrag(_annotation: Annotation<*>) { + override fun onAnnotationDrag(_annotation: Annotation<*>) { var reactAnnotation: RCTMGLPointAnnotation? = null for (key in mPointAnnotations.keys) { val annotation = mPointAnnotations[key] @@ -284,13 +284,13 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV } private fun setupEvents() { - mMap?.addOnRenderFrameFinishedListener( - object: OnRenderFrameFinishedListener { - override fun onRenderFrameFinished(eventData: RenderFrameFinishedEventData) { - handleMapChangedEvent(EventTypes.DID_FINISH_RENDERING_FRAME_FULLY) - } - } - ) + mMap?.addOnRenderFrameFinishedListener( + object: OnRenderFrameFinishedListener { + override fun onRenderFrameFinished(eventData: RenderFrameFinishedEventData) { + handleMapChangedEvent(EventTypes.DID_FINISH_RENDERING_FRAME_FULLY) + } + } + ) } private fun onMapReady(map: MapboxMap) { @@ -377,11 +377,11 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV Logger.e(LOG_TAG, String.format("Map load failed: %s", event.data.toString())) val errorMessage = event.getMapLoadingErrorEventData().message val event = MapChangeEvent(this, EventTypes.MAP_LOADING_ERROR, writableMapOf( - "error" to errorMessage + "error" to errorMessage )) mManager.handleEvent(event) - }, Arrays.asList(MapEvents.MAP_LOADING_ERROR)) + }, Arrays.asList(MapEvents.MAP_LOADING_ERROR)) } fun mapGestureBegin(type:MapGestureType, gesture: T) { @@ -496,7 +496,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV fun sendRegionChangeEvent(isAnimated: Boolean) { val didChangeEvent = MapChangeEvent(this, EventTypes.REGION_DID_CHANGE, - makeRegionPayload(isAnimated)) + makeRegionPayload(isAnimated)) mManager.handleEvent(didChangeEvent) mCameraChangeTracker.setReason(CameraChangeReason.NONE) } @@ -616,11 +616,11 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV styleLoaded(style) } }, - object : OnMapLoadErrorListener { - override fun onMapLoadError(mapLoadingErrorEventData: MapLoadingErrorEventData) { - Logger.w("MapLoadError", mapLoadingErrorEventData.message) - } + object : OnMapLoadErrorListener { + override fun onMapLoadError(mapLoadingErrorEventData: MapLoadingErrorEventData) { + Logger.w("MapLoadError", mapLoadingErrorEventData.message) } + } ) } } @@ -631,10 +631,10 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV } fun handleTapInSources( - sources: LinkedList>, screenPoint: ScreenCoordinate, - hits: HashMap?>, - hitTouchableSources: ArrayList?>, - handleTap: HandleTap + sources: LinkedList>, screenPoint: ScreenCoordinate, + hits: HashMap?>, + hitTouchableSources: ArrayList?>, + handleTap: HandleTap ) { if (sources.isEmpty()) { handleTap.run(hitTouchableSources, hits) @@ -646,17 +646,17 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV 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) + ScreenCoordinate(screenPoint.x - halfWidth, + screenPoint.y - halfHeight + ), + ScreenCoordinate(screenPoint.x + halfWidth, + screenPoint.y + halfHeight) ) mapView.getMapboxMap().queryRenderedFeatures(RenderedQueryGeometry(screenBox), - RenderedQueryOptions( - source.layerIDs, - null - ) + RenderedQueryOptions( + source.layerIDs, + null + ) ) { features -> if (features.isValue) { if (features.value!!.size > 0) { @@ -693,9 +693,9 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV 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()) + hits[source.iD] as List, + GeoJSONUtils.toLatLng(point), + PointF(screenPoint.x.toFloat(), screenPoint.y.toFloat()) )) return } @@ -858,7 +858,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV properties.putDouble("heading", position.bearing) properties.putDouble("pitch", position.pitch) properties.putBoolean("animated", - if (null == isAnimated) mCameraChangeTracker.isAnimated else isAnimated) + if (null == isAnimated) mCameraChangeTracker.isAnimated else isAnimated) properties.putBoolean("isUserInteraction", mCameraChangeTracker.isUserInteraction) try { val bounds = mMap.coordinateBoundsForCamera(position.toCameraOptions()) @@ -876,7 +876,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV */ private fun setUpImage(loadedStyle: Style) { loadedStyle.addImage("MARKER_IMAGE_ID", BitmapFactory.decodeResource( - this.resources, R.drawable.red_marker) + this.resources, R.drawable.red_marker) ) } @@ -976,9 +976,9 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV ScreenCoordinate(rect.right.toDouble(), rect.bottom.toDouble() ), ScreenCoordinate(rect.left.toDouble(), rect.top.toDouble()), ) - mMap?.queryRenderedFeatures( - RenderedQueryGeometry(screenBox), - RenderedQueryOptions(layerIDs, filter) + mMap.queryRenderedFeatures( + RenderedQueryGeometry(screenBox), + RenderedQueryOptions(layerIDs, filter) ) { features -> if (features.isValue) { val featuresList = ArrayList() diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index e444ba08d..36dd9d0ea 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -868,19 +868,6 @@ class MapView extends NativeBridgeComponent( const handle = findNodeHandle(nativeRef as any); - if (isAndroid()) { - return new Promise((resolve, reject) => { - const callbackID = `${methodName}_${this._nextCallbackIncrement()}`; - this._addAddAndroidCallback(callbackID, resolve, reject); - - NativeMapViewModule[methodName]?.( - handle, - callbackID, - ...(args ?? []), - ); - }); - } - // @ts-expect-error TS says that string cannot be used to index NativeMapViewModule. // It can, it's just not pretty. return NativeMapViewModule[methodName]?.( From b06a4b8f3acaaa93c998aa779f11718461af9da8 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 11:45:27 +0200 Subject: [PATCH 19/33] Remove command name from module calls --- .../components/mapview/NativeMapViewModule.kt | 20 +++++----------- ios/RCTMGL-v10/MBXMapViewModule.mm | 24 +++++++++---------- src/components/MapView.tsx | 1 - src/components/NativeBridgeComponent.tsx | 5 ---- src/specs/NativeMapViewModule.ts | 20 ++++------------ src/utils/index.ts | 16 ------------- 6 files changed, 22 insertions(+), 64 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index c6c03ad5d..ad101f520 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -41,7 +41,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun takeSnap(viewRef: Double?, command: String, writeToDisk: Boolean, promise: Promise) { + override fun takeSnap(viewRef: Double?, writeToDisk: Boolean, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.takeSnap(writeToDisk) { fillData -> with(WritableNativeMap()) { @@ -54,7 +54,6 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun queryTerrainElevation( viewRef: Double?, - command: String, coordinates: ReadableArray, promise: Promise ) { @@ -70,7 +69,6 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun setSourceVisibility( viewRef: Double?, - command: String, visible: Boolean, sourceId: String, sourceLayerId: String?, @@ -83,7 +81,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun getCenter(viewRef: Double?, command: String, promise: Promise) { + override fun getCenter(viewRef: Double?, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.getCenter { fillData -> with(WritableNativeMap()) { @@ -96,7 +94,6 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun getCoordinateFromView( viewRef: Double?, - command: String, atPoint: ReadableArray, promise: Promise ) { @@ -110,7 +107,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun getPointInView(viewRef: Double?, command: String, atCoordinate: ReadableArray, promise: Promise) { + override fun getPointInView(viewRef: Double?, atCoordinate: ReadableArray, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.getPointInView(atCoordinate.toCoordinate()) { fillData -> with(WritableNativeMap()) { @@ -121,7 +118,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun getZoom(viewRef: Double?, command: String, promise: Promise) { + override fun getZoom(viewRef: Double?, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.getZoom { fillData -> with(WritableNativeMap()) { @@ -132,7 +129,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun getVisibleBounds(viewRef: Double?, command: String, promise: Promise) { + override fun getVisibleBounds(viewRef: Double?, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.getVisibleBounds { fillData -> with(WritableNativeMap()) { @@ -145,7 +142,6 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun queryRenderedFeaturesAtPoint( viewRef: Double?, - command: String, atPoint: ReadableArray, withFilter: ReadableArray, withLayerIDs: ReadableArray, @@ -169,7 +165,6 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun queryRenderedFeaturesInRect( viewRef: Double?, - command: String, withBBox: ReadableArray, withFilter: ReadableArray, withLayerIDs: ReadableArray, @@ -193,7 +188,6 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun setHandledMapChangedEvents( viewRef: Double?, - command: String, events: ReadableArray, promise: Promise ) { @@ -203,7 +197,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - override fun clearData(viewRef: Double?, command: String, promise: Promise) { + override fun clearData(viewRef: Double?, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.clearData { fillData -> with(WritableNativeMap()) { @@ -216,14 +210,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul override fun querySourceFeatures( viewRef: Double?, - command: String, withFilter: ReadableArray, withSourceLayerIDs: ReadableArray, promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { it.querySourceFeatures( - command, ExpressionParser.from(withFilter), if (withSourceLayerIDs.size == 0) null else withSourceLayerIDs ) { fillData -> diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index 3eb452f4d..7cecca5a9 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -26,28 +26,28 @@ - (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(MBXMapViewCompon } -- (void)takeSnap:(NSNumber*)viewRef command:(NSString *)command writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +- (void)takeSnap:(NSNumber*)viewRef writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view takeSnap:writeToDisk resolve:resolve]; } reject:reject]; } -- (void)clearData:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view clearData:resolve reject:reject]; } reject:reject]; } -- (void)getCenter:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getCenter:resolve reject:reject]; } reject:reject]; } -- (void)getCoordinateFromView:(NSNumber*)viewRef command:(NSString *)command atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { NSNumber* a = [atPoint objectAtIndex:0]; NSNumber* b = [atPoint objectAtIndex:1]; @@ -57,56 +57,56 @@ - (void)getCoordinateFromView:(NSNumber*)viewRef command:(NSString *)command atP } -- (void)getPointInView:(NSNumber*)viewRef command:(NSString *)command atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getPointInView:atCoordinate resolve:resolve reject:reject]; } reject:reject]; } -- (void)getVisibleBounds:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getVisibleBounds:resolve]; } reject:reject]; } -- (void)getZoom:(NSNumber*)viewRef command:(NSString *)command resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view getZoom:resolve reject:reject]; } reject:reject]; } -- (void)queryRenderedFeaturesAtPoint:(NSNumber*)viewRef command:(NSString *)command atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view queryRenderedFeaturesAtPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; } reject:reject]; } -- (void)queryRenderedFeaturesInRect:(NSNumber*)viewRef command:(NSString *)command withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view queryRenderedFeaturesInRect:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; } reject:reject]; } -- (void)queryTerrainElevation:(NSNumber*)viewRef command:(NSString *)command coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view queryTerrainElevation:coordinates resolve:resolve reject:reject]; } reject:reject]; } -- (void)setHandledMapChangedEvents:(NSNumber*)viewRef command:(NSString *)command events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)setHandledMapChangedEvents:(NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view setHandledMapChangedEvents:events resolve:resolve reject:reject]; } reject:reject]; } -- (void)setSourceVisibility:(NSNumber*)viewRef command:(NSString *)command visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; } reject:reject]; diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index 36dd9d0ea..94c3f43d5 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -872,7 +872,6 @@ class MapView extends NativeBridgeComponent( // It can, it's just not pretty. return NativeMapViewModule[methodName]?.( handle, - '', ...(args ?? []), ) as Promise; } else { diff --git a/src/components/NativeBridgeComponent.tsx b/src/components/NativeBridgeComponent.tsx index a4ec70e15..3d2e7cbf4 100644 --- a/src/components/NativeBridgeComponent.tsx +++ b/src/components/NativeBridgeComponent.tsx @@ -110,11 +110,6 @@ const NativeBridgeComponent = < args, ); } - - _nextCallbackIncrement() { - callbackIncrement += 1; - return callbackIncrement; - } }; export default NativeBridgeComponent; diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index 2ce47c4df..a5b31384d 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -4,59 +4,47 @@ import { Int32 } from 'react-native/Libraries/Types/CodegenTypes'; import { TurboModuleRegistry } from 'react-native'; export interface Spec extends TurboModule { - takeSnap: ( - viewRef: Int32 | null, - command: string, - writeToDisk: boolean, - ) => Promise; + takeSnap: (viewRef: Int32 | null, writeToDisk: boolean) => Promise; queryTerrainElevation: ( viewRef: Int32 | null, - command: string, coordinates: ReadonlyArray, ) => Promise; setSourceVisibility: ( viewRef: Int32 | null, - command: string, visible: boolean, sourceId: string, sourceLayerId: string, ) => Promise; - getCenter: (viewRef: Int32 | null, command: string) => Promise; + getCenter: (viewRef: Int32 | null) => Promise; getCoordinateFromView: ( viewRef: Int32 | null, - command: string, atPoint: ReadonlyArray, ) => Promise; getPointInView: ( viewRef: Int32 | null, - command: string, atCoordinate: ReadonlyArray, ) => Promise; - getZoom: (viewRef: Int32 | null, command: string) => Promise; - getVisibleBounds: (viewRef: Int32 | null, command: string) => Promise; + getZoom: (viewRef: Int32 | null) => Promise; + getVisibleBounds: (viewRef: Int32 | null) => Promise; queryRenderedFeaturesAtPoint: ( viewRef: Int32 | null, - command: string, atPoint: ReadonlyArray, withFilter: ReadonlyArray, withLayerIDs: ReadonlyArray, ) => Promise; queryRenderedFeaturesInRect: ( viewRef: Int32 | null, - command: string, withBBox: ReadonlyArray, withFilter: ReadonlyArray, withLayerIDs: ReadonlyArray, ) => Promise; setHandledMapChangedEvents: ( viewRef: Int32 | null, - command: string, events: ReadonlyArray, ) => Promise; clearData: (viewRef: Int32 | null, command: string) => Promise; querySourceFeatures: ( viewRef: Int32 | null, - command: string, withFilter: ReadonlyArray, withSourceLayerIDs: ReadonlyArray, ) => Promise; diff --git a/src/utils/index.ts b/src/utils/index.ts index 37dc15f44..8d0f10ada 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -99,22 +99,6 @@ export function runNativeCommand( return managerInstance[name](handle, ...args); } -export function getCommandName(module: string, name: string): string { - if (!isAndroid()) { - return ''; // unused on iOS - } - - const managerInstance = getAndroidManagerInstance(module); - - if (!managerInstance) { - throw new Error(`Could not find ${module}`); - } - - const { Commands } = managerInstance; - - return Commands._useCommandName ? name : Commands[name]; -} - export function cloneReactChildrenWithProps( children: Parameters[0], propsToAdd: { [key: string]: string } = {}, From 0a23822916d23233e2229a65b0589bb6528b068b Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 12:13:01 +0200 Subject: [PATCH 20/33] Reject promises when error is present --- .../components/mapview/NativeMapViewModule.kt | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index ad101f520..42f55ccb7 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -4,6 +4,7 @@ import com.facebook.react.ReactApplication import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray +import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.WritableNativeMap import com.facebook.react.fabric.FabricUIManager import com.facebook.react.uimanager.UIManagerHelper @@ -41,12 +42,20 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } + private fun Promise.resolveOrReject(data: ReadableMap?) { + if (data != null && data.hasKey("error")) { + this.reject(Exception(data.getString("error"))) + } else { + this.resolve(data) + } + } + override fun takeSnap(viewRef: Double?, writeToDisk: Boolean, promise: Promise) { withMapViewManagerOnUIThread(viewRef) { it.takeSnap(writeToDisk) { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -61,7 +70,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.queryTerrainElevation(coordinates.getDouble(0), coordinates.getDouble(1)) { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -77,7 +86,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul withMapViewManagerOnUIThread(viewRef) { it.setSourceVisibility(visible, sourceId, sourceLayerId) - promise.resolve(null) + promise.resolveOrReject(null) } } @@ -86,7 +95,8 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.getCenter { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + + promise.resolveOrReject(this) } } } @@ -101,7 +111,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.getCoordinateFromView(atPoint.toScreenCoordinate()) { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -112,7 +122,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.getPointInView(atCoordinate.toCoordinate()) { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -123,7 +133,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.getZoom { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -134,7 +144,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.getVisibleBounds { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -157,7 +167,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul ) { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -180,7 +190,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul ) { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } @@ -193,7 +203,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul ) { withMapViewManagerOnUIThread(viewRef) { it.setHandledMapChangedEvents(events.asArrayString() ?: emptyArray()) - promise.resolve(null) + promise.resolveOrReject(null) } } @@ -202,7 +212,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul it.clearData { fillData -> with(WritableNativeMap()) { fillData(this) - promise.resolve(this) + promise.resolveOrReject(this) } } } From 2f8dcf4b8e56ad5ee2e5eef68f40a9bf74603e36 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 14:32:38 +0200 Subject: [PATCH 21/33] I aimed a little to high in the code --- .../components/mapview/NativeMapViewModule.kt | 23 ++++--------------- .../components/mapview/RCTMGLMapView.kt | 6 ----- .../mapview/RCTMGLMapViewManager.kt | 4 ---- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index 42f55ccb7..af4aa7d9e 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -21,24 +21,11 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul return } - // returns null when called too early :/, maybe fixable -// val manager = UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) as FabricUIManager -// val view = manager.resolveView(viewRef.toInt()) - reactApplicationContext.runOnUiQueueThread { - val viewManagers = - (reactApplicationContext.applicationContext as ReactApplication) - .reactNativeHost - .reactInstanceManager - .getOrCreateViewManagers(reactApplicationContext) - .filterIsInstance() - - for (viewManager in viewManagers) { - val view = viewManager.getByReactTag(viewRef.toInt()) ?: continue - - fn(view) - break - } + val manager = UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) as FabricUIManager + val view = manager.resolveView(viewRef.toInt()) as? RCTMGLMapView + + view?.let(fn) } } @@ -202,7 +189,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul promise: Promise ) { withMapViewManagerOnUIThread(viewRef) { - it.setHandledMapChangedEvents(events.asArrayString() ?: emptyArray()) + it.setHandledMapChangedEvents(events.asArrayString()) promise.resolveOrReject(null) } } diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt index bb18e3a89..22d7ce5d7 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt @@ -208,12 +208,6 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV return mapView.getMapboxMap() } - override fun setId(id: Int) { - super.setId(id) - - mManager.setViewForReactTag(id, this) - } - val pointAnnotationManager: PointAnnotationManager? get() { if (mPointAnnotationManager == null) { diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt index 8c440e3ff..27cbdb318 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt @@ -118,10 +118,6 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : return mViews[reactTag] } - fun setViewForReactTag(reactTag: Int, mapView: RCTMGLMapView) { - mViews[reactTag] = mapView - } - // region React Props @ReactProp(name = "projection") override fun setProjection(mapView: RCTMGLMapView, projection: String?) { From 7dd5fe742ef77657381d3dbcb98ea8afef115ab3 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 14:37:52 +0200 Subject: [PATCH 22/33] Reject promise when map view cannot be found --- .../components/mapview/NativeMapViewModule.kt | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index af4aa7d9e..06940fbef 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -16,7 +16,7 @@ import com.mapbox.rctmgl.utils.extensions.toCoordinate import com.mapbox.rctmgl.utils.extensions.toScreenCoordinate class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModuleSpec(context) { - private fun withMapViewManagerOnUIThread(viewRef: Double?, fn: (RCTMGLMapView) -> Unit) { + private fun withMapViewManagerOnUIThread(viewRef: Double?, promise: Promise, fn: (RCTMGLMapView) -> Unit) { if (viewRef == null) { return } @@ -25,7 +25,11 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul val manager = UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) as FabricUIManager val view = manager.resolveView(viewRef.toInt()) as? RCTMGLMapView - view?.let(fn) + if (view != null) { + fn(view) + } else { + promise.reject(Exception("cannot find map view for tag ${viewRef.toInt()}")) + } } } @@ -38,7 +42,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } override fun takeSnap(viewRef: Double?, writeToDisk: Boolean, promise: Promise) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.takeSnap(writeToDisk) { fillData -> with(WritableNativeMap()) { fillData(this) @@ -53,7 +57,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul coordinates: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.queryTerrainElevation(coordinates.getDouble(0), coordinates.getDouble(1)) { fillData -> with(WritableNativeMap()) { fillData(this) @@ -70,7 +74,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul sourceLayerId: String?, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.setSourceVisibility(visible, sourceId, sourceLayerId) promise.resolveOrReject(null) @@ -78,7 +82,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } override fun getCenter(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.getCenter { fillData -> with(WritableNativeMap()) { fillData(this) @@ -94,7 +98,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul atPoint: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.getCoordinateFromView(atPoint.toScreenCoordinate()) { fillData -> with(WritableNativeMap()) { fillData(this) @@ -105,7 +109,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } override fun getPointInView(viewRef: Double?, atCoordinate: ReadableArray, promise: Promise) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.getPointInView(atCoordinate.toCoordinate()) { fillData -> with(WritableNativeMap()) { fillData(this) @@ -116,7 +120,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } override fun getZoom(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.getZoom { fillData -> with(WritableNativeMap()) { fillData(this) @@ -127,7 +131,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } override fun getVisibleBounds(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.getVisibleBounds { fillData -> with(WritableNativeMap()) { fillData(this) @@ -144,7 +148,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul withLayerIDs: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { val layerIds = ConvertUtils.toStringList(withLayerIDs) it.queryRenderedFeaturesAtPoint( @@ -167,7 +171,7 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul withLayerIDs: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { val layerIds = ConvertUtils.toStringList(withLayerIDs) it.queryRenderedFeaturesInRect( @@ -188,14 +192,14 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul events: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.setHandledMapChangedEvents(events.asArrayString()) promise.resolveOrReject(null) } } override fun clearData(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewManagerOnUIThread(viewRef, promise) { it.clearData { fillData -> with(WritableNativeMap()) { fillData(this) From 6d9d8e07d35fcb4e251990728896fa11afaaeb05 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Fri, 1 Sep 2023 17:45:24 +0200 Subject: [PATCH 23/33] feat: old arch also working --- fabricexample/App.tsx | 6 +- fabricexample/package.json | 4 +- fabricexample/scripts/set_access_token.js | 12 ++++ ios/RCTMGL-v10/MBXMapViewManager.swift | 2 +- ios/RCTMGL-v10/MBXMapViewModule.h | 17 +++-- ios/RCTMGL-v10/MBXMapViewModule.mm | 86 ++++++++++++++--------- src/components/MapView.tsx | 5 +- 7 files changed, 85 insertions(+), 47 deletions(-) create mode 100755 fabricexample/scripts/set_access_token.js diff --git a/fabricexample/App.tsx b/fabricexample/App.tsx index c806510f4..36f092461 100644 --- a/fabricexample/App.tsx +++ b/fabricexample/App.tsx @@ -1,11 +1,9 @@ -// @ts-ignore -import {ACCESS_TOKEN} from '@env'; - import React from 'react'; import {StyleSheet, View} from 'react-native'; import Mapbox from '@rnmapbox/maps'; +import env from './env.json'; -Mapbox.setAccessToken(ACCESS_TOKEN); +Mapbox.setAccessToken(env.accessToken); const App = () => { return ( diff --git a/fabricexample/package.json b/fabricexample/package.json index 50bb9a7a1..a441a4ae5 100644 --- a/fabricexample/package.json +++ b/fabricexample/package.json @@ -7,7 +7,8 @@ "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", - "test": "jest" + "test": "jest", + "postinstall": "node ./scripts/set_access_token.js && jetifier" }, "dependencies": { "@rnmapbox/maps": "link:../", @@ -26,6 +27,7 @@ "babel-jest": "^29.2.1", "eslint": "^8.19.0", "jest": "^29.2.1", + "jetifier": "^2.0.0", "metro-react-native-babel-preset": "0.76.8", "prettier": "^2.4.1", "react-native-dotenv": "^3.4.9", diff --git a/fabricexample/scripts/set_access_token.js b/fabricexample/scripts/set_access_token.js new file mode 100755 index 000000000..90b6ac1ae --- /dev/null +++ b/fabricexample/scripts/set_access_token.js @@ -0,0 +1,12 @@ +const fs = require('fs'); +const path = require('path'); + +const accessToken = fs.readFileSync(path.join('./', 'accesstoken')); + +if (!accessToken) { + process.exit(1); +} + +// eslint-disable-next-line no-new-wrappers +const fileContents = `{ "accessToken": "${new String(accessToken).trim()}" }`; +fs.writeFileSync(path.join('./', 'env.json'), fileContents); diff --git a/ios/RCTMGL-v10/MBXMapViewManager.swift b/ios/RCTMGL-v10/MBXMapViewManager.swift index 651c452af..95d95e89c 100644 --- a/ios/RCTMGL-v10/MBXMapViewManager.swift +++ b/ios/RCTMGL-v10/MBXMapViewManager.swift @@ -12,7 +12,7 @@ class MBXMapViewManager: RCTViewManager { } override func view() -> UIView! { - let result = RCTMGLMapView(frame: self.defaultFrame(), eventDispatcher: self.bridge.eventDispatcher()) + let result = MBXMapView(frame: self.defaultFrame(), eventDispatcher: self.bridge.eventDispatcher()) return result } } diff --git a/ios/RCTMGL-v10/MBXMapViewModule.h b/ios/RCTMGL-v10/MBXMapViewModule.h index cc4de2afd..2884bba48 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.h +++ b/ios/RCTMGL-v10/MBXMapViewModule.h @@ -1,11 +1,18 @@ -#ifdef RCT_NEW_ARCH_ENABLED -#import "rnmapbox_maps.h" - #import #import -@interface MBXMapViewModule : NSObject +#ifdef RCT_NEW_ARCH_ENABLED +#import "rnmapbox_maps.h" +#else +#import +#endif + +@interface MBXMapViewModule : NSObject +#ifdef RCT_NEW_ARCH_ENABLED + +#else + +#endif @end -#endif diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index 7cecca5a9..4dca2caf2 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -1,7 +1,12 @@ -#ifdef RCT_NEW_ARCH_ENABLED +#import +#import +#import #import "MBXMapViewModule.h" +#import "MBXMapView.h" +#ifdef RCT_NEW_ARCH_ENABLED #import "MBXMapViewComponentView.h" +#endif // RCT_NEW_ARCH_ENABLED @implementation MBXMapViewModule @@ -12,43 +17,55 @@ @implementation MBXMapViewModule #endif // RCT_NEW_ARCH_ENABLED @synthesize bridge = _bridge; -- (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(MBXMapViewComponentView*))block reject:(RCTPromiseRejectBlock)reject +- (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(UIView*))block reject:(RCTPromiseRejectBlock)reject { - dispatch_async(dispatch_get_main_queue(), ^{ - MBXMapViewComponentView* view = [self.viewRegistry_DEPRECATED viewForReactTag:viewRef]; - + void (^upperBlock)(void) = ^{ +#ifdef RCT_NEW_ARCH_ENABLED + [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { + UIView *view = [self.viewRegistry_DEPRECATED viewForReactTag:viewRef]; +#else + [self.bridge.uiManager + addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { + UIView *view = [uiManager viewForReactTag:viewRef]; +#endif // RCT_NEW_ARCH_ENABLED if (view != nil) { - block(view); + block(view); } else { - reject(@"takeSnap", [NSString stringWithFormat:@"Unknown find reactTag: %@", viewRef], nil); + reject(@"takeSnap", [NSString stringWithFormat:@"Unknown reactTag: %@", viewRef], nil); } - }); + }]; + }; + if (self.bridge) { + dispatch_async(RCTGetUIManagerQueue(), upperBlock); + } else { + dispatch_async(dispatch_get_main_queue(), upperBlock); + } } -- (void)takeSnap:(NSNumber*)viewRef writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +RCT_EXPORT_METHOD(takeSnap:(NSNumber*)viewRef writeToDisk:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view takeSnap:writeToDisk resolve:resolve]; } reject:reject]; } -- (void)clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view clearData:resolve reject:reject]; } reject:reject]; } -- (void)getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view getCenter:resolve reject:reject]; } reject:reject]; } -- (void)getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { NSNumber* a = [atPoint objectAtIndex:0]; NSNumber* b = [atPoint objectAtIndex:1]; @@ -57,62 +74,62 @@ - (void)getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint reso } -- (void)getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view getPointInView:atCoordinate resolve:resolve reject:reject]; } reject:reject]; } -- (void)getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view getVisibleBounds:resolve]; } reject:reject]; } -- (void)getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view getZoom:resolve reject:reject]; } reject:reject]; } -- (void)queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view queryRenderedFeaturesAtPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; } reject:reject]; } -- (void)queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view queryRenderedFeaturesInRect:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; } reject:reject]; } -- (void)queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view queryTerrainElevation:coordinates resolve:resolve reject:reject]; } reject:reject]; } -- (void)setHandledMapChangedEvents:(NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(setHandledMapChangedEvents:(nonnull NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view setHandledMapChangedEvents:events resolve:resolve reject:reject]; } reject:reject]; } -- (void)setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; } reject:reject]; } -- (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject { +RCT_EXPORT_METHOD(querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject) { [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { [view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; } reject:reject]; @@ -125,7 +142,6 @@ - (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NS { return std::make_shared(params); } +#endif // RCT_NEW_ARCH_ENABLED @end - -#endif // RCT_NEW_ARCH_ENABLED diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index 94c3f43d5..834129ceb 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -20,7 +20,6 @@ import { isAndroid, type NativeArg, type OrnamentPositonProp, - getCommandName, } from '../utils'; import { getFilter } from '../utils/filterUtils'; import Logger from '../utils/Logger'; @@ -744,6 +743,8 @@ class MapView extends NativeBridgeComponent( ): Promise { return this._runNativeCommand( methodName, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore TODO: fix types this._nativeRef as HostComponent | undefined, args, ); @@ -1137,6 +1138,8 @@ class MapView extends NativeBridgeComponent( ); } else if (this.state.isReady) { mapView = ( + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore TODO: fix types {this.props.children} From fc23bfdfa19fa46ebc77fe319a92a174cd4c2c9f Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Fri, 1 Sep 2023 18:17:16 +0200 Subject: [PATCH 24/33] Update gitignore --- fabricexample/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fabricexample/.gitignore b/fabricexample/.gitignore index e2209bbae..516dd5ba2 100644 --- a/fabricexample/.gitignore +++ b/fabricexample/.gitignore @@ -65,4 +65,6 @@ yarn-error.log # testing /coverage -.env \ No newline at end of file +.env +accesstoken +env.json From a95fe4f336eb30b371cd17db080d5995e9f2e9d6 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 4 Sep 2023 11:20:14 +0200 Subject: [PATCH 25/33] Fixes after rebase --- .../components/mapview/NativeMapViewModule.kt | 141 ++++++------------ fabricexample/ios/Podfile.lock | 8 +- ios/RCTMGL-v10/MBXMapView.h | 2 +- ios/RCTMGL-v10/MBXMapView.swift | 7 +- ios/RCTMGL-v10/MBXMapViewComponentView.h | 2 +- ios/RCTMGL-v10/MBXMapViewComponentView.mm | 2 +- ios/RCTMGL-v10/MBXMapViewModule.mm | 5 +- src/specs/NativeMapViewModule.ts | 3 +- 8 files changed, 63 insertions(+), 107 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index 06940fbef..79b8e60d1 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -1,10 +1,9 @@ package com.mapbox.rctmgl.components.mapview -import com.facebook.react.ReactApplication import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray -import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.WritableMap import com.facebook.react.bridge.WritableNativeMap import com.facebook.react.fabric.FabricUIManager import com.facebook.react.uimanager.UIManagerHelper @@ -16,7 +15,7 @@ import com.mapbox.rctmgl.utils.extensions.toCoordinate import com.mapbox.rctmgl.utils.extensions.toScreenCoordinate class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModuleSpec(context) { - private fun withMapViewManagerOnUIThread(viewRef: Double?, promise: Promise, fn: (RCTMGLMapView) -> Unit) { + private fun withMapViewOnUIThread(viewRef: Double?, promise: Promise, fn: (RCTMGLMapView) -> Unit) { if (viewRef == null) { return } @@ -33,22 +32,22 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } } - private fun Promise.resolveOrReject(data: ReadableMap?) { - if (data != null && data.hasKey("error")) { - this.reject(Exception(data.getString("error"))) - } else { - this.resolve(data) + private fun createCommandResponse(promise: Promise): CommandResponse = object : CommandResponse { + override fun success(builder: (WritableMap) -> Unit) { + val payload: WritableMap = WritableNativeMap() + builder(payload) + + promise.resolve(payload) + } + + override fun error(message: String) { + promise.reject(Exception(message)) } } override fun takeSnap(viewRef: Double?, writeToDisk: Boolean, promise: Promise) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.takeSnap(writeToDisk) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.takeSnap(writeToDisk, createCommandResponse(promise)) } } @@ -57,13 +56,8 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul coordinates: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.queryTerrainElevation(coordinates.getDouble(0), coordinates.getDouble(1)) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.queryTerrainElevation(coordinates.getDouble(0), coordinates.getDouble(1), createCommandResponse(promise)) } } @@ -74,22 +68,16 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul sourceLayerId: String?, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef, promise) { + withMapViewOnUIThread(viewRef, promise) { it.setSourceVisibility(visible, sourceId, sourceLayerId) - promise.resolveOrReject(null) + promise.resolve(null) } } override fun getCenter(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.getCenter { fillData -> - with(WritableNativeMap()) { - fillData(this) - - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.getCenter(createCommandResponse(promise)) } } @@ -98,46 +86,26 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul atPoint: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.getCoordinateFromView(atPoint.toScreenCoordinate()) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.getCoordinateFromView(atPoint.toScreenCoordinate(), createCommandResponse(promise)) } } override fun getPointInView(viewRef: Double?, atCoordinate: ReadableArray, promise: Promise) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.getPointInView(atCoordinate.toCoordinate()) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.getPointInView(atCoordinate.toCoordinate(), createCommandResponse(promise)) } } override fun getZoom(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.getZoom { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.getZoom(createCommandResponse(promise)) } } override fun getVisibleBounds(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.getVisibleBounds { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.getVisibleBounds(createCommandResponse(promise)) } } @@ -148,19 +116,15 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul withLayerIDs: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef, promise) { + withMapViewOnUIThread(viewRef, promise) { val layerIds = ConvertUtils.toStringList(withLayerIDs) it.queryRenderedFeaturesAtPoint( ConvertUtils.toPointF(atPoint), ExpressionParser.from(withFilter), - if (layerIds.size == 0) null else layerIds - ) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + if (layerIds.size == 0) null else layerIds, + createCommandResponse(promise) + ) } } @@ -171,19 +135,15 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul withLayerIDs: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef, promise) { + withMapViewOnUIThread(viewRef, promise) { val layerIds = ConvertUtils.toStringList(withLayerIDs) it.queryRenderedFeaturesInRect( ConvertUtils.toRectF(withBBox), ExpressionParser.from(withFilter), - if (layerIds.size == 0) null else layerIds - ) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + if (layerIds.size == 0) null else layerIds, + createCommandResponse(promise) + ) } } @@ -192,39 +152,34 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul events: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef, promise) { + withMapViewOnUIThread(viewRef, promise) { it.setHandledMapChangedEvents(events.asArrayString()) - promise.resolveOrReject(null) + promise.resolve(null) } } override fun clearData(viewRef: Double?, promise: Promise) { - withMapViewManagerOnUIThread(viewRef, promise) { - it.clearData { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolveOrReject(this) - } - } + withMapViewOnUIThread(viewRef, promise) { + it.clearData(createCommandResponse(promise)) } } override fun querySourceFeatures( viewRef: Double?, + sourceId: String, withFilter: ReadableArray, withSourceLayerIDs: ReadableArray, promise: Promise ) { - withMapViewManagerOnUIThread(viewRef) { + withMapViewOnUIThread(viewRef, promise) { + val sourceLayerIds = ConvertUtils.toStringList(withSourceLayerIDs) + it.querySourceFeatures( + sourceId, ExpressionParser.from(withFilter), - if (withSourceLayerIDs.size == 0) null else withSourceLayerIDs - ) { fillData -> - with(WritableNativeMap()) { - fillData(this) - promise.resolve(this) - } - } + if (sourceLayerIds.size == 0) null else sourceLayerIds, + createCommandResponse(promise) + ) } } diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock index 66f30b298..73a46de97 100644 --- a/fabricexample/ios/Podfile.lock +++ b/fabricexample/ios/Podfile.lock @@ -1007,13 +1007,13 @@ PODS: - React-jsi (= 0.72.4) - React-logger (= 0.72.4) - React-perflogger (= 0.72.4) - - rnmapbox-maps (10.0.12): + - rnmapbox-maps (10.0.13-rc.1): - MapboxMaps (~> 10.15.0) - React - React-Core - - rnmapbox-maps/DynamicLibrary (= 10.0.12) + - rnmapbox-maps/DynamicLibrary (= 10.0.13-rc.1) - Turf - - rnmapbox-maps/DynamicLibrary (10.0.12): + - rnmapbox-maps/DynamicLibrary (10.0.13-rc.1): - hermes-engine - MapboxMaps (~> 10.15.0) - RCT-Folly (= 2021.07.22.00) @@ -1232,7 +1232,7 @@ SPEC CHECKSUMS: React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d - rnmapbox-maps: dbaa77c7b8afec28f333c7d7ed3e57cd266acbc2 + rnmapbox-maps: 78fdff8350d72d002f77e3a1507c817b4df614a6 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h index 0891e83c4..21899dc9f 100644 --- a/ios/RCTMGL-v10/MBXMapView.h +++ b/ios/RCTMGL-v10/MBXMapView.h @@ -41,7 +41,7 @@ - (void)queryTerrainElevation:(NSArray* _Nonnull)coordinates resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; - (void)setHandledMapChangedEvents:(NSArray* _Nonnull)events resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; - (void)setSourceVisibility:(BOOL)visible sourceId:(NSString* _Nonnull)sourceId sourceLayerId:(NSString* _Nullable)sourceLayerId resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; -- (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)querySourceFeatures:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; @end diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift index 7491498be..88eb5ceb8 100644 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ b/ios/RCTMGL-v10/MBXMapView.swift @@ -193,11 +193,10 @@ open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { MBXMapViewManager.setSourceVisibility(self, visible: visible, sourceId: sourceId, sourceLayerId: sourceLayerId, resolver: resolve, rejecter: reject) } - func querySourceFeatures( - _ reactTag: NSNumber, - withSourceId sourceId: String, + public func querySourceFeatures( + _ sourceId: String, withFilter filter: [Any]?, - withSourceLayerIds sourceLayerIds: [String]?, + withSourceLayerIDs sourceLayerIds: [String]?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void { MBXMapViewManager.querySourceFeatures(self, withSourceId: sourceId, withFilter: filter, withSourceLayerIds: sourceLayerIds, resolver: resolve, rejecter: reject) diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.h b/ios/RCTMGL-v10/MBXMapViewComponentView.h index de8e300ac..f3b30885e 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.h +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.h @@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)queryTerrainElevation:(NSArray*)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; - (void)setHandledMapChangedEvents:(NSArray*)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; - (void)setSourceVisibility:(BOOL)visible sourceId:(NSString*)sourceId sourceLayerId:(NSString*)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)querySourceFeatures:sourceId:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; +- (void)querySourceFeatures:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; @end diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index 3b49c79cf..a072736f2 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -191,7 +191,7 @@ - (void)setSourceVisibility:(BOOL)visible sourceId:(NSString*)sourceId sourceLay [_view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; } -- (void)querySourceFeatures:sourceId:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject { +- (void)querySourceFeatures:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [_view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; } diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index 4dca2caf2..3731c7656 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -129,14 +129,15 @@ - (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(UIView* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject) { - [self withMapComponentView:viewRef block:^(MBXMapViewComponentView* view) { +RCT_EXPORT_METHOD(querySourceFeatures:(NSNumber*)viewRef sourceId:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapComponentView:viewRef block:^(UIView* view) { [view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; } reject:reject]; } // Thanks to this guard, we won't compile this code when we build for the old architecture. +#ifdef RCT_NEW_ARCH_ENABLED - (std::shared_ptr)getTurboModule: (const facebook::react::ObjCTurboModule::InitParams &)params { diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index a5b31384d..b581d33be 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -42,9 +42,10 @@ export interface Spec extends TurboModule { viewRef: Int32 | null, events: ReadonlyArray, ) => Promise; - clearData: (viewRef: Int32 | null, command: string) => Promise; + clearData: (viewRef: Int32 | null) => Promise; querySourceFeatures: ( viewRef: Int32 | null, + sourceId: string, withFilter: ReadonlyArray, withSourceLayerIDs: ReadonlyArray, ) => Promise; From fb96e20d6ec99d4d2bf660ca1aae28aaa39818e5 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 4 Sep 2023 11:32:25 +0200 Subject: [PATCH 26/33] Add helper for decoding event payload --- src/components/MapView.tsx | 42 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index 834129ceb..b9797298f 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -12,6 +12,7 @@ import { findNodeHandle, } from 'react-native'; import { debounce } from 'debounce'; +import { GeoJsonProperties, Geometry } from 'geojson'; import NativeMapView from '../specs/MBXMapViewNativeComponent'; import NativeMapViewModule from '../specs/NativeMapViewModule'; @@ -884,27 +885,27 @@ class MapView extends NativeBridgeComponent( } } + _decodePayload( + payload: GeoJSON.Feature | string, + ): GeoJSON.Feature { + // we check whether the payload is a string, since the strict type safety is enforced only on iOS on the new arch + // on Android, on both archs, the payload is an object + if (typeof payload === 'string') { + return JSON.parse(payload); + } else { + return payload; + } + } + _onPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { if (isFunction(this.props.onPress)) { - const { payload } = e.nativeEvent; - - if (typeof payload === 'string') { - this.props.onPress(JSON.parse(payload)); - } else { - this.props.onPress(payload); - } + this.props.onPress(this._decodePayload(e.nativeEvent.payload)); } } _onLongPress(e: NativeSyntheticEvent<{ payload: GeoJSON.Feature }>) { if (isFunction(this.props.onLongPress)) { - const { payload } = e.nativeEvent; - - if (typeof payload === 'string') { - this.props.onLongPress(JSON.parse(payload)); - } else { - this.props.onLongPress(payload); - } + this.props.onLongPress(e.nativeEvent.payload); } } @@ -932,13 +933,7 @@ class MapView extends NativeBridgeComponent( } _onCameraChanged(e: NativeSyntheticEvent<{ payload: MapState }>) { - const { payload } = e.nativeEvent; - - if (typeof payload === 'string') { - this.props.onCameraChanged?.(JSON.parse(payload)); - } else { - this.props.onCameraChanged?.(payload); - } + this.props.onCameraChanged?.(e.nativeEvent.payload); } _onChange( @@ -953,10 +948,7 @@ class MapView extends NativeBridgeComponent( const { regionWillChangeDebounceTime, regionDidChangeDebounceTime } = this.props; const { type } = e.nativeEvent; - const payload = - typeof e.nativeEvent.payload === 'string' - ? JSON.parse(e.nativeEvent.payload) - : e.nativeEvent.payload; + const payload = this._decodePayload(e.nativeEvent.payload); let propName: CallbablePropKeys | '' = ''; let deprecatedPropName: CallbablePropKeys | '' = ''; From cf70036d4526d2c7601b96c1b8086277324c1099 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 4 Sep 2023 11:41:53 +0200 Subject: [PATCH 27/33] Revert whitespace changes --- .../components/mapview/RCTMGLMapView.kt | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt index 22d7ce5d7..0895682da 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt @@ -218,9 +218,9 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV mPointAnnotationManager = mapView.annotations.createPointAnnotationManager(AnnotationConfig(layerId = "rctmgl-mapview-annotations")) mPointAnnotationManager?.addClickListener(OnPointAnnotationClickListener { pointAnnotation -> - onMarkerClick(pointAnnotation) - false - } + onMarkerClick(pointAnnotation) + false + } ) mPointAnnotationManager?.addDragListener(object : OnPointAnnotationDragListener { override fun onAnnotationDragStarted(_annotation: Annotation<*>) { @@ -236,7 +236,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV reactAnnotation?.let { it.onDragStart() } } - override fun onAnnotationDrag(_annotation: Annotation<*>) { + override fun onAnnotationDrag(_annotation: Annotation<*>) { var reactAnnotation: RCTMGLPointAnnotation? = null for (key in mPointAnnotations.keys) { val annotation = mPointAnnotations[key] @@ -278,13 +278,13 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV } private fun setupEvents() { - mMap?.addOnRenderFrameFinishedListener( - object: OnRenderFrameFinishedListener { - override fun onRenderFrameFinished(eventData: RenderFrameFinishedEventData) { - handleMapChangedEvent(EventTypes.DID_FINISH_RENDERING_FRAME_FULLY) - } - } - ) + mMap?.addOnRenderFrameFinishedListener( + object: OnRenderFrameFinishedListener { + override fun onRenderFrameFinished(eventData: RenderFrameFinishedEventData) { + handleMapChangedEvent(EventTypes.DID_FINISH_RENDERING_FRAME_FULLY) + } + } + ) } private fun onMapReady(map: MapboxMap) { @@ -371,11 +371,11 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV Logger.e(LOG_TAG, String.format("Map load failed: %s", event.data.toString())) val errorMessage = event.getMapLoadingErrorEventData().message val event = MapChangeEvent(this, EventTypes.MAP_LOADING_ERROR, writableMapOf( - "error" to errorMessage + "error" to errorMessage )) mManager.handleEvent(event) - }, Arrays.asList(MapEvents.MAP_LOADING_ERROR)) + }, Arrays.asList(MapEvents.MAP_LOADING_ERROR)) } fun mapGestureBegin(type:MapGestureType, gesture: T) { @@ -490,7 +490,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV fun sendRegionChangeEvent(isAnimated: Boolean) { val didChangeEvent = MapChangeEvent(this, EventTypes.REGION_DID_CHANGE, - makeRegionPayload(isAnimated)) + makeRegionPayload(isAnimated)) mManager.handleEvent(didChangeEvent) mCameraChangeTracker.setReason(CameraChangeReason.NONE) } @@ -610,11 +610,11 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV styleLoaded(style) } }, - object : OnMapLoadErrorListener { - override fun onMapLoadError(mapLoadingErrorEventData: MapLoadingErrorEventData) { - Logger.w("MapLoadError", mapLoadingErrorEventData.message) + object : OnMapLoadErrorListener { + override fun onMapLoadError(mapLoadingErrorEventData: MapLoadingErrorEventData) { + Logger.w("MapLoadError", mapLoadingErrorEventData.message) + } } - } ) } } @@ -625,10 +625,10 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV } fun handleTapInSources( - sources: LinkedList>, screenPoint: ScreenCoordinate, - hits: HashMap?>, - hitTouchableSources: ArrayList?>, - handleTap: HandleTap + sources: LinkedList>, screenPoint: ScreenCoordinate, + hits: HashMap?>, + hitTouchableSources: ArrayList?>, + handleTap: HandleTap ) { if (sources.isEmpty()) { handleTap.run(hitTouchableSources, hits) @@ -640,17 +640,17 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV 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) + ScreenCoordinate(screenPoint.x - halfWidth, + screenPoint.y - halfHeight + ), + ScreenCoordinate(screenPoint.x + halfWidth, + screenPoint.y + halfHeight) ) mapView.getMapboxMap().queryRenderedFeatures(RenderedQueryGeometry(screenBox), - RenderedQueryOptions( - source.layerIDs, - null - ) + RenderedQueryOptions( + source.layerIDs, + null + ) ) { features -> if (features.isValue) { if (features.value!!.size > 0) { @@ -687,9 +687,9 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV 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()) + hits[source.iD] as List, + GeoJSONUtils.toLatLng(point), + PointF(screenPoint.x.toFloat(), screenPoint.y.toFloat()) )) return } @@ -852,7 +852,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV properties.putDouble("heading", position.bearing) properties.putDouble("pitch", position.pitch) properties.putBoolean("animated", - if (null == isAnimated) mCameraChangeTracker.isAnimated else isAnimated) + if (null == isAnimated) mCameraChangeTracker.isAnimated else isAnimated) properties.putBoolean("isUserInteraction", mCameraChangeTracker.isUserInteraction) try { val bounds = mMap.coordinateBoundsForCamera(position.toCameraOptions()) @@ -870,7 +870,7 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV */ private fun setUpImage(loadedStyle: Style) { loadedStyle.addImage("MARKER_IMAGE_ID", BitmapFactory.decodeResource( - this.resources, R.drawable.red_marker) + this.resources, R.drawable.red_marker) ) } @@ -971,8 +971,8 @@ open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapV ScreenCoordinate(rect.left.toDouble(), rect.top.toDouble()), ) mMap.queryRenderedFeatures( - RenderedQueryGeometry(screenBox), - RenderedQueryOptions(layerIDs, filter) + RenderedQueryGeometry(screenBox), + RenderedQueryOptions(layerIDs, filter) ) { features -> if (features.isValue) { val featuresList = ArrayList() From 1b3922fd43135b91ea345b470deb5290b5d8231a Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 4 Sep 2023 15:52:28 +0200 Subject: [PATCH 28/33] Support for TextureMapView --- .../RCTMGLAndroidTextureMapViewManager.kt | 18 +++++- example/ios/Podfile.lock | 8 +-- src/components/MapView.tsx | 9 +-- ...MBXAndroidTextureMapViewNativeComponent.ts | 63 +++++++++++++++++++ 4 files changed, 86 insertions(+), 12 deletions(-) create mode 100644 src/specs/MBXAndroidTextureMapViewNativeComponent.ts diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt index 993703c1e..3d75b036c 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt @@ -2,11 +2,25 @@ package com.mapbox.rctmgl.components.mapview import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.ViewManagerDelegate +import com.facebook.react.viewmanagers.MBXAndroidTextureMapViewManagerDelegate +import com.facebook.react.viewmanagers.MBXAndroidTextureMapViewManagerInterface +import com.facebook.react.viewmanagers.MBXMapViewManagerDelegate import com.mapbox.maps.MapInitOptions class RCTMGLAndroidTextureMapViewManager(context: ReactApplicationContext) : RCTMGLMapViewManager( context -) { +), MBXAndroidTextureMapViewManagerInterface { + private val mDelegate: ViewManagerDelegate + + init { + mDelegate = MBXAndroidTextureMapViewManagerDelegate(this) + } + + override fun getDelegate(): ViewManagerDelegate? { + return mDelegate + } + override fun getName(): String { return REACT_CLASS } @@ -18,6 +32,6 @@ class RCTMGLAndroidTextureMapViewManager(context: ReactApplicationContext) : RCT } companion object { - const val REACT_CLASS = "RCTMGLAndroidTextureMapView" + const val REACT_CLASS = "MBXAndroidTextureMapView" } } \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1b6a8eb29..2f58f8298 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -426,13 +426,13 @@ PODS: - React-perflogger (= 0.71.7) - RNCAsyncStorage (1.19.2): - React-Core - - rnmapbox-maps (10.0.12-rc.3): + - rnmapbox-maps (10.0.13-rc.1): - MapboxMaps (~> 10.15.0) - React - React-Core - - rnmapbox-maps/DynamicLibrary (= 10.0.12-rc.3) + - rnmapbox-maps/DynamicLibrary (= 10.0.13-rc.1) - Turf - - rnmapbox-maps/DynamicLibrary (10.0.12-rc.3): + - rnmapbox-maps/DynamicLibrary (10.0.13-rc.1): - MapboxMaps (~> 10.15.0) - React - React-Core @@ -675,7 +675,7 @@ SPEC CHECKSUMS: React-runtimeexecutor: c5c89f8f543842dd864b63ded1b0bbb9c9445328 ReactCommon: dbfbe2f7f3c5ce4ce44f43f2fd0d5950d1eb67c5 RNCAsyncStorage: f57e929cd7757f2cb3dd8186d123c09e8281a1ad - rnmapbox-maps: 0660e2b651eea7aa9c2e51440ec55fc491d2eb16 + rnmapbox-maps: bec5f28dceb067f34dca4979a7be2cf43cd89df7 RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7 RNSVG: d7d7bc8229af3842c9cfc3a723c815a52cdd1105 RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8 diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index b9797298f..a38e276b1 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -3,7 +3,6 @@ import { View, StyleSheet, NativeModules, - requireNativeComponent, ViewProps, NativeSyntheticEvent, NativeMethods, @@ -15,6 +14,7 @@ import { debounce } from 'debounce'; import { GeoJsonProperties, Geometry } from 'geojson'; import NativeMapView from '../specs/MBXMapViewNativeComponent'; +import NativeAndroidTextureMapView from '../specs/MBXAndroidTextureMapViewNativeComponent'; import NativeMapViewModule from '../specs/NativeMapViewModule'; import { isFunction, @@ -44,10 +44,9 @@ if (!MGLModule.MapboxV10) { ); } +// TODO: check if this can be removed export const NATIVE_MODULE_NAME = 'MBXMapView'; -export const ANDROID_TEXTURE_NATIVE_MODULE_NAME = 'RCTMGLAndroidTextureMapView'; - const styles = StyleSheet.create({ matchParent: { flex: 1 }, }); @@ -1166,9 +1165,7 @@ const RCTMGLMapView = NativeMapView; let RCTMGLAndroidTextureMapView: any; if (isAndroid()) { - RCTMGLAndroidTextureMapView = requireNativeComponent( - ANDROID_TEXTURE_NATIVE_MODULE_NAME, - ); + RCTMGLAndroidTextureMapView = NativeAndroidTextureMapView; } export default MapView; diff --git a/src/specs/MBXAndroidTextureMapViewNativeComponent.ts b/src/specs/MBXAndroidTextureMapViewNativeComponent.ts new file mode 100644 index 000000000..93f1b4de9 --- /dev/null +++ b/src/specs/MBXAndroidTextureMapViewNativeComponent.ts @@ -0,0 +1,63 @@ +import type { HostComponent, ViewProps } from 'react-native'; +import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent'; +import { + WithDefault, + DirectEventHandler, + Int32, +} from 'react-native/Libraries/Types/CodegenTypes'; + +import type { UnsafeMixed } from './codegenUtils'; + +type OnCameraChangedEventType = { type: string; payload: string }; +type OnPressEventType = { type: string; payload: string }; +type OnMapChangeEventType = { type: string; payload: string }; + +type Point = { + x: Int32; + y: Int32; +}; + +type LocalizeLabels = { + locale: string; + layerIds?: string[]; +}; + +export interface NativeProps extends ViewProps { + onCameraChanged?: DirectEventHandler; + + attributionEnabled?: boolean; + attributionPosition?: UnsafeMixed; + + logoEnabled?: boolean; + logoPosition?: UnsafeMixed; + + compassEnabled?: boolean; + compassFadeWhenNorth?: boolean; + compassPosition?: UnsafeMixed; + compassViewPosition?: Int32; + compassViewMargins?: Point; + compassImage?: string; + + scaleBarEnabled?: boolean; + scaleBarPosition?: UnsafeMixed; + + zoomEnabled?: boolean; + scrollEnabled?: boolean; + rotateEnabled?: boolean; + pitchEnabled?: boolean; + + requestDisallowInterceptTouchEvent?: boolean; + + projection?: WithDefault<'mercator' | 'globe', 'mercator'>; + localizeLabels?: LocalizeLabels; + + styleURL?: string; + + onPress?: DirectEventHandler; + onLongPress?: DirectEventHandler; + onMapChange?: DirectEventHandler; +} + +export default codegenNativeComponent('MBXAndroidTextureMapView', { + excludedPlatforms: ['iOS'], +}) as HostComponent; From 55a11e840983db3ad5bee0070159ec584f0e89a1 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Mon, 4 Sep 2023 15:54:09 +0200 Subject: [PATCH 29/33] Support old architecture on Android --- android/build.gradle | 8 ++ .../components/mapview/NativeMapViewModule.kt | 10 ++- ...XAndroidTextureMapViewManagerDelegate.java | 89 +++++++++++++++++++ ...AndroidTextureMapViewManagerInterface.java | 37 ++++++++ .../MBXMapViewManagerDelegate.java | 89 +++++++++++++++++++ .../MBXMapViewManagerInterface.java | 37 ++++++++ .../rctmgl/NativeMapViewModuleSpec.java | 88 ++++++++++++++++++ 7 files changed, 355 insertions(+), 3 deletions(-) create mode 100644 android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerDelegate.java create mode 100644 android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerInterface.java create mode 100644 android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerDelegate.java create mode 100644 android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerInterface.java create mode 100644 android/src/main/old-arch/com/mapbox/rctmgl/NativeMapViewModuleSpec.java diff --git a/android/build.gradle b/android/build.gradle index 3c0a15d45..9e673056b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -79,6 +79,14 @@ android { throw new GradleException(msg) } + if (!isNewArchitectureEnabled()) { + sourceSets { + main { + java.srcDirs += 'src/main/old-arch' + } + } + } + compileSdkVersion safeExtGet("compileSdkVersion", 28) buildToolsVersion safeExtGet("buildToolsVersion", '28.0.3') diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt index 79b8e60d1..12a9da669 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/NativeMapViewModule.kt @@ -5,9 +5,9 @@ import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.WritableMap import com.facebook.react.bridge.WritableNativeMap -import com.facebook.react.fabric.FabricUIManager import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.common.UIManagerType +import com.mapbox.rctmgl.BuildConfig import com.mapbox.rctmgl.NativeMapViewModuleSpec import com.mapbox.rctmgl.utils.ConvertUtils import com.mapbox.rctmgl.utils.ExpressionParser @@ -21,8 +21,12 @@ class NativeMapViewModule(context: ReactApplicationContext) : NativeMapViewModul } reactApplicationContext.runOnUiQueueThread { - val manager = UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) as FabricUIManager - val view = manager.resolveView(viewRef.toInt()) as? RCTMGLMapView + val manager = if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) + UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.FABRIC) + else + UIManagerHelper.getUIManager(reactApplicationContext, UIManagerType.DEFAULT) + + val view = manager?.resolveView(viewRef.toInt()) as? RCTMGLMapView if (view != null) { fn(view) diff --git a/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerDelegate.java b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerDelegate.java new file mode 100644 index 000000000..568a3d2ce --- /dev/null +++ b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerDelegate.java @@ -0,0 +1,89 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* This file should be updated after modifying `MBXAndroidTextureMapViewNativeComponent.ts`. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.DynamicFromObject; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.BaseViewManagerInterface; + +public class MBXAndroidTextureMapViewManagerDelegate & MBXAndroidTextureMapViewManagerInterface> extends BaseViewManagerDelegate { + public MBXAndroidTextureMapViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "attributionEnabled": + mViewManager.setAttributionEnabled(view, value == null ? false : (boolean) value); + break; + case "attributionPosition": + mViewManager.setAttributionPosition(view, new DynamicFromObject(value)); + break; + case "logoEnabled": + mViewManager.setLogoEnabled(view, value == null ? false : (boolean) value); + break; + case "logoPosition": + mViewManager.setLogoPosition(view, new DynamicFromObject(value)); + break; + case "compassEnabled": + mViewManager.setCompassEnabled(view, value == null ? false : (boolean) value); + break; + case "compassFadeWhenNorth": + mViewManager.setCompassFadeWhenNorth(view, value == null ? false : (boolean) value); + break; + case "compassPosition": + mViewManager.setCompassPosition(view, new DynamicFromObject(value)); + break; + case "compassViewPosition": + mViewManager.setCompassViewPosition(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "compassViewMargins": + mViewManager.setCompassViewMargins(view, (ReadableMap) value); + break; + case "compassImage": + mViewManager.setCompassImage(view, value == null ? null : (String) value); + break; + case "scaleBarEnabled": + mViewManager.setScaleBarEnabled(view, value == null ? false : (boolean) value); + break; + case "scaleBarPosition": + mViewManager.setScaleBarPosition(view, new DynamicFromObject(value)); + break; + case "zoomEnabled": + mViewManager.setZoomEnabled(view, value == null ? false : (boolean) value); + break; + case "scrollEnabled": + mViewManager.setScrollEnabled(view, value == null ? false : (boolean) value); + break; + case "rotateEnabled": + mViewManager.setRotateEnabled(view, value == null ? false : (boolean) value); + break; + case "pitchEnabled": + mViewManager.setPitchEnabled(view, value == null ? false : (boolean) value); + break; + case "requestDisallowInterceptTouchEvent": + mViewManager.setRequestDisallowInterceptTouchEvent(view, value == null ? false : (boolean) value); + break; + case "projection": + mViewManager.setProjection(view, (String) value); + break; + case "localizeLabels": + mViewManager.setLocalizeLabels(view, (ReadableMap) value); + break; + case "styleURL": + mViewManager.setStyleURL(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerInterface.java b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerInterface.java new file mode 100644 index 000000000..17b387be1 --- /dev/null +++ b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXAndroidTextureMapViewManagerInterface.java @@ -0,0 +1,37 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* This file should be updated after modifying `MBXAndroidTextureMapViewNativeComponent.ts`. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.Dynamic; +import com.facebook.react.bridge.ReadableMap; + +public interface MBXAndroidTextureMapViewManagerInterface { + void setAttributionEnabled(T view, boolean value); + void setAttributionPosition(T view, Dynamic value); + void setLogoEnabled(T view, boolean value); + void setLogoPosition(T view, Dynamic value); + void setCompassEnabled(T view, boolean value); + void setCompassFadeWhenNorth(T view, boolean value); + void setCompassPosition(T view, Dynamic value); + void setCompassViewPosition(T view, int value); + void setCompassViewMargins(T view, @Nullable ReadableMap value); + void setCompassImage(T view, @Nullable String value); + void setScaleBarEnabled(T view, boolean value); + void setScaleBarPosition(T view, Dynamic value); + void setZoomEnabled(T view, boolean value); + void setScrollEnabled(T view, boolean value); + void setRotateEnabled(T view, boolean value); + void setPitchEnabled(T view, boolean value); + void setRequestDisallowInterceptTouchEvent(T view, boolean value); + void setProjection(T view, @Nullable String value); + void setLocalizeLabels(T view, @Nullable ReadableMap value); + void setStyleURL(T view, @Nullable String value); +} diff --git a/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerDelegate.java b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerDelegate.java new file mode 100644 index 000000000..2b081b1eb --- /dev/null +++ b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerDelegate.java @@ -0,0 +1,89 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* This file should be updated after modifying `MBXMapViewNativeComponent.ts`. +* +* @generated by codegen project: GeneratePropsJavaDelegate.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.DynamicFromObject; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.uimanager.BaseViewManagerDelegate; +import com.facebook.react.uimanager.BaseViewManagerInterface; + +public class MBXMapViewManagerDelegate & MBXMapViewManagerInterface> extends BaseViewManagerDelegate { + public MBXMapViewManagerDelegate(U viewManager) { + super(viewManager); + } + @Override + public void setProperty(T view, String propName, @Nullable Object value) { + switch (propName) { + case "attributionEnabled": + mViewManager.setAttributionEnabled(view, value == null ? false : (boolean) value); + break; + case "attributionPosition": + mViewManager.setAttributionPosition(view, new DynamicFromObject(value)); + break; + case "logoEnabled": + mViewManager.setLogoEnabled(view, value == null ? false : (boolean) value); + break; + case "logoPosition": + mViewManager.setLogoPosition(view, new DynamicFromObject(value)); + break; + case "compassEnabled": + mViewManager.setCompassEnabled(view, value == null ? false : (boolean) value); + break; + case "compassFadeWhenNorth": + mViewManager.setCompassFadeWhenNorth(view, value == null ? false : (boolean) value); + break; + case "compassPosition": + mViewManager.setCompassPosition(view, new DynamicFromObject(value)); + break; + case "compassViewPosition": + mViewManager.setCompassViewPosition(view, value == null ? 0 : ((Double) value).intValue()); + break; + case "compassViewMargins": + mViewManager.setCompassViewMargins(view, (ReadableMap) value); + break; + case "compassImage": + mViewManager.setCompassImage(view, value == null ? null : (String) value); + break; + case "scaleBarEnabled": + mViewManager.setScaleBarEnabled(view, value == null ? false : (boolean) value); + break; + case "scaleBarPosition": + mViewManager.setScaleBarPosition(view, new DynamicFromObject(value)); + break; + case "zoomEnabled": + mViewManager.setZoomEnabled(view, value == null ? false : (boolean) value); + break; + case "scrollEnabled": + mViewManager.setScrollEnabled(view, value == null ? false : (boolean) value); + break; + case "rotateEnabled": + mViewManager.setRotateEnabled(view, value == null ? false : (boolean) value); + break; + case "pitchEnabled": + mViewManager.setPitchEnabled(view, value == null ? false : (boolean) value); + break; + case "requestDisallowInterceptTouchEvent": + mViewManager.setRequestDisallowInterceptTouchEvent(view, value == null ? false : (boolean) value); + break; + case "projection": + mViewManager.setProjection(view, (String) value); + break; + case "localizeLabels": + mViewManager.setLocalizeLabels(view, (ReadableMap) value); + break; + case "styleURL": + mViewManager.setStyleURL(view, value == null ? null : (String) value); + break; + default: + super.setProperty(view, propName, value); + } + } +} diff --git a/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerInterface.java b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerInterface.java new file mode 100644 index 000000000..b366be9f3 --- /dev/null +++ b/android/src/main/old-arch/com/facebook/react/viewmanagers/MBXMapViewManagerInterface.java @@ -0,0 +1,37 @@ +/** +* This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). +* +* This file should be updated after modifying `MBXMapViewNativeComponent.ts`. +* +* @generated by codegen project: GeneratePropsJavaInterface.js +*/ + +package com.facebook.react.viewmanagers; + +import android.view.View; +import androidx.annotation.Nullable; +import com.facebook.react.bridge.Dynamic; +import com.facebook.react.bridge.ReadableMap; + +public interface MBXMapViewManagerInterface { + void setAttributionEnabled(T view, boolean value); + void setAttributionPosition(T view, Dynamic value); + void setLogoEnabled(T view, boolean value); + void setLogoPosition(T view, Dynamic value); + void setCompassEnabled(T view, boolean value); + void setCompassFadeWhenNorth(T view, boolean value); + void setCompassPosition(T view, Dynamic value); + void setCompassViewPosition(T view, int value); + void setCompassViewMargins(T view, @Nullable ReadableMap value); + void setCompassImage(T view, @Nullable String value); + void setScaleBarEnabled(T view, boolean value); + void setScaleBarPosition(T view, Dynamic value); + void setZoomEnabled(T view, boolean value); + void setScrollEnabled(T view, boolean value); + void setRotateEnabled(T view, boolean value); + void setPitchEnabled(T view, boolean value); + void setRequestDisallowInterceptTouchEvent(T view, boolean value); + void setProjection(T view, @Nullable String value); + void setLocalizeLabels(T view, @Nullable ReadableMap value); + void setStyleURL(T view, @Nullable String value); +} diff --git a/android/src/main/old-arch/com/mapbox/rctmgl/NativeMapViewModuleSpec.java b/android/src/main/old-arch/com/mapbox/rctmgl/NativeMapViewModuleSpec.java new file mode 100644 index 000000000..f6f593df1 --- /dev/null +++ b/android/src/main/old-arch/com/mapbox/rctmgl/NativeMapViewModuleSpec.java @@ -0,0 +1,88 @@ + +/** + * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen). + * +* This file should be updated after modifying `NativeMapViewModule.ts`. + * + * @generated by codegen project: GenerateModuleJavaSpec.js + * + * @nolint + */ + +package com.mapbox.rctmgl; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReactModuleWithSpec; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class NativeMapViewModuleSpec extends ReactContextBaseJavaModule implements ReactModuleWithSpec, TurboModule { + public static final String NAME = "MBXMapViewModule"; + + public NativeMapViewModuleSpec(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public @Nonnull String getName() { + return NAME; + } + + @ReactMethod + @DoNotStrip + public abstract void takeSnap(@Nullable Double viewRef, boolean writeToDisk, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void queryTerrainElevation(@Nullable Double viewRef, ReadableArray coordinates, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void setSourceVisibility(@Nullable Double viewRef, boolean visible, String sourceId, String sourceLayerId, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getCenter(@Nullable Double viewRef, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getCoordinateFromView(@Nullable Double viewRef, ReadableArray atPoint, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getPointInView(@Nullable Double viewRef, ReadableArray atCoordinate, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getZoom(@Nullable Double viewRef, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void getVisibleBounds(@Nullable Double viewRef, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void queryRenderedFeaturesAtPoint(@Nullable Double viewRef, ReadableArray atPoint, ReadableArray withFilter, ReadableArray withLayerIDs, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void queryRenderedFeaturesInRect(@Nullable Double viewRef, ReadableArray withBBox, ReadableArray withFilter, ReadableArray withLayerIDs, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void setHandledMapChangedEvents(@Nullable Double viewRef, ReadableArray events, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void clearData(@Nullable Double viewRef, Promise promise); + + @ReactMethod + @DoNotStrip + public abstract void querySourceFeatures(@Nullable Double viewRef, String sourceId, ReadableArray withFilter, ReadableArray withSourceLayerIDs, Promise promise); +} From 174ebcc109068431a8a6917b3f8632c9b62e7f42 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Tue, 5 Sep 2023 15:31:51 +0200 Subject: [PATCH 30/33] feat: simpler new arch interoop --- ios/RCTMGL-v10/Bridge/RCTMGL.h | 1 - ios/RCTMGL-v10/MBXMapView.h | 50 ---- ios/RCTMGL-v10/MBXMapView.swift | 217 ---------------- ios/RCTMGL-v10/MBXMapViewComponentView.mm | 150 ++++------- ios/RCTMGL-v10/MBXMapViewManager.m | 70 ----- ios/RCTMGL-v10/MBXMapViewManager.swift | 299 ++++++---------------- ios/RCTMGL-v10/MBXMapViewModule.mm | 73 +++--- ios/RCTMGL-v10/RCTMGLMapView.swift | 50 ++-- src/components/MapView.tsx | 36 +-- src/specs/NativeMapViewModule.ts | 2 +- 10 files changed, 209 insertions(+), 739 deletions(-) delete mode 100644 ios/RCTMGL-v10/MBXMapView.h delete mode 100644 ios/RCTMGL-v10/MBXMapView.swift diff --git a/ios/RCTMGL-v10/Bridge/RCTMGL.h b/ios/RCTMGL-v10/Bridge/RCTMGL.h index 057763926..56185b970 100644 --- a/ios/RCTMGL-v10/Bridge/RCTMGL.h +++ b/ios/RCTMGL-v10/Bridge/RCTMGL.h @@ -5,4 +5,3 @@ #import #import "RCTSwiftLog.h" -#import "MBXMapView.h" diff --git a/ios/RCTMGL-v10/MBXMapView.h b/ios/RCTMGL-v10/MBXMapView.h deleted file mode 100644 index 21899dc9f..000000000 --- a/ios/RCTMGL-v10/MBXMapView.h +++ /dev/null @@ -1,50 +0,0 @@ -#import - -@protocol MBXMapViewProtocol -- (void)setAttributionEnabled:(BOOL)enabled; -- (void)setAttributionPosition:(NSDictionary*)position; -- (void)setLogoEnabled:(BOOL)enabled; -- (void)setLogoPosition:(NSDictionary*)position; - -- (void)setCompassEnabled:(BOOL)enabled; -- (void)setCompassFadeWhenNorth:(BOOL)enabled; -- (void)setCompassPosition:(NSDictionary*)position; -- (void)setCompassViewPosition:(NSInteger)position; -- (void)setCompassViewMargins:(CGPoint)position; -- (void)setCompassImage:(NSString*)position; - -- (void)setScaleBarEnabled:(BOOL)enabled; -- (void)setScaleBarPosition:(NSDictionary*)position; - -- (void)setZoomEnabled:(BOOL)enabled; -- (void)setScrollEnabled:(BOOL)enabled; -- (void)setRotateEnabled:(BOOL)enabled; -- (void)setPitchEnabled:(BOOL)enabled; - -- (void)setProjection:(NSString*)projection; -- (void)setLocalizeLabels:(NSDictionary*)labels; -- (void)setStyleUrl:(NSString*)url; - -- (void)setOnPress:(RCTBubblingEventBlock)callback; -- (void)setOnLongPress:(RCTBubblingEventBlock)callback; -- (void)setOnMapChange:(RCTBubblingEventBlock)callback; - -- (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve; -- (void)clearData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getCenter:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getCoordinateFromView:(CGPoint)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getPointInView:(NSArray*)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getVisibleBounds:(RCTPromiseResolveBlock)resolve; -- (void)getZoom:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)queryRenderedFeaturesAtPoint:(NSArray*)point withFilter:(NSArray* _Nullable)filter withLayerIDs:(NSArray* _Nullable)layerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; -- (void)queryRenderedFeaturesInRect:(NSArray* _Nonnull)bbox withFilter:(NSArray* _Nullable)filter withLayerIDs:(NSArray* _Nullable)layerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; -- (void)queryTerrainElevation:(NSArray* _Nonnull)coordinates resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; -- (void)setHandledMapChangedEvents:(NSArray* _Nonnull)events resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; -- (void)setSourceVisibility:(BOOL)visible sourceId:(NSString* _Nonnull)sourceId sourceLayerId:(NSString* _Nullable)sourceLayerId resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; -- (void)querySourceFeatures:(NSString* _Nonnull)sourceId withFilter:(NSArray* _Nullable)filter withSourceLayerIDs:(NSArray* _Nullable)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; - -@end - -@interface MBXMapViewFactory -+ (UIView*)createWithFrame:(CGRect)frame eventDispatcher:(id)eventDispatcher NS_SWIFT_NAME(create(frame:eventDispatcher:)); -@end diff --git a/ios/RCTMGL-v10/MBXMapView.swift b/ios/RCTMGL-v10/MBXMapView.swift deleted file mode 100644 index 88eb5ceb8..000000000 --- a/ios/RCTMGL-v10/MBXMapView.swift +++ /dev/null @@ -1,217 +0,0 @@ -import MapboxMaps - -@objc(MBXMapView) -open class MBXMapView : RCTMGLMapView, MBXMapViewProtocol { - required public init(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) { - super.init(frame: frame, eventDispatcher: eventDispatcher) - } - - public required init(coder: NSCoder) { - super .init(coder: coder) - } - - public func setAttributionEnabled(_ enabled: Bool) { - self.setReactAttributionEnabled(enabled) - } - - public func setAttributionPosition(_ position: [String : NSNumber]!) { - self.setReactAttributionPosition(position) - } - - public func setLogoEnabled(_ enabled: Bool) { - self.setReactLogoEnabled(enabled) - } - - public func setLogoPosition(_ position: [String : NSNumber]!) { - self.setReactLogoPosition(position) - } - - public func setCompassEnabled(_ enabled: Bool) { - self.setReactCompassEnabled(enabled) - } - - public func setCompassFadeWhenNorth(_ enabled: Bool) { - self.setReactCompassFadeWhenNorth(enabled) - } - - public func setCompassPosition(_ position: [String : NSNumber]!) { - self.setReactCompassPosition(position) - } - - public func setCompassViewPosition(_ position: NSInteger) { - self.setReactCompassViewPosition(position) - } - - public func setCompassViewMargins(_ margins: CGPoint) { - self.setReactCompassViewMargins(margins) - } - - public func setCompassImage(_ position: String) { - self.setReactCompassImage(position) - } - - public func setScaleBarEnabled(_ enabled: Bool) { - self.setReactScaleBarEnabled(enabled) - } - - public func setScaleBarPosition(_ position: [String : NSNumber]!) { - self.setReactScaleBarPosition(position) - } - - public func setZoomEnabled(_ enabled: Bool) { - self.setReactZoomEnabled(enabled) - } - - public func setRotateEnabled(_ enabled: Bool) { - self.setReactRotateEnabled(enabled) - } - - public func setScrollEnabled(_ enabled: Bool) { - self.setReactScrollEnabled(enabled) - } - - public func setPitchEnabled(_ enabled: Bool) { - self.setReactPitchEnabled(enabled) - } - - public func setProjection(_ projection: String) { - self.setReactProjection(projection) - } - - public func setLocalizeLabels(_ labels: [AnyHashable : Any]) { - self.setReactLocalizeLabels(labels as NSDictionary) - } - - public func setStyleUrl(_ url: String) { - self.setReactStyleURL(url) - } - - public func setOnPress(_ callback: @escaping RCTBubblingEventBlock) { - self.setReactOnPress(callback) - } - - public func setOnLongPress(_ callback: @escaping RCTBubblingEventBlock) { - self.setReactOnLongPress(callback) - } - - public func setOnMapChange(_ callback: @escaping RCTBubblingEventBlock) { - self.setReactOnMapChange(callback) - } - - - private func withMapboxMap( - name: String, - rejecter: @escaping RCTPromiseRejectBlock, - fn: @escaping (_: MapboxMap) -> Void) -> Void - { - guard let mapboxMap = self.mapboxMap else { - RCTMGLLogError("MapboxMap is not yet available"); - rejecter(name, "Map not loaded yet", nil) - return; - } - - fn(mapboxMap) - } - - public func takeSnap(_ writeToDisk: Bool, resolve: RCTPromiseResolveBlock!) { - MBXMapViewManager.takeSnap(self, writeToDisk: writeToDisk, resolver: resolve) - } - - public func clearData(_ resolve: RCTPromiseResolveBlock!, reject: RCTPromiseRejectBlock!) { - MBXMapViewManager.clearData(self, resolver: resolve, rejecter: reject) - } - - public func getCenter(_ resolve: RCTPromiseResolveBlock!, reject: RCTPromiseRejectBlock!) { - withMapboxMap(name: "getCenter", rejecter: reject) { map in - MBXMapViewManager.getCenter(map, resolver: resolve) - } - } - - public func getCoordinateFromView(_ point: CGPoint, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { - withMapboxMap(name: "getCoordinateFromView", rejecter: reject) { map in - MBXMapViewManager.getCoordinateFromView(map, atPoint: point, resolver: resolve) - } - } - - public func getPointInView(_ coordinate: [NSNumber], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { - withMapboxMap(name: "getPointInView", rejecter: reject) { map in - MBXMapViewManager.getPointInView(map, atCoordinate: coordinate, resolver: resolve) - } - } - - public func getVisibleBounds(_ resolve: RCTPromiseResolveBlock!) { - MBXMapViewManager.getVisibleBounds(self, resolver: resolve) - } - - public func getZoom(_ resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { - withMapboxMap(name: "getZoom", rejecter: reject) { map in - MBXMapViewManager.getZoom(map, resolver: resolve) - } - } - - public func queryRenderedFeatures( - atPoint point: [NSNumber], - withFilter filter: [Any]?, - withLayerIDs layerIDs: [String]?, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - withMapboxMap(name: "queryRenderedFeaturesAtPoint", rejecter: reject) { map in - MBXMapViewManager.queryRenderedFeaturesAtPoint(map, atPoint: point, withFilter: filter, withLayerIDs: layerIDs, resolver: resolve, rejecter: reject) - } - } - - public func queryRenderedFeatures( - inRect bbox: [NSNumber], - withFilter filter: [Any]?, - withLayerIDs layerIDs: [String]?, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - MBXMapViewManager.queryRenderedFeaturesInRect(self, withBBox: bbox, withFilter: filter, withLayerIDs: layerIDs, resolver: resolve, rejecter: reject) - } - - public func queryTerrainElevation( - _ coordinates: [NSNumber], - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock - ) { - MBXMapViewManager.queryTerrainElevation(self, coordinates: coordinates, resolver: resolve, rejecter: reject) - } - - public func setHandledMapChangedEvents( - _ events: [String], - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - MBXMapViewManager.setHandledMapChangedEvents(self, events: events, resolver: resolve, rejecter: reject) - } - - public func setSourceVisibility( - _ visible: Bool, - sourceId: String, - sourceLayerId: String?, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) { - MBXMapViewManager.setSourceVisibility(self, visible: visible, sourceId: sourceId, sourceLayerId: sourceLayerId, resolver: resolve, rejecter: reject) - } - - public func querySourceFeatures( - _ sourceId: String, - withFilter filter: [Any]?, - withSourceLayerIDs sourceLayerIds: [String]?, - resolve: @escaping RCTPromiseResolveBlock, - reject: @escaping RCTPromiseRejectBlock) -> Void { - MBXMapViewManager.querySourceFeatures(self, withSourceId: sourceId, withFilter: filter, withSourceLayerIds: sourceLayerIds, resolver: resolve, rejecter: reject) - } -} - -@objc(MBXMapViewFactory) -open class MBXMapViewFactory : NSObject { - @objc - static func create(frame: CGRect, eventDispatcher: RCTEventDispatcherProtocol) -> MBXMapViewProtocol { - let view = MBXMapView(frame: frame, eventDispatcher: eventDispatcher) - - // just need to pass something, it won't really be used on fabric, but it's used to create events (it won't impact sending them) - view.reactTag = -1; - - return view - } -} diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index a072736f2..1fbcf3137 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -9,8 +9,14 @@ #import #import #import +// needed for compilation for some reason +#import +#import -#import "MBXMapView.h" +@interface MapView : UIView +@end + +#import using namespace facebook::react; @@ -40,7 +46,7 @@ - (void)sendEvent:(id)event { @end @implementation MBXMapViewComponentView { - UIView *_view; + MBXMapView *_view; MBXMapViewEventDispatcher *_eventDispatcher; } @@ -50,32 +56,32 @@ - (instancetype)initWithFrame:(CGRect)frame static const auto defaultProps = std::make_shared(); _props = defaultProps; _eventDispatcher = [[MBXMapViewEventDispatcher alloc] initWithComponentView:self]; - _view = [MBXMapViewFactory createWithFrame:frame eventDispatcher:_eventDispatcher]; + _view = [[MBXMapView alloc] initWithFrame:frame eventDispatcher:_eventDispatcher]; // capture weak self reference to prevent retain cycle __weak __typeof__(self) weakSelf = self; - [_view setOnPress:^(NSDictionary* event) { + [_view setReactOnPress:^(NSDictionary* event) { __typeof__(self) strongSelf = weakSelf; - + if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onPress({type, json}); } }]; - - [_view setOnLongPress:^(NSDictionary* event) { + + [_view setReactOnLongPress:^(NSDictionary* event) { __typeof__(self) strongSelf = weakSelf; - + if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onLongPress({type, json}); } }]; - - [_view setOnMapChange:^(NSDictionary* event) { + + [_view setReactOnMapChange:^(NSDictionary* event) { __typeof__(self) strongSelf = weakSelf; - + if (strongSelf != nullptr && strongSelf->_eventEmitter != nullptr) { const auto [type, json] = [MBXMapViewComponentView stringifyEventData:event]; std::dynamic_pointer_cast(strongSelf->_eventEmitter)->onMapChange({type, json}); @@ -96,26 +102,26 @@ - (void)dispatchCameraChangedEvent:(NSDictionary*)event { + (std::tuple)stringifyEventData:(NSDictionary*)event { std::string type = [event valueForKey:@"type"] == nil ? "" : std::string([[event valueForKey:@"type"] UTF8String]); std::string json = "{}"; - + NSError *error; NSData *jsonData = nil; - + if ([event valueForKey:@"payload"] != nil) { jsonData = [NSJSONSerialization dataWithJSONObject:[event valueForKey:@"payload"] options:0 error:&error]; } - + if (jsonData) { json = std::string([[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] UTF8String]); } - + return {type, json}; } - (NSDictionary*)convertPositionToDictionary:(const folly::dynamic*)position { NSMutableDictionary* result = [[NSMutableDictionary alloc] init]; - + if (!position->isNull()) { for (auto& pair : position->items()) { NSString* key = [NSString stringWithUTF8String:pair.first.getString().c_str()]; @@ -123,76 +129,24 @@ - (NSDictionary*)convertPositionToDictionary:(const folly::dynamic*)position { [result setValue:value forKey:key]; } } - + return result; } - (NSDictionary*)convertLocalizeLabels:(const MBXMapViewLocalizeLabelsStruct*)labels { NSMutableDictionary* result = [[NSMutableDictionary alloc] init]; NSMutableArray* ids = [[NSMutableArray alloc] init]; - + [result setValue:[NSString stringWithUTF8String:labels->locale.c_str()] forKey:@"locale"]; - + for (auto& layerId : labels->layerIds) { NSString* value = [NSString stringWithUTF8String:layerId.c_str()]; [ids addObject:value]; } - - [result setValue:ids forKey:@"layerIds"]; - - return result; -} - -- (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve { - [_view takeSnap:writeToDisk resolve:resolve]; -} - -- (void)clearData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view clearData:resolve reject:reject]; -} - -- (void)getCenter:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view getCenter:resolve reject:reject]; -} -- (void)getCoordinateFromView:(CGPoint)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view getCoordinateFromView:point resolve:resolve reject:reject]; -} - -- (void)getPointInView:(NSArray*)coordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view getPointInView:coordinate resolve:resolve reject:reject]; -} - -- (void)getVisibleBounds:(RCTPromiseResolveBlock)resolve { - [_view getVisibleBounds:resolve]; -} - -- (void)getZoom:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view getZoom:resolve reject:reject]; -} - -- (void)queryRenderedFeaturesAtPoint:(NSArray*)point withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view queryRenderedFeaturesAtPoint:point withFilter:filter withLayerIDs:layerIDs resolve:resolve reject:reject]; -} - -- (void)queryRenderedFeaturesInRect:(NSArray*)bbox withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view queryRenderedFeaturesInRect:bbox withFilter:filter withLayerIDs:layerIDs resolve:resolve reject:reject]; -} - -- (void)queryTerrainElevation:(NSArray*)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view queryTerrainElevation:coordinates resolve:resolve reject:reject]; -} - -- (void)setHandledMapChangedEvents:(NSArray*)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view setHandledMapChangedEvents:events resolve:resolve reject:reject]; -} - -- (void)setSourceVisibility:(BOOL)visible sourceId:(NSString*)sourceId sourceLayerId:(NSString*)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; -} + [result setValue:ids forKey:@"layerIds"]; -- (void)querySourceFeatures:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { - [_view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; + return result; } @@ -206,32 +160,32 @@ + (ComponentDescriptorProvider)componentDescriptorProvider - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps { const auto &newProps = *std::static_pointer_cast(props); - [_view setAttributionEnabled:newProps.attributionEnabled]; - [_view setAttributionPosition:[self convertPositionToDictionary:&newProps.attributionPosition]]; - - [_view setLogoEnabled:newProps.logoEnabled]; - [_view setLogoPosition:[self convertPositionToDictionary:&newProps.logoPosition]]; - - [_view setCompassEnabled:newProps.compassEnabled]; - [_view setCompassFadeWhenNorth:newProps.compassFadeWhenNorth]; - [_view setCompassPosition:[self convertPositionToDictionary:&newProps.compassPosition]]; - [_view setCompassViewPosition:newProps.compassViewPosition]; - [_view setCompassViewMargins:CGPointMake(newProps.compassViewMargins.x, newProps.compassViewMargins.y)]; - [_view setCompassImage:[NSString stringWithUTF8String:newProps.compassImage.c_str()]]; - - [_view setScaleBarEnabled:newProps.scaleBarEnabled]; - [_view setScaleBarPosition:[self convertPositionToDictionary:&newProps.scaleBarPosition]]; - - [_view setZoomEnabled:newProps.zoomEnabled]; - [_view setScrollEnabled:newProps.scrollEnabled]; - [_view setRotateEnabled:newProps.rotateEnabled]; - [_view setPitchEnabled:newProps.pitchEnabled]; - - [_view setProjection:newProps.projection == MBXMapViewProjection::Mercator ? @"mercator" : @"globe"]; - [_view setStyleUrl:[NSString stringWithUTF8String:newProps.styleURL.c_str()]]; - + [_view setReactAttributionEnabled:newProps.attributionEnabled]; + [_view setReactAttributionPosition:[self convertPositionToDictionary:&newProps.attributionPosition]]; + + [_view setReactLogoEnabled:newProps.logoEnabled]; + [_view setReactLogoPosition:[self convertPositionToDictionary:&newProps.logoPosition]]; + + [_view setReactCompassEnabled:newProps.compassEnabled]; + [_view setReactCompassFadeWhenNorth:newProps.compassFadeWhenNorth]; + [_view setReactCompassPosition:[self convertPositionToDictionary:&newProps.compassPosition]]; + [_view setReactCompassViewPosition:newProps.compassViewPosition]; + [_view setReactCompassViewMargins:CGPointMake(newProps.compassViewMargins.x, newProps.compassViewMargins.y)]; + [_view setReactCompassImage:[NSString stringWithUTF8String:newProps.compassImage.c_str()]]; + + [_view setReactScaleBarEnabled:newProps.scaleBarEnabled]; + [_view setReactScaleBarPosition:[self convertPositionToDictionary:&newProps.scaleBarPosition]]; + + [_view setReactZoomEnabled:newProps.zoomEnabled]; + [_view setReactScrollEnabled:newProps.scrollEnabled]; + [_view setReactRotateEnabled:newProps.rotateEnabled]; + [_view setReactPitchEnabled:newProps.pitchEnabled]; + + [_view setReactProjection:newProps.projection == MBXMapViewProjection::Mercator ? @"mercator" : @"globe"]; + [_view setReactStyleURL:[NSString stringWithUTF8String:newProps.styleURL.c_str()]]; + if (!newProps.localizeLabels.locale.empty()) { - [_view setLocalizeLabels:[self convertLocalizeLabels:&newProps.localizeLabels]]; + [_view setReactLocalizeLabels:[self convertLocalizeLabels:&newProps.localizeLabels]]; } [super updateProps:props oldProps:oldProps]; } diff --git a/ios/RCTMGL-v10/MBXMapViewManager.m b/ios/RCTMGL-v10/MBXMapViewManager.m index e352cc5a5..62f8efe27 100644 --- a/ios/RCTMGL-v10/MBXMapViewManager.m +++ b/ios/RCTMGL-v10/MBXMapViewManager.m @@ -34,74 +34,4 @@ @interface RCT_EXTERN_REMAP_MODULE(MBXMapView, MBXMapViewManager, RCTViewManager RCT_REMAP_VIEW_PROPERTY(onLongPress, reactOnLongPress, RCTBubblingEventBlock) RCT_REMAP_VIEW_PROPERTY(onMapChange, reactOnMapChange, RCTBubblingEventBlock) -RCT_EXTERN_METHOD(takeSnap:(nonnull NSNumber*)reactTag - writeToDisk:(BOOL)writeToDisk - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(queryTerrainElevation:(nonnull NSNumber*)reactTag - coordinates: (nonnull NSArray*)coordinates - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(setSourceVisibility:(nonnull NSNumber *)reactTag - visible:(BOOL)visible - sourceId:(nonnull NSString*)sourceId - sourceLayerId:(nullable NSString*)sourceLayerId - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getCenter:(nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getCoordinateFromView:(nonnull NSNumber*)reactTag - atPoint:(CGPoint)point - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getPointInView:(nonnull NSNumber*)reactTag - atCoordinate:(NSArray*)coordinate - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getZoom:(nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(getVisibleBounds:(nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(queryRenderedFeaturesAtPoint:(nonnull NSNumber*)reactTag - atPoint:(NSArray*)point - withFilter:(NSArray*)filter - withLayerIDs:(NSArray*)layerIDs - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(queryRenderedFeaturesInRect:(nonnull NSNumber*)reactTag - withBBox:(NSArray*)bbox - withFilter:(NSArray*)filter - withLayerIDs:(NSArray*)layerIDs - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(querySourceFeatures:(nonnull NSNumber*)reactTag - withSourceId:(NSString*)sourceId - withFilter:(NSArray)filter - withSourceLayerIds:(NSArray*)sourceLayerIds - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(setHandledMapChangedEvents:(nonnull NSNumber*)reactTag - events:(NSArray*)events - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject) - -RCT_EXTERN_METHOD(clearData: (nonnull NSNumber*)reactTag - resolver:(RCTPromiseResolveBlock)resolve - rejecter:(RCTPromiseRejectBlock)reject - ) - @end diff --git a/ios/RCTMGL-v10/MBXMapViewManager.swift b/ios/RCTMGL-v10/MBXMapViewManager.swift index 95d95e89c..04a4d4abb 100644 --- a/ios/RCTMGL-v10/MBXMapViewManager.swift +++ b/ios/RCTMGL-v10/MBXMapViewManager.swift @@ -1,9 +1,9 @@ import MapboxMaps @objc(MBXMapViewManager) -class MBXMapViewManager: RCTViewManager { +public class MBXMapViewManager: RCTViewManager { @objc - override static func requiresMainQueueSetup() -> Bool { + override public static func requiresMainQueueSetup() -> Bool { return true } @@ -11,8 +11,8 @@ class MBXMapViewManager: RCTViewManager { return UIScreen.main.bounds } - override func view() -> UIView! { - let result = MBXMapView(frame: self.defaultFrame(), eventDispatcher: self.bridge.eventDispatcher()) + override public func view() -> UIView! { + let result = RCTMGLMapView(frame: self.defaultFrame(), eventDispatcher: self.bridge.eventDispatcher()) return result } } @@ -20,32 +20,12 @@ class MBXMapViewManager: RCTViewManager { // MARK: helpers extension MBXMapViewManager { - func withMapView( - _ reactTag: NSNumber, - name: String, - rejecter: @escaping RCTPromiseRejectBlock, - fn: @escaping (_: RCTMGLMapView) -> Void) -> Void - { - self.bridge.uiManager.addUIBlock { (manager, viewRegistry) in - let view = viewRegistry![reactTag] - - guard let view = view, let view = view as? RCTMGLMapView else { - RCTMGLLogError("Invalid react tag, could not find RCTMGLMapView"); - rejecter(name, "Unknown find reactTag: \(reactTag)", nil) - return; - } - - fn(view) - } - } - - func withMapboxMap( - _ reactTag: NSNumber, + static func withMapboxMap( + _ view: RCTMGLMapView, name: String, rejecter: @escaping RCTPromiseRejectBlock, fn: @escaping (_: MapboxMap) -> Void) -> Void { - withMapView(reactTag, name: name, rejecter: rejecter) { view in guard let mapboxMap = view.mapboxMap else { RCTMGLLogError("MapboxMap is not yet available"); rejecter(name, "Map not loaded yet", nil) @@ -53,32 +33,20 @@ extension MBXMapViewManager { } fn(mapboxMap) - } } } // MARK: - react methods extension MBXMapViewManager { - static func takeSnap(_ view: RCTMGLMapView, + @objc public static func takeSnap(_ view: RCTMGLMapView, writeToDisk: Bool, resolver: @escaping RCTPromiseResolveBlock) { let uri = view.takeSnap(writeToDisk: writeToDisk) resolver(["uri": uri.absoluteString]) } - - @objc - func takeSnap(_ reactTag: NSNumber, - writeToDisk: Bool, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock - ) -> Void { - withMapView(reactTag, name:"takeSnap", rejecter: rejecter) { view in - MBXMapViewManager.takeSnap(view, writeToDisk: writeToDisk, resolver: resolver) - } - } - static func queryTerrainElevation(_ view: RCTMGLMapView, + @objc public static func queryTerrainElevation(_ view: RCTMGLMapView, coordinates: [NSNumber], resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock @@ -90,19 +58,8 @@ extension MBXMapViewManager { resolver(nil) } } - - @objc - func queryTerrainElevation(_ reactTag: NSNumber, - coordinates: [NSNumber], - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock - ) -> Void { - withMapView(reactTag, name:"queryTerrainElevation", rejecter: rejecter) { view in - MBXMapViewManager.queryTerrainElevation(view, coordinates: coordinates, resolver: resolver, rejecter: rejecter) - } - } - - static func setSourceVisibility(_ view: RCTMGLMapView, + + @objc public static func setSourceVisibility(_ view: RCTMGLMapView, visible: Bool, sourceId: String, sourceLayerId: String?, @@ -111,75 +68,42 @@ extension MBXMapViewManager { view.setSourceVisibility(visible, sourceId: sourceId, sourceLayerId:sourceLayerId) resolver(nil) } - - @objc - func setSourceVisibility(_ reactTag: NSNumber, - visible: Bool, - sourceId: String, - sourceLayerId: String?, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapView(reactTag, name:"setSourceVisibility", rejecter: rejecter) { view in - MBXMapViewManager.setSourceVisibility(view, visible: visible, sourceId: sourceId, sourceLayerId: sourceLayerId, resolver: resolver, rejecter: rejecter) - } - } - - static func getCenter(_ map: MapboxMap, resolver: @escaping RCTPromiseResolveBlock) { - resolver(["center": [ - map.cameraState.center.longitude, - map.cameraState.center.latitude - ]]) - } - @objc - func getCenter(_ reactTag: NSNumber, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapboxMap(reactTag, name:"getCenter", rejecter: rejecter) { mapboxMap in - MBXMapViewManager.getCenter(mapboxMap, resolver: resolver) + @objc public static func getCenter(_ view: RCTMGLMapView, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) { + withMapboxMap(view, name: "getCenter", rejecter:rejecter) { map in + resolver(["center": [ + map.cameraState.center.longitude, + map.cameraState.center.latitude + ]]) + } } - } - - static func getCoordinateFromView( - _ map: MapboxMap, + + @objc public static func getCoordinateFromView( + _ view: RCTMGLMapView, atPoint point: CGPoint, - resolver: @escaping RCTPromiseResolveBlock) { - let coordinates = map.coordinate(for: point) - resolver(["coordinateFromView": [coordinates.longitude, coordinates.latitude]]) + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) { + withMapboxMap(view, name: "getCoordinateFromView", rejecter:rejecter) { map in + let coordinates = map.coordinate(for: point) + resolver(["coordinateFromView": [coordinates.longitude, coordinates.latitude]]) + } + } - @objc - func getCoordinateFromView( - _ reactTag: NSNumber, - atPoint point: CGPoint, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(reactTag, name:"getCoordinateFromView", rejecter: rejecter) { mapboxMap in - MBXMapViewManager.getCoordinateFromView(mapboxMap, atPoint: point, resolver: resolver) - } - } - - static func getPointInView( - _ map: MapboxMap, + @objc public static func getPointInView( + _ view: RCTMGLMapView, atCoordinate coordinate: [NSNumber], - resolver: @escaping RCTPromiseResolveBlock) { - let coordinate = CLLocationCoordinate2DMake(coordinate[1].doubleValue, coordinate[0].doubleValue) - let point = map.point(for: coordinate) - resolver(["pointInView": [(point.x), (point.y)]]) - } - - @objc - func getPointInView( - _ reactTag: NSNumber, - atCoordinate coordinate: [NSNumber], - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(reactTag, name:"getPointInView", rejecter: rejecter) { mapboxMap in - MBXMapViewManager.getPointInView(mapboxMap, atCoordinate: coordinate, resolver: resolver) + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) { + withMapboxMap(view, name: "getPointInView", rejecter:rejecter) { map in + let coordinate = CLLocationCoordinate2DMake(coordinate[1].doubleValue, coordinate[0].doubleValue) + let point = map.point(for: coordinate) + resolver(["pointInView": [(point.x), (point.y)]]) + } + } - } - static func setHandledMapChangedEvents( + @objc public static func setHandledMapChangedEvents( _ view: RCTMGLMapView, events: [String], resolver: @escaping RCTPromiseResolveBlock, @@ -189,95 +113,59 @@ extension MBXMapViewManager { }) resolver(nil); } - - @objc - func setHandledMapChangedEvents( - _ reactTag: NSNumber, - events: [String], - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) { - withMapView(reactTag, name:"setHandledMapChangedEvents", rejecter: rejecter) { mapView in - MBXMapViewManager.setHandledMapChangedEvents(mapView, events: events, resolver: resolver, rejecter: rejecter) - } - } - - static func getZoom( - _ map: MapboxMap, - resolver: @escaping RCTPromiseResolveBlock) { - resolver(["zoom": map.cameraState.zoom]) - } - @objc - func getZoom( - _ reactTag: NSNumber, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) { - withMapboxMap(reactTag, name:"getZoom", rejecter: rejecter) { mapboxMap in - MBXMapViewManager.getZoom(mapboxMap, resolver: resolver) - } - } + @objc public static func getZoom( + _ view: RCTMGLMapView, + resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock) { + withMapboxMap(view, name: "getZoom", rejecter:rejecter) { map in + resolver(["zoom": map.cameraState.zoom]) + } + + } - static func getVisibleBounds( + @objc public static func getVisibleBounds( _ view: RCTMGLMapView, resolver: @escaping RCTPromiseResolveBlock) { resolver(["visibleBounds": view.mapboxMap.coordinateBounds(for: view.bounds).toArray()]) } - - @objc - func getVisibleBounds( - _ reactTag: NSNumber, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) { - withMapView(reactTag, name:"getVisibleBounds", rejecter: rejecter) { mapView in - MBXMapViewManager.getVisibleBounds(mapView, resolver: resolver) - } - } + } // MARK: - queryRenderedFeatures extension MBXMapViewManager { - static func queryRenderedFeaturesAtPoint( - _ map: MapboxMap, + @objc public static func queryRenderedFeaturesAtPoint( + _ view: RCTMGLMapView, atPoint point: [NSNumber], withFilter filter: [Any]?, withLayerIDs layerIDs: [String]?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) -> Void { - let point = CGPoint(x: CGFloat(point[0].floatValue), y: CGFloat(point[1].floatValue)) - - logged("queryRenderedFeaturesAtPoint.option", rejecter: rejecter) { - let options = try RenderedQueryOptions(layerIds: (layerIDs ?? []).isEmpty ? nil : layerIDs, filter: filter?.asExpression()) - - map.queryRenderedFeatures(with: point, options: options) { result in - switch result { - case .success(let features): - resolver([ - "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in - logged("queryRenderedFeaturesAtPoint.feature.toJSON") { try queriedFeature.feature.toJSON() } - }] - ]) - case .failure(let error): - rejecter("queryRenderedFeaturesAtPoint","failed to query features", error) - } - } + withMapboxMap(view, name: "queryRenderedFeaturesAtPoint", rejecter:rejecter) { map in + let point = CGPoint(x: CGFloat(point[0].floatValue), y: CGFloat(point[1].floatValue)) + + logged("queryRenderedFeaturesAtPoint.option", rejecter: rejecter) { + let options = try RenderedQueryOptions(layerIds: (layerIDs ?? []).isEmpty ? nil : layerIDs, filter: filter?.asExpression()) + + map.queryRenderedFeatures(with: point, options: options) { result in + switch result { + case .success(let features): + resolver([ + "data": ["type": "FeatureCollection", "features": features.compactMap { queriedFeature in + logged("queryRenderedFeaturesAtPoint.feature.toJSON") { try queriedFeature.feature.toJSON() } + }] + ]) + case .failure(let error): + rejecter("queryRenderedFeaturesAtPoint","failed to query features", error) + } + } + } } + } - - @objc - func queryRenderedFeaturesAtPoint( - _ reactTag: NSNumber, - atPoint point: [NSNumber], - withFilter filter: [Any]?, - withLayerIDs layerIDs: [String]?, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapboxMap(reactTag, name:"queryRenderedFeaturesAtPoint", rejecter: rejecter) { mapboxMap in - MBXMapViewManager.queryRenderedFeaturesAtPoint(mapboxMap, atPoint: point, withFilter: filter, withLayerIDs: layerIDs, resolver: resolver, rejecter: rejecter) - } - } - static func queryRenderedFeaturesInRect( + @objc public static func queryRenderedFeaturesInRect( _ map: RCTMGLMapView, withBBox bbox: [NSNumber], withFilter filter: [Any]?, @@ -305,21 +193,8 @@ extension MBXMapViewManager { } } } - - @objc - func queryRenderedFeaturesInRect( - _ reactTag: NSNumber, - withBBox bbox: [NSNumber], - withFilter filter: [Any]?, - withLayerIDs layerIDs: [String]?, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapView(reactTag, name:"queryRenderedFeaturesInRect", rejecter: rejecter) { mapView in - MBXMapViewManager.queryRenderedFeaturesInRect(mapView, withBBox: bbox, withFilter: filter, withLayerIDs: layerIDs, resolver: resolver, rejecter: rejecter) - } - } - static func querySourceFeatures( + @objc public static func querySourceFeatures( _ map: RCTMGLMapView, withSourceId sourceId: String, withFilter filter: [Any]?, @@ -343,22 +218,8 @@ extension MBXMapViewManager { } } } - - @objc - func querySourceFeatures( - _ reactTag: NSNumber, - withSourceId sourceId: String, - withFilter filter: [Any]?, - withSourceLayerIds sourceLayerIds: [String]?, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock) -> Void { - withMapView(reactTag, name:"querySourceFeatures", rejecter: rejecter) { mapView in - MBXMapViewManager.querySourceFeatures(mapView, withSourceId: sourceId, withFilter: filter, withSourceLayerIds: sourceLayerIds, resolver: resolver, rejecter: rejecter) - } - } - - static func clearData( + @objc public static func clearData( _ view: RCTMGLMapView, resolver:@escaping RCTPromiseResolveBlock, rejecter:@escaping RCTPromiseRejectBlock @@ -371,15 +232,5 @@ extension MBXMapViewManager { } } } - - @objc - func clearData( - _ reactTag: NSNumber, - resolver: @escaping RCTPromiseResolveBlock, - rejecter: @escaping RCTPromiseRejectBlock - ) { - withMapView(reactTag, name:"clearDataPath", rejecter: rejecter) { mapView in - MBXMapViewManager.clearData(mapView, resolver: resolver, rejecter: rejecter) - } - } + } diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index 3731c7656..b9925eb40 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -3,11 +3,20 @@ #import #import "MBXMapViewModule.h" -#import "MBXMapView.h" #ifdef RCT_NEW_ARCH_ENABLED #import "MBXMapViewComponentView.h" #endif // RCT_NEW_ARCH_ENABLED +// needed for compilation for some reason +#import +#import + +@interface MapView : UIView +@end + +#import + + @implementation MBXMapViewModule RCT_EXPORT_MODULE(); @@ -17,16 +26,18 @@ @implementation MBXMapViewModule #endif // RCT_NEW_ARCH_ENABLED @synthesize bridge = _bridge; -- (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(UIView*))block reject:(RCTPromiseRejectBlock)reject +- (void)withMapView:(NSNumber*)viewRef block:(void (^)(MBXMapView *))block reject:(RCTPromiseRejectBlock)reject { void (^upperBlock)(void) = ^{ #ifdef RCT_NEW_ARCH_ENABLED [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { - UIView *view = [self.viewRegistry_DEPRECATED viewForReactTag:viewRef]; + MBXMapViewComponentView *componentView = [self.viewRegistry_DEPRECATED viewForReactTag:viewRef]; + MBXMapView *view = componentView.contentView; + #else [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary *viewRegistry) { - UIView *view = [uiManager viewForReactTag:viewRef]; + MBXMapView *view = [uiManager viewForReactTag:viewRef]; #endif // RCT_NEW_ARCH_ENABLED if (view != nil) { block(view); @@ -45,93 +56,93 @@ - (void)withMapComponentView:(NSNumber*)viewRef block:(void (^)(UIView* view) { - [view takeSnap:writeToDisk resolve:resolve]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager takeSnap:view writeToDisk:writeToDisk resolver:resolve]; } reject:reject]; } RCT_EXPORT_METHOD(clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view clearData:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager clearData:view resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view getCenter:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager getCenter:view resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(getCoordinateFromView:(NSNumber*)viewRef atPoint:(NSArray *)atPoint resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { + [self withMapView:viewRef block:^(MBXMapView *view) { NSNumber* a = [atPoint objectAtIndex:0]; NSNumber* b = [atPoint objectAtIndex:1]; - [view getCoordinateFromView:CGPointMake(a.floatValue, b.floatValue) resolve:resolve reject:reject]; + [MBXMapViewManager getCoordinateFromView:view atPoint:CGPointMake(a.floatValue, b.floatValue) resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view getPointInView:atCoordinate resolve:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager getPointInView:view atCoordinate:atCoordinate resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view getVisibleBounds:resolve]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager getVisibleBounds:view resolver:resolve]; } reject:reject]; } RCT_EXPORT_METHOD(getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view getZoom:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager getZoom:view resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view queryRenderedFeaturesAtPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager queryRenderedFeaturesAtPoint:view atPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view queryRenderedFeaturesInRect:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolve:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager queryRenderedFeaturesInRect:view withBBox:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view queryTerrainElevation:coordinates resolve:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager queryTerrainElevation:view coordinates:coordinates resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(setHandledMapChangedEvents:(nonnull NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view setHandledMapChangedEvents:events resolve:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager setHandledMapChangedEvents:view events:events resolver:resolve rejecter:reject]; } reject:reject]; } RCT_EXPORT_METHOD(setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view setSourceVisibility:visible sourceId:sourceId sourceLayerId:sourceLayerId resolve:resolve reject:reject]; + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager setSourceVisibility:view visible:visible sourceId:sourceId sourceLayerId:sourceLayerId resolver:resolve rejecter:reject]; } reject:reject]; } -RCT_EXPORT_METHOD(querySourceFeatures:(NSNumber*)viewRef sourceId:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { - [self withMapComponentView:viewRef block:^(UIView* view) { - [view querySourceFeatures:sourceId withFilter:filter withSourceLayerIDs:sourceLayerIDs resolve:resolve reject:reject]; +RCT_EXPORT_METHOD(querySourceFeatures:(NSNumber*)viewRef sourceId:(NSString*)sourceId withFilter:(NSArray*)withFilter withSourceLayerIDs:(NSArray*)withSourceLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { + [self withMapView:viewRef block:^(MBXMapView *view) { + [MBXMapViewManager querySourceFeatures:view withSourceId:sourceId withFilter:withFilter withSourceLayerIds:withSourceLayerIDs resolver:resolve rejecter:reject]; } reject:reject]; } diff --git a/ios/RCTMGL-v10/RCTMGLMapView.swift b/ios/RCTMGL-v10/RCTMGLMapView.swift index a59953a75..8948762a6 100644 --- a/ios/RCTMGL-v10/RCTMGLMapView.swift +++ b/ios/RCTMGL-v10/RCTMGLMapView.swift @@ -47,7 +47,7 @@ class RCTMGLCameraChanged : RCTMGLEvent, RCTEvent { } } -@objc(RCTMGLMapView) +@objc(MBXMapView) open class RCTMGLMapView : MapView { var tapDelegate: IgnoreRCTMGLMakerViewGestureDelegate? = nil @@ -152,7 +152,7 @@ open class RCTMGLMapView : MapView { super.removeReactSubview(subview) } - public required init(frame:CGRect, eventDispatcher: RCTEventDispatcherProtocol) { + @objc public required init(frame:CGRect, eventDispatcher: RCTEventDispatcherProtocol) { let resourceOptions = ResourceOptions(accessToken: MGLModule.accessToken!) self.eventDispatcher = eventDispatcher super.init(frame: frame, mapInitOptions: MapInitOptions(resourceOptions: resourceOptions)) @@ -193,14 +193,14 @@ open class RCTMGLMapView : MapView { // MARK: - React Native properties - @objc func setReactProjection(_ value: String?) { + @objc public func setReactProjection(_ value: String?) { if let value = value { let projection = StyleProjection(name: value == "globe" ? .globe : .mercator) try! self.mapboxMap.style.setProjection(projection) } } - @objc func setReactLocalizeLabels(_ value: NSDictionary?) { + @objc public func setReactLocalizeLabels(_ value: NSDictionary?) { onMapStyleLoaded { _ in if let value = value { logged("RCTMGLMapVIew.setReactLocalizeLabels") { @@ -214,34 +214,34 @@ open class RCTMGLMapView : MapView { } - @objc func setReactAttributionEnabled(_ value: Bool) { + @objc public func setReactAttributionEnabled(_ value: Bool) { mapView.ornaments.options.attributionButton.visibility = value ? .visible : .hidden } - @objc func setReactAttributionPosition(_ position: [String: NSNumber]) { + @objc public func setReactAttributionPosition(_ position: [String: NSNumber]) { if let ornamentOptions = self.getOrnamentOptionsFromPosition(position) { mapView.ornaments.options.attributionButton.position = ornamentOptions.position mapView.ornaments.options.attributionButton.margins = ornamentOptions.margins } } - @objc func setReactLogoEnabled(_ value: Bool) { + @objc public func setReactLogoEnabled(_ value: Bool) { mapView.ornaments.options.logo.visibility = value ? .visible : .hidden } - @objc func setReactLogoPosition(_ position: [String: NSNumber]) { + @objc public func setReactLogoPosition(_ position: [String: NSNumber]) { if let ornamentOptions = self.getOrnamentOptionsFromPosition(position) { mapView.ornaments.options.logo.position = ornamentOptions.position mapView.ornaments.options.logo.margins = ornamentOptions.margins } } - @objc func setReactCompassEnabled(_ value: Bool) { + @objc public func setReactCompassEnabled(_ value: Bool) { compassEnabled = value refreshCompassVisibility() } - @objc func setReactCompassFadeWhenNorth(_ value: Bool) { + @objc public func setReactCompassFadeWhenNorth(_ value: Bool) { compassFadeWhenNorth = value refreshCompassVisibility() } @@ -256,7 +256,7 @@ open class RCTMGLMapView : MapView { refreshCompassImage() } - @objc func setReactCompassPosition(_ position: [String: NSNumber]) { + @objc public func setReactCompassPosition(_ position: [String: NSNumber]) { if let ornamentOptions = self.getOrnamentOptionsFromPosition(position) { mapView.ornaments.options.compass.position = ornamentOptions.position mapView.ornaments.options.compass.margins = ornamentOptions.margins @@ -286,15 +286,15 @@ open class RCTMGLMapView : MapView { } } - @objc func setReactCompassViewPosition(_ position: NSInteger) { + @objc public func setReactCompassViewPosition(_ position: NSInteger) { mapView.ornaments.options.compass.position = toOrnamentPositon(Int(truncating: NSNumber(value: position))) } - @objc func setReactCompassViewMargins(_ margins: CGPoint) { + @objc public func setReactCompassViewMargins(_ margins: CGPoint) { mapView.ornaments.options.compass.margins = margins; } - @objc func setReactCompassImage(_ image: String) { + @objc public func setReactCompassImage(_ image: String) { compassImage = image.isEmpty ? nil : image refreshCompassImage() } @@ -312,33 +312,33 @@ open class RCTMGLMapView : MapView { } } - @objc func setReactScaleBarEnabled(_ value: Bool) { + @objc public func setReactScaleBarEnabled(_ value: Bool) { self.mapView.ornaments.options.scaleBar.visibility = value ? .visible : .hidden } - @objc func setReactScaleBarPosition(_ position: [String: NSNumber]) { + @objc public func setReactScaleBarPosition(_ position: [String: NSNumber]) { if let ornamentOptions = self.getOrnamentOptionsFromPosition(position) { mapView.ornaments.options.scaleBar.position = ornamentOptions.position mapView.ornaments.options.scaleBar.margins = ornamentOptions.margins } } - @objc func setReactZoomEnabled(_ value: Bool) { + @objc public func setReactZoomEnabled(_ value: Bool) { self.mapView.gestures.options.quickZoomEnabled = value self.mapView.gestures.options.doubleTapToZoomInEnabled = value self.mapView.gestures.options.pinchZoomEnabled = value } - @objc func setReactScrollEnabled(_ value: Bool) { + @objc public func setReactScrollEnabled(_ value: Bool) { self.mapView.gestures.options.panEnabled = value self.mapView.gestures.options.pinchPanEnabled = value } - @objc func setReactRotateEnabled(_ value: Bool) { + @objc public func setReactRotateEnabled(_ value: Bool) { self.mapView.gestures.options.rotateEnabled = value } - @objc func setReactPitchEnabled(_ value: Bool) { + @objc public func setReactPitchEnabled(_ value: Bool) { self.mapView.gestures.options.pitchEnabled = value } @@ -368,7 +368,7 @@ open class RCTMGLMapView : MapView { addFeaturesToMap(style: style) } - @objc func setReactStyleURL(_ value: String?) { + @objc public func setReactStyleURL(_ value: String?) { var initialLoad = !self.styleLoaded if !initialLoad { refreshComponentsBeforeStyleChange() } self.styleLoaded = false @@ -446,7 +446,7 @@ extension RCTMGLMapView { } } - @objc func setReactOnMapChange(_ value: @escaping RCTBubblingEventBlock) { + @objc public func setReactOnMapChange(_ value: @escaping RCTBubblingEventBlock) { self.reactOnMapChange = value self.onEvery(event: .cameraChanged, handler: { (self, cameraEvent) in @@ -664,7 +664,7 @@ class IgnoreRCTMGLMakerViewGestureDelegate : NSObject, UIGestureRecognizerDelega extension RCTMGLMapView { - @objc func setReactOnPress(_ value: @escaping RCTBubblingEventBlock) { + @objc public func setReactOnPress(_ value: @escaping RCTBubblingEventBlock) { self.reactOnPress = value let singleTapGestureRecognizer = self.mapView.gestures.singleTapGestureRecognizer @@ -676,7 +676,7 @@ extension RCTMGLMapView { singleTapGestureRecognizer.delegate = tapDelegate } - @objc func setReactOnLongPress(_ value: @escaping RCTBubblingEventBlock) { + @objc public func setReactOnLongPress(_ value: @escaping RCTBubblingEventBlock) { self.reactOnLongPress = value let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(doHandleLongPress(_:))) @@ -864,7 +864,7 @@ extension RCTMGLMapView: GestureManagerDelegate { extension RCTMGLMapView { - @objc func takeSnap( + @objc public func takeSnap( writeToDisk:Bool) -> URL { UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0); diff --git a/src/components/MapView.tsx b/src/components/MapView.tsx index a38e276b1..cd4d858c5 100644 --- a/src/components/MapView.tsx +++ b/src/components/MapView.tsx @@ -858,30 +858,22 @@ class MapView extends NativeBridgeComponent( nativeRef: RefType | undefined, args?: NativeArg[], ): Promise { - if (NativeMapViewModule) { - // when this method is called after component mounts, the ref is not yet set - // schedule it to be called after a timeout - if (!this._nativeRef) { - return new Promise((resolve) => setTimeout(resolve, 1)).then(() => { - return this._runNativeCommand(methodName, this._nativeRef, args); - }); - } + // when this method is called after component mounts, the ref is not yet set + // schedule it to be called after a timeout + if (!this._nativeRef) { + return new Promise((resolve) => setTimeout(resolve, 1)).then(() => { + return this._runNativeCommand(methodName, this._nativeRef, args); + }); + } - const handle = findNodeHandle(nativeRef as any); + const handle = findNodeHandle(nativeRef as any); - // @ts-expect-error TS says that string cannot be used to index NativeMapViewModule. - // It can, it's just not pretty. - return NativeMapViewModule[methodName]?.( - handle, - ...(args ?? []), - ) as Promise; - } else { - return super._runNativeCommand( - methodName, - nativeRef, - args, - ); - } + // @ts-expect-error TS says that string cannot be used to index NativeMapViewModule. + // It can, it's just not pretty. + return NativeMapViewModule[methodName]?.( + handle, + ...(args ?? []), + ) as Promise; } _decodePayload( diff --git a/src/specs/NativeMapViewModule.ts b/src/specs/NativeMapViewModule.ts index b581d33be..28f3e89b0 100644 --- a/src/specs/NativeMapViewModule.ts +++ b/src/specs/NativeMapViewModule.ts @@ -51,4 +51,4 @@ export interface Spec extends TurboModule { ) => Promise; } -export default TurboModuleRegistry.get('MBXMapViewModule'); +export default TurboModuleRegistry.getEnforcing('MBXMapViewModule'); From 780834380fa9722595295787456884c7cb983fb4 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 5 Sep 2023 16:56:00 +0200 Subject: [PATCH 31/33] Clean up the simpler interop and make iOS compile --- .../mapview/RCTMGLMapViewManager.kt | 120 ------------------ example/ios/Podfile.lock | 2 +- fabricexample/ios/Podfile.lock | 2 +- ios/RCTMGL-v10/MBXMapViewComponentView.h | 14 -- ios/RCTMGL-v10/MBXMapViewComponentView.mm | 11 +- ios/RCTMGL-v10/MBXMapViewModule.h | 2 +- ios/RCTMGL-v10/rnmapbox_maps.h | 1 + package.json | 2 +- rnmapbox-maps.podspec | 1 + 9 files changed, 13 insertions(+), 142 deletions(-) create mode 100644 ios/RCTMGL-v10/rnmapbox_maps.h diff --git a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt index 27cbdb318..22c62011c 100644 --- a/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt +++ b/android/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt @@ -295,126 +295,6 @@ open class RCTMGLMapViewManager(context: ReactApplicationContext) : "_useCommandName" to 1 ); } - - fun sendResponse(mapView: RCTMGLMapView, callbackId: String, responseBuilder: (WritableMap) -> Unit) { - val payload: WritableMap = WritableNativeMap() - responseBuilder(payload) - var event = AndroidCallbackEvent(mapView, callbackId, payload) - handleEvent(event) - } - - override fun receiveCommand(mapView: RCTMGLMapView, command: String, args: ReadableArray?) { - val callbackId = args!!.getString(0); - // allows method calls to work with componentDidMount - val mapboxMap = mapView.getMapboxMap() - ?: // mapView.enqueuePreRenderMapMethod(commandID, args); - return - val response = object : CommandResponse { - override fun success(builder: (WritableMap) -> Unit) { - sendResponse(mapView, callbackId, builder) - } - - override fun error(message: String) { - Logger.e(REACT_CLASS, "Command: ${command} failed with: ${message}") - sendResponse(mapView, callbackId) { - it.putNull("data") - it.putString("error", message) - } - } - } - when (command) { - "queryTerrainElevation" -> { - val coords = args!!.getArray(1) - mapView.queryTerrainElevation( - coords.getDouble(0), - coords.getDouble(1), - response - ) - } - "getZoom" -> { - mapView.getZoom(response) - } - "getCenter" -> { - mapView.getCenter(response) - } - "getPointInView" -> { - mapView.getPointInView(args.getArray(1).toCoordinate(), response) - } - "getCoordinateFromView" -> { - mapView.getCoordinateFromView(args.getArray(1).toScreenCoordinate(), response) - } - "setSourceVisibility" -> { - mapView!!.setSourceVisibility( - args!!.getBoolean(1), - args!!.getString(2), - args!!.getString(3) - ); - } - "queryRenderedFeaturesAtPoint" -> { - mapView.queryRenderedFeaturesAtPoint( - ConvertUtils.toPointF(args!!.getArray(1)), - ExpressionParser.from(args!!.getArray(2)), - ConvertUtils.toStringList(args!!.getArray(3)), - response - ) - } - "queryRenderedFeaturesInRect" -> { - val layerIds = ConvertUtils.toStringList(args!!.getArray(3)) - mapView.queryRenderedFeaturesInRect( - if ((args.getArray(1)?.size() ?: 0) == 0) null else args.getArray(1).toRectF(), - ExpressionParser.from(args!!.getArray(2)), - if (layerIds.size == 0) null else layerIds, - response - ) - } - "querySourceFeatures" -> { - val sourceLayerIds = ConvertUtils.toStringList(args!!.getArray(3)) - mapView.querySourceFeatures( - args!!.getString(1), - ExpressionParser.from(args!!.getArray(2)), - if (sourceLayerIds.size == 0) null else sourceLayerIds, - response - ); - } - "getVisibleBounds" -> { - mapView.getVisibleBounds(response) - } - "takeSnap" -> { - mapView.takeSnap(args!!.getBoolean(1), response) - } - "setHandledMapChangedEvents" -> { - args?.let { - mapView.setHandledMapChangedEvents(it.getArray(1).asArrayString()); - } - } - "clearData" -> { - mapView.clearData(response) - } - else -> { - Logger.w("RCTMGLMapView.receiveCommand", "unexpected command: ${command}") - } - } - /* - 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) : diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 2f58f8298..6ecd42c7a 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -675,7 +675,7 @@ SPEC CHECKSUMS: React-runtimeexecutor: c5c89f8f543842dd864b63ded1b0bbb9c9445328 ReactCommon: dbfbe2f7f3c5ce4ce44f43f2fd0d5950d1eb67c5 RNCAsyncStorage: f57e929cd7757f2cb3dd8186d123c09e8281a1ad - rnmapbox-maps: bec5f28dceb067f34dca4979a7be2cf43cd89df7 + rnmapbox-maps: 52784eea1f6d2d4e19c5040e600ac351beba3c33 RNScreens: b21dc57dfa2b710c30ec600786a3fc223b1b92e7 RNSVG: d7d7bc8229af3842c9cfc3a723c815a52cdd1105 RNVectorIcons: fcc2f6cb32f5735b586e66d14103a74ce6ad61f8 diff --git a/fabricexample/ios/Podfile.lock b/fabricexample/ios/Podfile.lock index 73a46de97..0209a015a 100644 --- a/fabricexample/ios/Podfile.lock +++ b/fabricexample/ios/Podfile.lock @@ -1232,7 +1232,7 @@ SPEC CHECKSUMS: React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035 React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d - rnmapbox-maps: 78fdff8350d72d002f77e3a1507c817b4df614a6 + rnmapbox-maps: e58b0ffd46127cec4b5f2e355fc60936fdcd335d SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4 Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981 diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.h b/ios/RCTMGL-v10/MBXMapViewComponentView.h index f3b30885e..10caa05c3 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.h +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.h @@ -11,20 +11,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)dispatchCameraChangedEvent:(NSDictionary*)event; -- (void)takeSnap:(BOOL)writeToDisk resolve:(RCTPromiseResolveBlock)resolve; -- (void)clearData:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getCenter:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getCoordinateFromView:(CGPoint)point resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getPointInView:(NSArray*)coordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)getVisibleBounds:(RCTPromiseResolveBlock)resolve; -- (void)getZoom:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)queryRenderedFeaturesAtPoint:(NSArray*)point withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)queryRenderedFeaturesInRect:(NSArray*)bbox withFilter:(NSArray*)filter withLayerIDs:(NSArray*)layerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)queryTerrainElevation:(NSArray*)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)setHandledMapChangedEvents:(NSArray*)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)setSourceVisibility:(BOOL)visible sourceId:(NSString*)sourceId sourceLayerId:(NSString*)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject; -- (void)querySourceFeatures:(NSString*)sourceId withFilter:(NSArray*)filter withSourceLayerIDs:(NSArray*)sourceLayerIDs resolve:(RCTPromiseResolveBlock _Nonnull )resolve reject:(RCTPromiseRejectBlock _Nonnull )reject; - @end NS_ASSUME_NONNULL_END diff --git a/ios/RCTMGL-v10/MBXMapViewComponentView.mm b/ios/RCTMGL-v10/MBXMapViewComponentView.mm index 1fbcf3137..df044fdeb 100644 --- a/ios/RCTMGL-v10/MBXMapViewComponentView.mm +++ b/ios/RCTMGL-v10/MBXMapViewComponentView.mm @@ -5,10 +5,10 @@ #import #import -#import -#import -#import -#import +#import +#import +#import +#import // needed for compilation for some reason #import #import @@ -58,6 +58,9 @@ - (instancetype)initWithFrame:(CGRect)frame _eventDispatcher = [[MBXMapViewEventDispatcher alloc] initWithComponentView:self]; _view = [[MBXMapView alloc] initWithFrame:frame eventDispatcher:_eventDispatcher]; + // just need to pass something, it won't really be used on fabric, but it's used to create events (it won't impact sending them) + _view.reactTag = @-1; + // capture weak self reference to prevent retain cycle __weak __typeof__(self) weakSelf = self; diff --git a/ios/RCTMGL-v10/MBXMapViewModule.h b/ios/RCTMGL-v10/MBXMapViewModule.h index 2884bba48..e79b18120 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.h +++ b/ios/RCTMGL-v10/MBXMapViewModule.h @@ -2,7 +2,7 @@ #import #ifdef RCT_NEW_ARCH_ENABLED -#import "rnmapbox_maps.h" +#import "rnmapbox_maps_specs.h" #else #import #endif diff --git a/ios/RCTMGL-v10/rnmapbox_maps.h b/ios/RCTMGL-v10/rnmapbox_maps.h new file mode 100644 index 000000000..a3cf5ec3c --- /dev/null +++ b/ios/RCTMGL-v10/rnmapbox_maps.h @@ -0,0 +1 @@ +// xcode tries to import this header in the auto-generated swift header diff --git a/package.json b/package.json index 033d06488..4a1c56177 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "typescript": "4.8.4" }, "codegenConfig": { - "name": "rnmapbox_maps", + "name": "rnmapbox_maps_specs", "type": "all", "jsSrcsDir": "src/specs", "android": { diff --git a/rnmapbox-maps.podspec b/rnmapbox-maps.podspec index dd29566be..df6364e7a 100644 --- a/rnmapbox-maps.podspec +++ b/rnmapbox-maps.podspec @@ -237,6 +237,7 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/rnmapbox/maps.git" } s.license = "MIT" s.platform = :ios, "11.0" + s.header_dir = "rnmapbox_maps" unless $RNMapboxMapsSwiftPackageManager case $RNMapboxMapsImpl From 66e6ccdbf9af21a1eb27527df92c41b436532bc6 Mon Sep 17 00:00:00 2001 From: Jakub Piasecki Date: Tue, 5 Sep 2023 17:53:34 +0200 Subject: [PATCH 32/33] Fix lint & tests --- .eslintrc.js | 1 + fabricexample/.eslintrc.js | 4 ---- fabricexample/App.tsx | 1 + fabricexample/__tests__/App.test.tsx | 17 ----------------- fabricexample/index.js | 1 + fabricexample/metro.config.js | 2 ++ fabricexample/package.json | 1 - fabricexample/tsconfig.json | 14 ++++++++++++-- setup-jest.js | 16 ++++++++++++++++ 9 files changed, 33 insertions(+), 24 deletions(-) delete mode 100644 fabricexample/.eslintrc.js delete mode 100644 fabricexample/__tests__/App.test.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 02fc5cede..d03f89bd1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -90,6 +90,7 @@ module.exports = { project: [ './tsconfig.json', './example/tsconfig.json', + './fabricexample/tsconfig.json', './plugin/src/__tests__/tsconfig.eslint.json', ], }, diff --git a/fabricexample/.eslintrc.js b/fabricexample/.eslintrc.js deleted file mode 100644 index 187894b6a..000000000 --- a/fabricexample/.eslintrc.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - root: true, - extends: '@react-native', -}; diff --git a/fabricexample/App.tsx b/fabricexample/App.tsx index 36f092461..a7304bf28 100644 --- a/fabricexample/App.tsx +++ b/fabricexample/App.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {StyleSheet, View} from 'react-native'; import Mapbox from '@rnmapbox/maps'; + import env from './env.json'; Mapbox.setAccessToken(env.accessToken); diff --git a/fabricexample/__tests__/App.test.tsx b/fabricexample/__tests__/App.test.tsx deleted file mode 100644 index 3413ac1c4..000000000 --- a/fabricexample/__tests__/App.test.tsx +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @format - */ - -import 'react-native'; -import React from 'react'; -import App from '../App'; - -// Note: import explicitly to use the types shiped with jest. -import {it} from '@jest/globals'; - -// Note: test renderer must be required after react-native. -import renderer from 'react-test-renderer'; - -it('renders correctly', () => { - renderer.create(); -}); diff --git a/fabricexample/index.js b/fabricexample/index.js index a850d031d..84c185a5d 100644 --- a/fabricexample/index.js +++ b/fabricexample/index.js @@ -3,6 +3,7 @@ */ import {AppRegistry} from 'react-native'; + import App from './App'; import {name as appName} from './app.json'; diff --git a/fabricexample/metro.config.js b/fabricexample/metro.config.js index 6b535f5e3..4c9e4fcc6 100644 --- a/fabricexample/metro.config.js +++ b/fabricexample/metro.config.js @@ -1,6 +1,8 @@ const path = require('path'); + const exclusionList = require('metro-config/src/defaults/exclusionList'); const escape = require('escape-string-regexp'); + const pack = require('../package.json'); const root = path.resolve(__dirname, '..'); diff --git a/fabricexample/package.json b/fabricexample/package.json index a441a4ae5..5b002dc47 100644 --- a/fabricexample/package.json +++ b/fabricexample/package.json @@ -19,7 +19,6 @@ "@babel/core": "^7.20.0", "@babel/preset-env": "^7.20.0", "@babel/runtime": "^7.20.0", - "@react-native/eslint-config": "^0.72.2", "@react-native/metro-config": "^0.72.11", "@tsconfig/react-native": "^3.0.0", "@types/react": "^18.0.24", diff --git a/fabricexample/tsconfig.json b/fabricexample/tsconfig.json index 45a6c7072..6ad58e495 100644 --- a/fabricexample/tsconfig.json +++ b/fabricexample/tsconfig.json @@ -1,3 +1,13 @@ { - "extends": "@tsconfig/react-native/tsconfig.json" -} + "extends": "../tsconfig.json", + "compilerOptions": { + "allowJs": true, + "resolveJsonModule": true, + "baseUrl": ".", + "paths": { + "@rnmapbox/maps": ["../src"], + "react": ["./node_modules/@types/react"], + } + }, + "include": ["index.js", "src/**/*"] +} \ No newline at end of file diff --git a/setup-jest.js b/setup-jest.js index 397efabc0..6066fd0d3 100644 --- a/setup-jest.js +++ b/setup-jest.js @@ -118,6 +118,22 @@ NativeModules.MGLLocationModule = { pause: jest.fn(), }; +NativeModules.MBXMapViewModule = { + takeSnap: jest.fn(), + queryTerrainElevation: jest.fn(), + setSourceVisibility: jest.fn(), + getCenter: jest.fn(), + getCoordinateFromView: jest.fn(), + getPointInView: jest.fn(), + getZoom: jest.fn(), + getVisibleBounds: jest.fn(), + queryRenderedFeaturesAtPoint: jest.fn(), + queryRenderedFeaturesInRect: jest.fn(), + setHandledMapChangedEvents: jest.fn(), + clearData: jest.fn(), + querySourceFeatures: jest.fn(), +}; + // Mock for global AbortController global.AbortController = class { signal = 'test-signal'; From b1f77edcd89f0d6dfae6d19fbbef08dae5ef1897 Mon Sep 17 00:00:00 2001 From: Wojciech Lewicki Date: Tue, 12 Sep 2023 18:04:10 +0200 Subject: [PATCH 33/33] fix: dispatch methods on uimanager queue --- ios/RCTMGL-v10/MBXMapViewModule.mm | 54 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/ios/RCTMGL-v10/MBXMapViewModule.mm b/ios/RCTMGL-v10/MBXMapViewModule.mm index b9925eb40..0f73c3e36 100644 --- a/ios/RCTMGL-v10/MBXMapViewModule.mm +++ b/ios/RCTMGL-v10/MBXMapViewModule.mm @@ -26,9 +26,16 @@ @implementation MBXMapViewModule #endif // RCT_NEW_ARCH_ENABLED @synthesize bridge = _bridge; -- (void)withMapView:(NSNumber*)viewRef block:(void (^)(MBXMapView *))block reject:(RCTPromiseRejectBlock)reject +- (dispatch_queue_t)methodQueue { - void (^upperBlock)(void) = ^{ + // It seems that due to how UIBlocks work with uiManager, we need to call the methods there + // for the blocks to be dispatched before the batch is completed + return RCTGetUIManagerQueue(); +} + +- (void)withMapView:(NSNumber*)viewRef block:(void (^)(MBXMapView *))block reject:(RCTPromiseRejectBlock)reject methodName:(NSString *)methodName +{ +// void (^upperBlock)(void) = ^{ #ifdef RCT_NEW_ARCH_ENABLED [self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) { MBXMapViewComponentView *componentView = [self.viewRegistry_DEPRECATED viewForReactTag:viewRef]; @@ -42,15 +49,16 @@ - (void)withMapView:(NSNumber*)viewRef block:(void (^)(MBXMapView *))block rejec if (view != nil) { block(view); } else { - reject(@"takeSnap", [NSString stringWithFormat:@"Unknown reactTag: %@", viewRef], nil); + reject(methodName, [NSString stringWithFormat:@"Unknown reactTag: %@", viewRef], nil); } }]; - }; - if (self.bridge) { - dispatch_async(RCTGetUIManagerQueue(), upperBlock); - } else { - dispatch_async(dispatch_get_main_queue(), upperBlock); - } +// [self.bridge performSelector:@selector(batchDidComplete) withObject:self.bridge]; +// }; +// if (self.bridge) { +// dispatch_async(RCTGetUIManagerQueue(), upperBlock); +// } else { +// dispatch_async(dispatch_get_main_queue(), upperBlock); +// } } @@ -58,20 +66,20 @@ - (void)withMapView:(NSNumber*)viewRef block:(void (^)(MBXMapView *))block rejec { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager takeSnap:view writeToDisk:writeToDisk resolver:resolve]; - } reject:reject]; + } reject:reject methodName:@"takeSnap"]; } RCT_EXPORT_METHOD(clearData:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager clearData:view resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"clearData"]; } RCT_EXPORT_METHOD(getCenter:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager getCenter:view resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"getCenter"]; } @@ -81,69 +89,69 @@ - (void)withMapView:(NSNumber*)viewRef block:(void (^)(MBXMapView *))block rejec NSNumber* b = [atPoint objectAtIndex:1]; [MBXMapViewManager getCoordinateFromView:view atPoint:CGPointMake(a.floatValue, b.floatValue) resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"getCoordinateFromView"]; } -RCT_EXPORT_METHOD(getPointInView:(NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { +RCT_EXPORT_METHOD(getPointInView:(nonnull NSNumber*)viewRef atCoordinate:(NSArray *)atCoordinate resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager getPointInView:view atCoordinate:atCoordinate resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"getPointInView"]; } RCT_EXPORT_METHOD(getVisibleBounds:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager getVisibleBounds:view resolver:resolve]; - } reject:reject]; + } reject:reject methodName:@"getVisibleBounds"]; } RCT_EXPORT_METHOD(getZoom:(NSNumber*)viewRef resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager getZoom:view resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"getZoom"]; } RCT_EXPORT_METHOD(queryRenderedFeaturesAtPoint:(NSNumber*)viewRef atPoint:(NSArray *)atPoint withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager queryRenderedFeaturesAtPoint:view atPoint:atPoint withFilter:withFilter withLayerIDs:withLayerIDs resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"queryRenderedFeaturesAtPoint"]; } RCT_EXPORT_METHOD(queryRenderedFeaturesInRect:(NSNumber*)viewRef withBBox:(NSArray *)withBBox withFilter:(NSArray *)withFilter withLayerIDs:(NSArray *)withLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager queryRenderedFeaturesInRect:view withBBox:withBBox withFilter:withFilter withLayerIDs:withLayerIDs resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"queryRenderedFeaturesInRect"]; } RCT_EXPORT_METHOD(queryTerrainElevation:(NSNumber*)viewRef coordinates:(NSArray *)coordinates resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager queryTerrainElevation:view coordinates:coordinates resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"queryTerrainElevation"]; } RCT_EXPORT_METHOD(setHandledMapChangedEvents:(nonnull NSNumber*)viewRef events:(NSArray *)events resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager setHandledMapChangedEvents:view events:events resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"setHandledMapChangedEvents"]; } RCT_EXPORT_METHOD(setSourceVisibility:(NSNumber*)viewRef visible:(BOOL)visible sourceId:(NSString *)sourceId sourceLayerId:(NSString *)sourceLayerId resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager setSourceVisibility:view visible:visible sourceId:sourceId sourceLayerId:sourceLayerId resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"setSourceVisibility"]; } RCT_EXPORT_METHOD(querySourceFeatures:(NSNumber*)viewRef sourceId:(NSString*)sourceId withFilter:(NSArray*)withFilter withSourceLayerIDs:(NSArray*)withSourceLayerIDs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) { [self withMapView:viewRef block:^(MBXMapView *view) { [MBXMapViewManager querySourceFeatures:view withSourceId:sourceId withFilter:withFilter withSourceLayerIds:withSourceLayerIDs resolver:resolve rejecter:reject]; - } reject:reject]; + } reject:reject methodName:@"querySourceFeatures"]; }