diff --git a/.circleci/config.yml b/.circleci/config.yml index cd652462a..b2dec1bc7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ defaults: &defaults docker: # Choose the version of Node you want here - - image: cimg/node:18.15.0 + - image: cimg/node:18.17.1 working_directory: /mnt/ramdisk/repo version: 2.1 @@ -16,6 +16,12 @@ jobs: resource_class: large steps: - checkout + - run: + name: Install bun + command: curl -fsSL https://bun.sh/install | bash -s -- bun-v1.0.10 + - run: + name: Link bun + command: sudo ln -s ~/.bun/bin/bun /usr/local/bin/ - restore_cache: name: Restore node modules keys: diff --git a/.gitignore b/.gitignore index 8e4c59182..9377cde8f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,8 @@ coverage # newly spun-up apps, but we do want to ignore it in # Ignite's source repo. boilerplate/yarn.lock +boilerplate/bun.lockb boilerplate/.gitignore.template + +# flame CLI +.config diff --git a/README.md b/README.md index 75de5ffb6..e9db00997 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,13 @@ # Ignite - the battle-tested React Native boilerplate npm version +![GitHub Repo stars](https://img.shields.io/github/stars/infinitered/ignite) +![Twitter Follow](https://img.shields.io/twitter/follow/ir_ignite) [![CircleCI](https://dl.circleci.com/status-badge/img/gh/infinitered/ignite/tree/master.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/infinitered/ignite/tree/master) -## Battle-tested React Native boilerplate +## Proven React Native boilerplate -The culmination of over six years of constant React Native development, Ignite is the most popular React Native app boilerplate for both Expo and bare React Native. +The culmination of over seven years of constant React Native development, Ignite is the most popular React Native app boilerplate for both Expo and bare React Native. This is the React Native boilerplate that the [Infinite Red](https://infinite.red) team uses on a day-to-day basis to build client apps. Developers who use Ignite report that it saves them two to four weeks of time on average off the beginning of their React Native project! @@ -15,36 +17,38 @@ This is the React Native boilerplate that the [Infinite Red](https://infinite.re Check out the [Getting Started with Ignite](https://www.youtube.com/watch?v=KOSvDlFyg20) video for a 13 minute overview! +## [Full Documentation](https://github.com/infinitered/ignite/blob/master/docs) + +We've put great effort into the documentation as a team, please [read through it here](https://github.com/infinitered/ignite/blob/master/docs). If you're unsure why a certain decision was made related to this boilerplate or how to proceed with a particular feature, it's likely documented. If it still isn't clear, go through the proper [help channels](#reporting-bugs--getting-help) and we always welcome PRs to improve the docs! + ## Tech Stack Nothing makes it into Ignite unless it's been proven on projects that Infinite Red works on. Ignite apps include the following rock-solid technical decisions out of the box: | Library | Category | Version | Description | | ----------------- | -------------------- | ------- | ---------------------------------------------- | -| React Native | Mobile Framework | v0.71 | The best cross-platform mobile framework | +| React Native | Mobile Framework | v0.72 | The best cross-platform mobile framework | | React | UI Framework | v18 | The most popular UI framework in the world | -| TypeScript | Language | v4 | Static typechecking | +| TypeScript | Language | v5 | Static typechecking | | React Navigation | Navigation | v6 | Performant and consistent navigation framework | | MobX-State-Tree | State Management | v5 | Observable state tree | | MobX-React-Lite | React Integration | v3 | Re-render React performantly | -| Expo | SDK | v48 | Allows (optional) Expo modules | -| Expo Font | Custom Fonts | v10 | Import custom fonts | -| Expo Localization | Internationalization | v13 | i18n support (including RTL!) | +| Expo | SDK | v49 | Allows (optional) Expo modules | +| Expo Font | Custom Fonts | v11 | Import custom fonts | +| Expo Localization | Internationalization | v14 | i18n support (including RTL!) | | Expo Status Bar | Status Bar Library | v1 | Status bar support | -| RN Reanimated | Animations | v2 | Beautiful and performant animations | +| RN Reanimated | Animations | v3 | Beautiful and performant animations | | AsyncStorage | Persistence | v1 | State persistence | | apisauce | REST client | v2 | Communicate with back-end | -| Flipper | Debugger | | Native debugging | -| Reactotron RN | Inspector/Debugger | v2 | JS debugging | +| Reactotron RN | Inspector/Debugger | v3 | JS debugging | | Hermes | JS engine | | Fine-tuned JS engine for RN | | Jest | Test Runner | v26 | Standard test runner for JS apps | | Maestro | Testing Framework | | Automate end-to-end UI testing | | date-fns | Date library | v2 | Excellent date library | +| FlashList | FlatList replacement | v1 | A performant drop-in replacement for FlatList | Ignite also comes with a [component library](https://github.com/infinitered/ignite/blob/master/docs/Components.md) that is tuned for custom designs, theming support, testing, custom fonts, generators, and much, much more. -[Check out the documentation!](https://github.com/infinitered/ignite/blob/master/docs) - ## Quick Start Prerequisites: diff --git a/boilerplate/.gitignore b/boilerplate/.gitignore index baa76c655..7b101a98c 100644 --- a/boilerplate/.gitignore +++ b/boilerplate/.gitignore @@ -73,6 +73,10 @@ buck-out/ .expo/* bin/Exponent.app +# If using Expo Go/Prebuild, uncomment these: +# android +# ios + npm-debug.* *.jks *.p8 @@ -84,3 +88,5 @@ web-build/ # Configurations !env.js + +/coverage diff --git a/boilerplate/App.js b/boilerplate/App.js deleted file mode 100644 index 4e3371460..000000000 --- a/boilerplate/App.js +++ /dev/null @@ -1,19 +0,0 @@ -// This is the entry point if you run `yarn expo:start` -// If you run `yarn ios` or `yarn android`, it'll use ./index.js instead. -import App from "./app/app.tsx" -import React from "react" -import { registerRootComponent } from "expo" -import { Platform } from "react-native" -import * as SplashScreen from "expo-splash-screen" - -SplashScreen.preventAutoHideAsync() - -function IgniteApp() { - return -} - -if (Platform.OS !== "web") { - registerRootComponent(IgniteApp) -} - -export default IgniteApp diff --git a/boilerplate/App.tsx b/boilerplate/App.tsx new file mode 100644 index 000000000..1fd79cc56 --- /dev/null +++ b/boilerplate/App.tsx @@ -0,0 +1,11 @@ +import App from "./app/app" +import React from "react" +import * as SplashScreen from "expo-splash-screen" + +SplashScreen.preventAutoHideAsync() + +function IgniteApp() { + return +} + +export default IgniteApp diff --git a/boilerplate/android/.gitignore b/boilerplate/android/.gitignore deleted file mode 100644 index 877b87e9a..000000000 --- a/boilerplate/android/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# OSX -# -.DS_Store - -# Android/IntelliJ -# -build/ -.idea -.gradle -local.properties -*.iml -*.hprof - -# Bundle artifacts -*.jsbundle diff --git a/boilerplate/android/app/BUCK b/boilerplate/android/app/BUCK deleted file mode 100644 index 0e7790483..000000000 --- a/boilerplate/android/app/BUCK +++ /dev/null @@ -1,55 +0,0 @@ -# To learn about Buck see [Docs](https://buckbuild.com/). -# To run your application with Buck: -# - install Buck -# - `npm start` - to start the packager -# - `cd android` -# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` -# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck -# - `buck install -r android/app` - compile, install and run application -# - -load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") - -lib_deps = [] - -create_aar_targets(glob(["libs/*.aar"])) - -create_jar_targets(glob(["libs/*.jar"])) - -android_library( - name = "all-libs", - exported_deps = lib_deps, -) - -android_library( - name = "app-code", - srcs = glob([ - "src/main/java/**/*.java", - ]), - deps = [ - ":all-libs", - ":build_config", - ":res", - ], -) - -android_build_config( - name = "build_config", - package = "com.helloworld", -) - -android_resource( - name = "res", - package = "com.helloworld", - res = "src/main/res", -) - -android_binary( - name = "app", - keystore = "//android/keystores:debug", - manifest = "src/main/AndroidManifest.xml", - package_type = "debug", - deps = [ - ":app-code", - ], -) diff --git a/boilerplate/android/app/build.gradle b/boilerplate/android/app/build.gradle deleted file mode 100644 index e0c6bf0eb..000000000 --- a/boilerplate/android/app/build.gradle +++ /dev/null @@ -1,193 +0,0 @@ -apply plugin: "com.android.application" -apply plugin: "com.facebook.react" - -import com.android.build.OutputFile - -def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() -def expoDebuggableVariants = ['debug'] -// Override `debuggableVariants` for expo-updates debugging -if (System.getenv('EX_UPDATES_NATIVE_DEBUG') == "1") { - react { - expoDebuggableVariants = [] - } -} - - -/** - * 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 { - entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim()) - reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() - hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc" - debuggableVariants = expoDebuggableVariants - - /* 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"] -} - -// Override `hermesEnabled` by `expo.jsEngine` -ext { - hermesEnabled = (findProperty('expo.jsEngine') ?: "hermes") == "hermes" -} - -/** - * Set this to true to create four separate APKs instead of one, - * one for each native architecture. This is useful if you don't - * use App Bundles (https://developer.android.com/guide/app-bundle/) - * and want to have separate APKs to upload to the Play Store. - */ -def enableSeparateBuildPerCPUArchitecture = false - -/** - * Set this to true to Run Proguard on Release builds to minify the Java bytecode. - */ -def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean() - -/** - * 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:+' - -/** - * Private function to get the list of Native Architectures you want to build. - * This reads the value from reactNativeArchitectures in your gradle.properties - * file and works together with the --active-arch-only flag of react-native run-android. - */ -def reactNativeArchitectures() { - def value = project.getProperties().get("reactNativeArchitectures") - return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] -} - -android { - ndkVersion rootProject.ext.ndkVersion - - compileSdkVersion rootProject.ext.compileSdkVersion - - namespace "com.helloworld" - defaultConfig { - applicationId "com.helloworld" - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" - } - - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include (*reactNativeArchitectures()) - } - } - 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" - } - } - - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // https://developer.android.com/studio/build/configure-apk-splits.html - // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. - def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - defaultConfig.versionCode * 1000 + versionCodes.get(abi) - } - - } - } -} - -dependencies { - // The version of react-native is set by the React Native Gradle Plugin - implementation("com.facebook.react:react-android") - - implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") - - // RN BootSplash - implementation("androidx.core:core-splashscreen:1.0.0") - - 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) \ No newline at end of file diff --git a/boilerplate/android/app/debug.keystore b/boilerplate/android/app/debug.keystore deleted file mode 100644 index 364e105ed..000000000 Binary files a/boilerplate/android/app/debug.keystore and /dev/null differ diff --git a/boilerplate/android/app/proguard-rules.pro b/boilerplate/android/app/proguard-rules.pro deleted file mode 100644 index 11b025724..000000000 --- a/boilerplate/android/app/proguard-rules.pro +++ /dev/null @@ -1,10 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: diff --git a/boilerplate/android/app/src/debug/AndroidManifest.xml b/boilerplate/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 4b185bc15..000000000 --- a/boilerplate/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - diff --git a/boilerplate/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java b/boilerplate/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java deleted file mode 100644 index 283027d2d..000000000 --- a/boilerplate/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * 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.helloworld; - -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.react.ReactFlipperPlugin; -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 ReactFlipperPlugin()); - 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/boilerplate/android/app/src/main/AndroidManifest.xml b/boilerplate/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 1976c1dee..000000000 --- a/boilerplate/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/boilerplate/android/app/src/main/java/com/helloworld/MainActivity.java b/boilerplate/android/app/src/main/java/com/helloworld/MainActivity.java deleted file mode 100644 index bb43d6fcb..000000000 --- a/boilerplate/android/app/src/main/java/com/helloworld/MainActivity.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.helloworld; - -import android.os.Build; -import android.os.Bundle; - -import com.facebook.react.ReactActivity; -import com.facebook.react.ReactActivityDelegate; -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; -import com.facebook.react.defaults.DefaultReactActivityDelegate; -import com.zoontek.rnbootsplash.RNBootSplash; - -import expo.modules.ReactActivityDelegateWrapper; - -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 "HelloWorld"; - } - - /** - * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and - * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer - * (Paper). - */ - @Override - protected ReactActivityDelegate createReactActivityDelegate() { - return new ReactActivityDelegateWrapper(this, BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, new DefaultReactActivityDelegate( - this, - getMainComponentName(), - // If you opted-in for the New Architecture, we enable the Fabric Renderer. - DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled - // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). - DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled - )); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - RNBootSplash.init(this); // <- initialize the splash screen - super.onCreate(null); // or super.onCreate(savedInstanceState) when not using react-native-screens - } - - /** - * Align the back button behavior with Android S - * where moving root activities to background instead of finishing activities. - * @see onBackPressed - */ - @Override - public void invokeDefaultOnBackPressed() { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { - if (!moveTaskToBack(false)) { - // For non-root activities, use the default implementation to finish them. - super.invokeDefaultOnBackPressed(); - } - return; - } - - // Use the default back button implementation on Android S - // because it's doing more than {@link Activity#moveTaskToBack} in fact. - super.invokeDefaultOnBackPressed(); - } -} diff --git a/boilerplate/android/app/src/main/java/com/helloworld/MainApplication.java b/boilerplate/android/app/src/main/java/com/helloworld/MainApplication.java deleted file mode 100644 index 02f4c5c9b..000000000 --- a/boilerplate/android/app/src/main/java/com/helloworld/MainApplication.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.helloworld; - -import android.app.Application; -import android.content.res.Configuration; -import androidx.annotation.NonNull; - -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; - -import expo.modules.ApplicationLifecycleDispatcher; -import expo.modules.ReactNativeHostWrapper; - -public class MainApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = - new ReactNativeHostWrapper(this, 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()); - ApplicationLifecycleDispatcher.onApplicationCreate(this); - } - - @Override - public void onConfigurationChanged(@NonNull Configuration newConfig) { - super.onConfigurationChanged(newConfig); - ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig); - } - -} \ No newline at end of file diff --git a/boilerplate/android/app/src/main/res/drawable/rn_edit_text_material.xml b/boilerplate/android/app/src/main/res/drawable/rn_edit_text_material.xml deleted file mode 100644 index f35d99620..000000000 --- a/boilerplate/android/app/src/main/res/drawable/rn_edit_text_material.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - diff --git a/boilerplate/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/boilerplate/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 4ae7d1237..000000000 --- a/boilerplate/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/boilerplate/android/app/src/main/res/mipmap-hdpi/bootsplash_logo.png b/boilerplate/android/app/src/main/res/mipmap-hdpi/bootsplash_logo.png deleted file mode 100644 index 5a9365f88..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-hdpi/bootsplash_logo.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index ba87cf746..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png deleted file mode 100644 index 06ebcc020..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index 4bcef333c..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index df965f3ca..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-mdpi/bootsplash_logo.png b/boilerplate/android/app/src/main/res/mipmap-mdpi/bootsplash_logo.png deleted file mode 100644 index 4f6ecbc4a..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-mdpi/bootsplash_logo.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 2aeb8d920..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png deleted file mode 100644 index bdab1a28a..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index e8b2c349e..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index d3e2cd150..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xhdpi/bootsplash_logo.png b/boilerplate/android/app/src/main/res/mipmap-xhdpi/bootsplash_logo.png deleted file mode 100644 index 405798f8a..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xhdpi/bootsplash_logo.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 3edb0da33..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png deleted file mode 100644 index fd2fdeb25..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 6770b989e..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 1da1f18e2..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/bootsplash_logo.png b/boilerplate/android/app/src/main/res/mipmap-xxhdpi/bootsplash_logo.png deleted file mode 100644 index 84db0e848..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/bootsplash_logo.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 7839a3354..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png deleted file mode 100644 index c630e4009..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 17fa5f48c..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index 92802df21..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/bootsplash_logo.png b/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/bootsplash_logo.png deleted file mode 100644 index 294bf63a0..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/bootsplash_logo.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 42d7c36fb..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png deleted file mode 100644 index 284ce6ac7..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index b2257c0e8..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index ecd5c1892..000000000 Binary files a/boilerplate/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/boilerplate/android/app/src/main/res/values/colors.xml b/boilerplate/android/app/src/main/res/values/colors.xml deleted file mode 100644 index 711e4e041..000000000 --- a/boilerplate/android/app/src/main/res/values/colors.xml +++ /dev/null @@ -1,3 +0,0 @@ - - #191015 - diff --git a/boilerplate/android/app/src/main/res/values/strings.xml b/boilerplate/android/app/src/main/res/values/strings.xml deleted file mode 100644 index b89cc1489..000000000 --- a/boilerplate/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - HelloWorld - diff --git a/boilerplate/android/app/src/main/res/values/styles.xml b/boilerplate/android/app/src/main/res/values/styles.xml deleted file mode 100644 index b653be3de..000000000 --- a/boilerplate/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - diff --git a/boilerplate/android/app/src/release/java/com/helloworld/ReactNativeFlipper.java b/boilerplate/android/app/src/release/java/com/helloworld/ReactNativeFlipper.java deleted file mode 100644 index 053f2a140..000000000 --- a/boilerplate/android/app/src/release/java/com/helloworld/ReactNativeFlipper.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * 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.helloworld; - -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. - } -} \ No newline at end of file diff --git a/boilerplate/android/build.gradle b/boilerplate/android/build.gradle deleted file mode 100644 index cd175a591..000000000 --- a/boilerplate/android/build.gradle +++ /dev/null @@ -1,44 +0,0 @@ -import org.apache.tools.ant.taskdefs.condition.Os - -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - ext { - buildToolsVersion = findProperty('android.buildToolsVersion') ?: '33.0.0' - minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '21') - compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '33') - targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '33') - if (findProperty('android.kotlinVersion')) { - kotlinVersion = findProperty('android.kotlinVersion') - } - frescoVersion = findProperty('expo.frescoVersion') ?: '2.5.0' - - // 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:7.3.1') - classpath('com.facebook.react:react-native-gradle-plugin') - } -} - -allprojects { - repositories { - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android')) - } - maven { - // Android JSC is installed from npm - url(new File(['node', '--print', "require.resolve('jsc-android/package.json')"].execute(null, rootDir).text.trim(), '../dist')) - } - - google() - mavenCentral() - maven { url 'https://www.jitpack.io' } - } -} diff --git a/boilerplate/android/gradle.properties b/boilerplate/android/gradle.properties deleted file mode 100644 index 09fce1d47..000000000 --- a/boilerplate/android/gradle.properties +++ /dev/null @@ -1,51 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -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.125.0 - -# Enable GIF support in React Native images (~200 B increase) -expo.gif.enabled=true -# Enable webp support in React Native images (~85 KB increase) -expo.webp.enabled=true -# Enable animated webp support (~3.4 MB increase) -# Disabled by default because iOS doesn't support animated webp -expo.webp.animated=false -# Use hermes as JS engine. To disable remove this line -expo.jsEngine=hermes - - -# 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 diff --git a/boilerplate/android/gradle/wrapper/gradle-wrapper.jar b/boilerplate/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 7454180f2..000000000 Binary files a/boilerplate/android/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/boilerplate/android/gradle/wrapper/gradle-wrapper.properties b/boilerplate/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 8fad3f5a9..000000000 --- a/boilerplate/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/boilerplate/android/gradlew b/boilerplate/android/gradlew deleted file mode 100755 index 1b6c78733..000000000 --- a/boilerplate/android/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/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/master/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 - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-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*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - 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 \ - "$@" - -# 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/boilerplate/android/gradlew.bat b/boilerplate/android/gradlew.bat deleted file mode 100644 index ac1b06f93..000000000 --- a/boilerplate/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@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=. -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%" == "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%"=="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! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/boilerplate/android/settings.gradle b/boilerplate/android/settings.gradle deleted file mode 100644 index 1dc416e7c..000000000 --- a/boilerplate/android/settings.gradle +++ /dev/null @@ -1,10 +0,0 @@ -rootProject.name = 'HelloWorld' - -apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle"); -useExpoModules() - -apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle"); -applyNativeModulesSettingsGradle(settings) - -include ':app' -includeBuild(new File(["node", "--print", "require.resolve('react-native-gradle-plugin/package.json')"].execute(null, rootDir).text.trim()).getParentFile()) diff --git a/boilerplate/app.config.ts b/boilerplate/app.config.ts new file mode 100644 index 000000000..77e3312d0 --- /dev/null +++ b/boilerplate/app.config.ts @@ -0,0 +1,25 @@ +import { ExpoConfig, ConfigContext } from "@expo/config" + +/** + * Use ts-node here so we can use TypeScript for our Config Plugins + * and not have to compile them to JavaScript + */ +require("ts-node/register") + +/** + * @param config ExpoConfig coming from the static config app.json if it exists + * + * You can read more about Expo's Configuration Resolution Rules here: + * https://docs.expo.dev/workflow/configuration/#configuration-resolution-rules + */ +module.exports = ({ config }: ConfigContext): Partial => { + const existingPlugins = config.plugins ?? [] + + return { + ...config, + plugins: [ + ...existingPlugins, + require("./plugins/withSplashScreen").withSplashScreen, + ], + } +} diff --git a/boilerplate/app.json b/boilerplate/app.json index b338e4505..f975acbdc 100644 --- a/boilerplate/app.json +++ b/boilerplate/app.json @@ -50,10 +50,28 @@ "image": "./assets/images/splash-logo-web.png", "resizeMode": "contain", "backgroundColor": "#191015" - } + }, + "bundler": "metro" }, "plugins": [ - "expo-localization" - ] + "expo-localization", + [ + "expo-build-properties", + { + "ios": { + "newArchEnabled": false + }, + "android": { + "newArchEnabled": false + } + } + ] + ], + "experiments": { + "tsconfigPaths": true + } + }, + "ignite": { + "version": "UNKNOWN" } } diff --git a/boilerplate/app/app.tsx b/boilerplate/app/app.tsx index fb14741c8..c968524de 100644 --- a/boilerplate/app/app.tsx +++ b/boilerplate/app/app.tsx @@ -28,6 +28,8 @@ import { ErrorBoundary } from "./screens/ErrorScreen/ErrorBoundary" import * as storage from "./utils/storage" import { customFontsToLoad } from "./theme" import Config from "./config" +import { GestureHandlerRootView } from "react-native-gesture-handler" +import { ViewStyle } from "react-native" export const NAVIGATION_PERSISTENCE_KEY = "NAVIGATION_STATE" @@ -53,7 +55,7 @@ const config = { } interface AppProps { - hideSplashScreen: () => Promise + hideSplashScreen: () => Promise } /** @@ -96,14 +98,20 @@ function App(props: AppProps) { return ( - + + + ) } export default App + +const $container: ViewStyle = { + flex: 1, +} diff --git a/boilerplate/app/components/AutoImage.tsx b/boilerplate/app/components/AutoImage.tsx index 10eb0da9c..9f36b8f28 100644 --- a/boilerplate/app/components/AutoImage.tsx +++ b/boilerplate/app/components/AutoImage.tsx @@ -25,7 +25,7 @@ export interface AutoImageProps extends ImageProps { */ export function useAutoImage( remoteUri: string, - dimensions?: [maxWidth: number, maxHeight: number], + dimensions?: [maxWidth?: number, maxHeight?: number], ): [width: number, height: number] { const [[remoteWidth, remoteHeight], setRemoteImageDimensions] = useState([0, 0]) const remoteAspectRatio = remoteWidth / remoteHeight diff --git a/boilerplate/app/components/Button.tsx b/boilerplate/app/components/Button.tsx index ac95e7f2d..38aa03cfa 100644 --- a/boilerplate/app/components/Button.tsx +++ b/boilerplate/app/components/Button.tsx @@ -88,15 +88,15 @@ export function Button(props: ButtonProps) { ...rest } = props - const preset: Presets = $viewPresets[props.preset] ? props.preset : "default" - function $viewStyle({ pressed }) { + const preset: Presets = props.preset ?? "default" + function $viewStyle({ pressed }: PressableStateCallbackType) { return [ $viewPresets[preset], $viewStyleOverride, !!pressed && [$pressedViewPresets[preset], $pressedViewStyleOverride], ] } - function $textStyle({ pressed }) { + function $textStyle({ pressed }: PressableStateCallbackType) { return [ $textPresets[preset], $textStyleOverride, diff --git a/boilerplate/app/components/Card.tsx b/boilerplate/app/components/Card.tsx index 1cdb69aa8..66323f18c 100644 --- a/boilerplate/app/components/Card.tsx +++ b/boilerplate/app/components/Card.tsx @@ -5,6 +5,7 @@ import { TouchableOpacity, TouchableOpacityProps, View, + ViewProps, ViewStyle, } from "react-native" import { colors, spacing } from "../theme" @@ -148,13 +149,15 @@ export function Card(props: CardProps) { ...WrapperProps } = props - const preset: Presets = $containerPresets[props.preset] ? props.preset : "default" + const preset: Presets = props.preset ?? "default" const isPressable = !!WrapperProps.onPress const isHeadingPresent = !!(HeadingComponent || heading || headingTx) const isContentPresent = !!(ContentComponent || content || contentTx) const isFooterPresent = !!(FooterComponent || footer || footerTx) - const Wrapper: ComponentType = isPressable ? TouchableOpacity : View + const Wrapper = (isPressable ? TouchableOpacity : View) as ComponentType< + TouchableOpacityProps | ViewProps + > const HeaderContentWrapper = verticalAlignment === "force-footer-bottom" ? View : Fragment const $containerStyle = [$containerPresets[preset], $containerStyleOverride] diff --git a/boilerplate/app/components/EmptyState.tsx b/boilerplate/app/components/EmptyState.tsx index 7ecef5dc6..5f78ed180 100644 --- a/boilerplate/app/components/EmptyState.tsx +++ b/boilerplate/app/components/EmptyState.tsx @@ -101,13 +101,20 @@ interface EmptyStateProps { ButtonProps?: ButtonProps } +interface EmptyStatePresetItem { + imageSource: ImageProps["source"] + heading: TextProps["text"] + content: TextProps["text"] + button: TextProps["text"] +} + const EmptyStatePresets = { generic: { imageSource: sadFace, heading: translate("emptyStateComponent.generic.heading"), content: translate("emptyStateComponent.generic.content"), button: translate("emptyStateComponent.generic.button"), - }, + } as EmptyStatePresetItem, } as const /** @@ -116,20 +123,20 @@ const EmptyStatePresets = { * - [Documentation and Examples](https://github.com/infinitered/ignite/blob/master/docs/Components-EmptyState.md) */ export function EmptyState(props: EmptyStateProps) { - const preset = EmptyStatePresets[props.preset] ? EmptyStatePresets[props.preset] : undefined + const preset = EmptyStatePresets[props.preset ?? "generic"] const { - button = preset?.button, + button = preset.button, buttonTx, buttonOnPress, buttonTxOptions, - content = preset?.content, + content = preset.content, contentTx, contentTxOptions, - heading = preset?.heading, + heading = preset.heading, headingTx, headingTxOptions, - imageSource = preset?.imageSource, + imageSource = preset.imageSource, style: $containerStyleOverride, buttonStyle: $buttonStyleOverride, buttonTextStyle: $buttonTextStyleOverride, diff --git a/boilerplate/app/components/Icon.tsx b/boilerplate/app/components/Icon.tsx index 31035b3ff..00887c4d2 100644 --- a/boilerplate/app/components/Icon.tsx +++ b/boilerplate/app/components/Icon.tsx @@ -7,6 +7,7 @@ import { TouchableOpacity, TouchableOpacityProps, View, + ViewProps, ViewStyle, } from "react-native" @@ -61,9 +62,16 @@ export function Icon(props: IconProps) { } = props const isPressable = !!WrapperProps.onPress - const Wrapper: ComponentType = WrapperProps?.onPress - ? TouchableOpacity - : View + const Wrapper = (WrapperProps?.onPress ? TouchableOpacity : View) as ComponentType< + TouchableOpacityProps | ViewProps + > + + const $imageStyle: StyleProp = [ + $imageStyleBase, + color !== undefined && { tintColor: color }, + size !== undefined && { width: size, height: size }, + $imageStyleOverride, + ] return ( - + ) } @@ -90,25 +90,25 @@ export const iconRegistry = { caretLeft: require("../../assets/icons/caretLeft.png"), caretRight: require("../../assets/icons/caretRight.png"), check: require("../../assets/icons/check.png"), - clap: require("../../assets/icons/clap.png"), - community: require("../../assets/icons/community.png"), - components: require("../../assets/icons/components.png"), - debug: require("../../assets/icons/debug.png"), - github: require("../../assets/icons/github.png"), - heart: require("../../assets/icons/heart.png"), + clap: require("../../assets/icons/demo/clap.png"), // @demo remove-current-line + community: require("../../assets/icons/demo/community.png"), // @demo remove-current-line + components: require("../../assets/icons/demo/components.png"), // @demo remove-current-line + debug: require("../../assets/icons/demo/debug.png"), // @demo remove-current-line + github: require("../../assets/icons/demo/github.png"), // @demo remove-current-line + heart: require("../../assets/icons/demo/heart.png"), // @demo remove-current-line hidden: require("../../assets/icons/hidden.png"), ladybug: require("../../assets/icons/ladybug.png"), lock: require("../../assets/icons/lock.png"), menu: require("../../assets/icons/menu.png"), more: require("../../assets/icons/more.png"), - pin: require("../../assets/icons/pin.png"), - podcast: require("../../assets/icons/podcast.png"), + pin: require("../../assets/icons/demo/pin.png"), // @demo remove-current-line + podcast: require("../../assets/icons/demo/podcast.png"), // @demo remove-current-line settings: require("../../assets/icons/settings.png"), - slack: require("../../assets/icons/slack.png"), + slack: require("../../assets/icons/demo/slack.png"), // @demo remove-current-line view: require("../../assets/icons/view.png"), x: require("../../assets/icons/x.png"), } -const $imageStyle: ImageStyle = { +const $imageStyleBase: ImageStyle = { resizeMode: "contain", } diff --git a/boilerplate/app/components/ListItem.tsx b/boilerplate/app/components/ListItem.tsx index e1d658fe0..4863790bb 100644 --- a/boilerplate/app/components/ListItem.tsx +++ b/boilerplate/app/components/ListItem.tsx @@ -89,7 +89,7 @@ export interface ListItemProps extends TouchableOpacityProps { } interface ListItemActionProps { - icon: IconTypes + icon?: IconTypes iconColor?: string Component?: ReactElement size: number @@ -167,7 +167,7 @@ function ListItemAction(props: ListItemActionProps) { if (Component) return Component - if (icon) { + if (icon !== undefined) { return ( = FlashList | FlatList + +export type ListViewProps = PropsWithoutRef> + +/** + * This is a Higher Order Component meant to ease the pain of using @shopify/flash-list + * when there is a chance that a user would have their device language set to an + * RTL language like Arabic or Punjabi. This component will use react-native's + * FlatList if the user's language is RTL or FlashList if the user's language is LTR. + * + * Because FlashList's props are a superset of FlatList's, you must pass estimatedItemSize + * to this component if you want to use it. + * + * This is a temporary workaround until the FlashList component supports RTL at + * which point this component can be removed and we will default to using FlashList everywhere. + * + * @see {@link https://github.com/Shopify/flash-list/issues/544|RTL Bug Android} + * @see {@link https://github.com/Shopify/flash-list/issues/840|Flashlist Not Support RTL} + * + * @param props - FlashListProps | FlatListProps + * @param forwardRef - React.Ref> + * @returns JSX.Element + */ + +const ListViewComponent = forwardRef( + (props: ListViewProps, ref: React.ForwardedRef>) => { + const ListComponentWrapper = isRTL ? FlatList : FlashList + + return + }, +) + +ListViewComponent.displayName = "ListView" + +export const ListView = ListViewComponent as ( + props: ListViewProps & { + ref?: React.RefObject> + }, +) => React.ReactElement diff --git a/boilerplate/app/components/Screen.tsx b/boilerplate/app/components/Screen.tsx index 9f209bf2a..32ce840aa 100644 --- a/boilerplate/app/components/Screen.tsx +++ b/boilerplate/app/components/Screen.tsx @@ -91,8 +91,8 @@ function useAutoPreset(props: AutoScreenProps) { const { preset, scrollEnabledToggleThreshold } = props const { percent = 0.92, point = 0 } = scrollEnabledToggleThreshold || {} - const scrollViewHeight = useRef(null) - const scrollViewContentHeight = useRef(null) + const scrollViewHeight = useRef(null) + const scrollViewContentHeight = useRef(null) const [scrollEnabled, setScrollEnabled] = useState(true) function updateScrollState() { @@ -155,7 +155,7 @@ function ScreenWithScrolling(props: ScreenProps) { style, } = props as ScrollScreenProps - const ref = useRef() + const ref = useRef(null) const { scrollEnabled, onContentSizeChange, onLayout } = useAutoPreset(props as AutoScreenProps) diff --git a/boilerplate/app/components/Text.tsx b/boilerplate/app/components/Text.tsx index 79265e261..595ad43a2 100644 --- a/boilerplate/app/components/Text.tsx +++ b/boilerplate/app/components/Text.tsx @@ -56,12 +56,12 @@ export function Text(props: TextProps) { const i18nText = tx && translate(tx, txOptions) const content = i18nText || text || children - const preset: Presets = $presets[props.preset] ? props.preset : "default" - const $styles = [ + const preset: Presets = props.preset ?? "default" + const $styles: StyleProp = [ $rtlStyle, $presets[preset], - $fontWeightStyles[weight], - $sizeStyles[size], + weight && $fontWeightStyles[weight], + size && $sizeStyles[size], $styleOverride, ] diff --git a/boilerplate/app/components/TextField.tsx b/boilerplate/app/components/TextField.tsx index 6822a2096..1b42f8ae1 100644 --- a/boilerplate/app/components/TextField.tsx +++ b/boilerplate/app/components/TextField.tsx @@ -123,7 +123,7 @@ export const TextField = forwardRef(function TextField(props: TextFieldProps, re inputWrapperStyle: $inputWrapperStyleOverride, ...TextInputProps } = props - const input = useRef() + const input = useRef(null) const disabled = TextInputProps.editable === false || status === "disabled" @@ -144,7 +144,7 @@ export const TextField = forwardRef(function TextField(props: TextFieldProps, re $inputWrapperStyleOverride, ] - const $inputStyles = [ + const $inputStyles: StyleProp = [ $inputStyle, disabled && { color: colors.textDim }, isRTL && { textAlign: "right" as TextStyle["textAlign"] }, @@ -164,7 +164,7 @@ export const TextField = forwardRef(function TextField(props: TextFieldProps, re input.current?.focus() } - useImperativeHandle(ref, () => input.current) + useImperativeHandle(ref, () => input.current as TextInput) return ( )} @@ -210,7 +210,7 @@ export const TextField = forwardRef(function TextField(props: TextFieldProps, re style={$rightAccessoryStyle} status={status} editable={!disabled} - multiline={TextInputProps.multiline} + multiline={TextInputProps.multiline ?? false} /> )} diff --git a/boilerplate/app/components/Toggle.tsx b/boilerplate/app/components/Toggle.tsx index 7d5cbcc83..47e96d158 100644 --- a/boilerplate/app/components/Toggle.tsx +++ b/boilerplate/app/components/Toggle.tsx @@ -10,6 +10,7 @@ import { TouchableOpacity, TouchableOpacityProps, View, + ViewProps, ViewStyle, } from "react-native" import Animated, { useAnimatedStyle, withTiming } from "react-native-reanimated" @@ -180,8 +181,8 @@ export function Toggle(props: ToggleProps) { const disabled = editable === false || status === "disabled" || props.disabled - const Wrapper = useMemo>( - () => (disabled ? View : TouchableOpacity), + const Wrapper = useMemo( + () => (disabled ? View : TouchableOpacity) as ComponentType, [disabled], ) const ToggleInput = useMemo(() => ToggleInputs[variant] || (() => null), [variant]) @@ -213,12 +214,12 @@ export function Toggle(props: ToggleProps) { {labelPosition === "left" && } @@ -299,8 +300,12 @@ function Checkbox(props: ToggleInputProps) { ]} > @@ -475,7 +480,7 @@ function SwitchAccessibilityLabel(props: ToggleInputProps & { role: "on" | "off" const shouldLabelBeVisible = (on && role === "on") || (!on && role === "off") - const $switchAccessibilityStyle = [ + const $switchAccessibilityStyle: StyleProp = [ $switchAccessibility, role === "off" && { end: "5%" }, role === "on" && { left: "5%" }, diff --git a/boilerplate/app/components/index.ts b/boilerplate/app/components/index.ts index c65532ff4..43506380f 100644 --- a/boilerplate/app/components/index.ts +++ b/boilerplate/app/components/index.ts @@ -4,6 +4,7 @@ export * from "./Card" export * from "./Header" export * from "./Icon" export * from "./ListItem" +export * from "./ListView" export * from "./Screen" export * from "./Text" export * from "./TextField" diff --git a/boilerplate/app/devtools/ReactotronConfig.ts b/boilerplate/app/devtools/ReactotronConfig.ts index d23ab06d8..09a99eea2 100644 --- a/boilerplate/app/devtools/ReactotronConfig.ts +++ b/boilerplate/app/devtools/ReactotronConfig.ts @@ -14,16 +14,14 @@ import { goBack, resetRoot, navigate } from "app/navigators/navigationUtilities" import { Reactotron } from "./ReactotronClient" -Reactotron.configure({ +const reactotron = Reactotron.configure({ name: require("../../package.json").name, host: "localhost", onConnect: () => { /** since this file gets hot reloaded, let's clear the past logs every time we connect */ Reactotron.clear() }, -}) - -Reactotron.use( +}).use( mst({ /** ignore some chatty `mobx-state-tree` actions */ filter: (event) => /postProcessSnapshot|@APPLY_SNAPSHOT/.test(event.name) === false, @@ -31,8 +29,12 @@ Reactotron.use( ) if (Platform.OS !== "web") { - Reactotron.setAsyncStorageHandler(AsyncStorage) - Reactotron.useReactNative() + reactotron.setAsyncStorageHandler?.(AsyncStorage) + reactotron.useReactNative({ + networking: { + ignoreUrls: /symbolicate/, + }, + }) } /** @@ -46,8 +48,7 @@ if (Platform.OS !== "web") { * NOTE: If you edit this file while running the app, you will need to do a full refresh * or else your custom commands won't be registered correctly. */ - -Reactotron.onCustomCommand({ +reactotron.onCustomCommand({ title: "Show Dev Menu", description: "Opens the React Native dev menu", command: "showDevMenu", @@ -57,7 +58,7 @@ Reactotron.onCustomCommand({ }, }) -Reactotron.onCustomCommand({ +reactotron.onCustomCommand({ title: "Reset Root Store", description: "Resets the MST store", command: "resetStore", @@ -67,7 +68,7 @@ Reactotron.onCustomCommand({ }, }) -Reactotron.onCustomCommand({ +reactotron.onCustomCommand({ title: "Reset Navigation State", description: "Resets the navigation state", command: "resetNavigation", @@ -77,28 +78,23 @@ Reactotron.onCustomCommand({ }, }) -Reactotron.onCustomCommand({ +reactotron.onCustomCommand<[{ name: "route"; type: ArgType.String }]>({ command: "navigateTo", handler: (args) => { - const { route } = args + const { route } = args ?? {} if (route) { Reactotron.log(`Navigating to: ${route}`) - navigate(route) + navigate(route as any) // this should be tied to the navigator, but since this is for debugging, we can navigate to illegal routes } else { Reactotron.log("Could not navigate. No route provided.") } }, title: "Navigate To Screen", description: "Navigates to a screen by name.", - args: [ - { - name: "route", - type: ArgType.String, - }, - ], + args: [{ name: "route", type: ArgType.String }], }) -Reactotron.onCustomCommand({ +reactotron.onCustomCommand({ title: "Go Back", description: "Goes back", command: "goBack", @@ -120,7 +116,7 @@ Reactotron.onCustomCommand({ * * Use this power responsibly! :) */ -console.tron = Reactotron +console.tron = reactotron /** * We tell typescript about our dark magic @@ -147,7 +143,7 @@ declare global { * } * */ - tron: typeof Reactotron + tron: typeof reactotron } } @@ -157,22 +153,32 @@ declare global { const ogConsoleLog = console.log console.log = (...args: Parameters) => { ogConsoleLog(...args) - Reactotron.log(...args) + reactotron.log(...args) } const ogConsoleWarn = console.warn console.warn = (...args: Parameters) => { ogConsoleWarn(...args) - Reactotron.warn(args[0]) + reactotron.warn(args[0]) +} + +const ogConsoleError = console.error +console.error = (...args: Parameters) => { + ogConsoleError(...args) + if (args[0] instanceof Error) { + reactotron.error(args[0].message, args[0].stack) + } else { + reactotron.error(args[0], args[1]) + } } const ogConsoleDebug = console.debug console.debug = (...args: Parameters) => { ogConsoleDebug(...args) - Reactotron.debug(args[0]) + reactotron.debug(args[0]) } /** * Now that we've setup all our Reactotron configuration, let's connect! */ -Reactotron.connect() +reactotron.connect() diff --git a/boilerplate/app/models/EpisodeStore.ts b/boilerplate/app/models/EpisodeStore.ts index fdd4e035d..f640d311b 100644 --- a/boilerplate/app/models/EpisodeStore.ts +++ b/boilerplate/app/models/EpisodeStore.ts @@ -17,7 +17,7 @@ export const EpisodeStoreModel = types if (response.kind === "ok") { store.setProp("episodes", response.episodes) } else { - console.tron.error(`Error fetching episodes: ${JSON.stringify(response)}`, []) + console.tron.error?.(`Error fetching episodes: ${JSON.stringify(response)}`, []) } }, addFavorite(episode: Episode) { diff --git a/boilerplate/app/models/helpers/setupRootStore.ts b/boilerplate/app/models/helpers/setupRootStore.ts index 50f2ccf07..039bd86e6 100644 --- a/boilerplate/app/models/helpers/setupRootStore.ts +++ b/boilerplate/app/models/helpers/setupRootStore.ts @@ -21,7 +21,7 @@ const ROOT_STATE_STORAGE_KEY = "root-v1" /** * Setup the root state. */ -let _disposer: IDisposer +let _disposer: IDisposer | undefined export async function setupRootStore(rootStore: RootStore) { let restoredState: RootStoreSnapshot | undefined | null @@ -32,7 +32,7 @@ export async function setupRootStore(rootStore: RootStore) { } catch (e) { // if there's any problems loading, then inform the dev what happened if (__DEV__) { - console.tron.error(e.message, null) + if (e instanceof Error) console.tron.error?.(e.message, null) } } @@ -43,7 +43,7 @@ export async function setupRootStore(rootStore: RootStore) { _disposer = onSnapshot(rootStore, (snapshot) => storage.save(ROOT_STATE_STORAGE_KEY, snapshot)) const unsubscribe = () => { - _disposer() + _disposer?.() _disposer = undefined } diff --git a/boilerplate/app/models/helpers/useStores.ts b/boilerplate/app/models/helpers/useStores.ts index 9303ea16f..68b0cc761 100644 --- a/boilerplate/app/models/helpers/useStores.ts +++ b/boilerplate/app/models/helpers/useStores.ts @@ -53,7 +53,7 @@ export const useInitialRootStore = (callback: () => void | Promise) => { // Kick off initial async loading actions, like loading fonts and rehydrating RootStore useEffect(() => { - let _unsubscribe + let _unsubscribe: () => void | undefined ;(async () => { // set up the RootStore (returns the state restored from AsyncStorage) const { unsubscribe } = await setupRootStore(rootStore) @@ -73,7 +73,7 @@ export const useInitialRootStore = (callback: () => void | Promise) => { return () => { // cleanup - if (_unsubscribe) _unsubscribe() + if (_unsubscribe !== undefined) _unsubscribe() } }, []) diff --git a/boilerplate/app/navigators/DemoNavigator.tsx b/boilerplate/app/navigators/DemoNavigator.tsx index 529d2f798..22f1fb584 100644 --- a/boilerplate/app/navigators/DemoNavigator.tsx +++ b/boilerplate/app/navigators/DemoNavigator.tsx @@ -50,7 +50,7 @@ export function DemoNavigator() { options={{ tabBarLabel: translate("demoNavigator.componentsTab"), tabBarIcon: ({ focused }) => ( - + ), }} /> @@ -61,7 +61,7 @@ export function DemoNavigator() { options={{ tabBarLabel: translate("demoNavigator.communityTab"), tabBarIcon: ({ focused }) => ( - + ), }} /> @@ -73,7 +73,7 @@ export function DemoNavigator() { tabBarAccessibilityLabel: translate("demoNavigator.podcastListTab"), tabBarLabel: translate("demoNavigator.podcastListTab"), tabBarIcon: ({ focused }) => ( - + ), }} /> @@ -84,7 +84,7 @@ export function DemoNavigator() { options={{ tabBarLabel: translate("demoNavigator.debugTab"), tabBarIcon: ({ focused }) => ( - + ), }} /> diff --git a/boilerplate/app/navigators/navigationUtilities.ts b/boilerplate/app/navigators/navigationUtilities.ts index 51b9363c3..a8a8623c3 100644 --- a/boilerplate/app/navigators/navigationUtilities.ts +++ b/boilerplate/app/navigators/navigationUtilities.ts @@ -1,6 +1,10 @@ import { useState, useEffect, useRef } from "react" import { BackHandler, Platform } from "react-native" -import { NavigationState, createNavigationContainerRef } from "@react-navigation/native" +import { + NavigationState, + PartialState, + createNavigationContainerRef, +} from "@react-navigation/native" import Config from "../config" import type { PersistNavigationConfig } from "../config/config.base" import { useIsMounted } from "../utils/useIsMounted" @@ -25,10 +29,8 @@ export const navigationRef = createNavigationContainerRef() /** * Gets the current screen from any navigation state. */ -export function getActiveRouteName( - state: ReturnType, -): keyof AppStackParamList { - const route = state.routes[state.index] +export function getActiveRouteName(state: NavigationState | PartialState): string { + const route = state.routes[state.index ?? 0] // Found the active route -- return the name if (!route.state) return route.name as keyof AppStackParamList @@ -113,22 +115,24 @@ export function useNavigationPersistence(storage: Storage, persistenceKey: strin const routeNameRef = useRef() - const onNavigationStateChange: NavigationProps["onStateChange"] = (state) => { + const onNavigationStateChange = (state: NavigationState | undefined) => { const previousRouteName = routeNameRef.current - const currentRouteName = getActiveRouteName(state) - - if (previousRouteName !== currentRouteName) { - // track screens. - if (__DEV__) { - console.tron.log(currentRouteName) + if (state !== undefined) { + const currentRouteName = getActiveRouteName(state) + + if (previousRouteName !== currentRouteName) { + // track screens. + if (__DEV__) { + console.tron.log?.(currentRouteName) + } } - } - // Save the current route name for later comparison - routeNameRef.current = currentRouteName + // Save the current route name for later comparison + routeNameRef.current = currentRouteName as keyof AppStackParamList - // Persist state to storage - storage.save(persistenceKey, state) + // Persist state to storage + storage.save(persistenceKey, state) + } } const restoreState = async () => { @@ -152,9 +156,10 @@ export function useNavigationPersistence(storage: Storage, persistenceKey: strin * prop. If you have access to the navigation prop, do not use this. * @see https://reactnavigation.org/docs/navigating-without-navigation-prop/ */ -export function navigate(...args: Parameters) { +export function navigate(name: unknown, params?: unknown) { if (navigationRef.isReady()) { - navigationRef.navigate(...args) + // @ts-expect-error + navigationRef.navigate(name as never, params as never) } } diff --git a/boilerplate/app/screens/DemoCommunityScreen.tsx b/boilerplate/app/screens/DemoCommunityScreen.tsx index 50df9ed70..554da41fb 100644 --- a/boilerplate/app/screens/DemoCommunityScreen.tsx +++ b/boilerplate/app/screens/DemoCommunityScreen.tsx @@ -6,10 +6,10 @@ import { spacing } from "../theme" import { openLinkInBrowser } from "../utils/openLinkInBrowser" import { isRTL } from "../i18n" -const chainReactLogo = require("../../assets/images/cr-logo.png") -const reactNativeLiveLogo = require("../../assets/images/rnl-logo.png") -const reactNativeRadioLogo = require("../../assets/images/rnr-logo.png") -const reactNativeNewsletterLogo = require("../../assets/images/rnn-logo.png") +const chainReactLogo = require("../../assets/images/demo/cr-logo.png") +const reactNativeLiveLogo = require("../../assets/images/demo/rnl-logo.png") +const reactNativeRadioLogo = require("../../assets/images/demo/rnr-logo.png") +const reactNativeNewsletterLogo = require("../../assets/images/demo/rnn-logo.png") export const DemoCommunityScreen: FC> = function DemoCommunityScreen(_props) { diff --git a/boilerplate/app/screens/DemoDebugScreen.tsx b/boilerplate/app/screens/DemoDebugScreen.tsx index 4cdeca122..45f6bab97 100644 --- a/boilerplate/app/screens/DemoDebugScreen.tsx +++ b/boilerplate/app/screens/DemoDebugScreen.tsx @@ -19,6 +19,8 @@ export const DemoDebugScreen: FC> = function Dem } = useStores() const usingHermes = typeof HermesInternal === "object" && HermesInternal !== null + // @ts-expect-error + const usingFabric = global.nativeFabricUIManager != null const demoReactotron = React.useMemo( () => async () => { @@ -88,6 +90,14 @@ export const DemoDebugScreen: FC> = function Dem } /> + + Fabric Enabled + {String(usingFabric)} + + } + />