mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
chore(android): target API 36 with Expo 54
Upgrade the mobile runtime and tracked Android project to compile and target API 36. Align Expo modules, React Native, Node, Gradle, and Android build tooling while preserving the custom widget sources.\n\nAdapt file-system, notification, animation, test, and Metro compatibility for the SDK 54 runtime.
This commit is contained in:
1 parent
1be54175e4
commit
f35114dc77
30 files changed
+4061
-5634
No files matched your search
@@ -44,8 +44,8 @@
|
|||||||
"tailwind-merge": "^2.2.0"
|
"tailwind-merge": "^2.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.2.0",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-dom": "^18.2.0",
|
"@types/react-dom": "~19.1.7",
|
||||||
"@vitejs/plugin-react": "^4.2.0",
|
"@vitejs/plugin-react": "^4.2.0",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"postcss": "^8.4.32",
|
"postcss": "^8.4.32",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ react {
|
|||||||
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
|
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
|
||||||
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
|
||||||
|
|
||||||
|
enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean()
|
||||||
// Use Expo CLI to bundle the app, this ensures the Metro config
|
// Use Expo CLI to bundle the app, this ensures the Metro config
|
||||||
// works correctly with Expo projects.
|
// works correctly with Expo projects.
|
||||||
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
|
cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim())
|
||||||
@@ -63,9 +64,9 @@ react {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
* Set this to true in release builds to optimize the app using R8.
|
||||||
*/
|
*/
|
||||||
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
|
def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The preferred build flavor of JavaScriptCore (JSC)
|
* The preferred build flavor of JavaScriptCore (JSC)
|
||||||
@@ -78,7 +79,7 @@ def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInRelea
|
|||||||
* give correct results when using with locales other than en-US. Note that
|
* give correct results when using with locales other than en-US. Note that
|
||||||
* this variant is about 6MiB larger per architecture than default.
|
* this variant is about 6MiB larger per architecture than default.
|
||||||
*/
|
*/
|
||||||
def jscFlavor = 'org.webkit:android-jsc:+'
|
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
ndkVersion rootProject.ext.ndkVersion
|
ndkVersion rootProject.ext.ndkVersion
|
||||||
@@ -93,6 +94,7 @@ android {
|
|||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 46
|
versionCode 46
|
||||||
versionName "1.0.5"
|
versionName "1.0.5"
|
||||||
|
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""
|
||||||
}
|
}
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
debug {
|
debug {
|
||||||
@@ -110,15 +112,18 @@ android {
|
|||||||
// Caution! In production, you need to generate your own keystore file.
|
// Caution! In production, you need to generate your own keystore file.
|
||||||
// see https://reactnative.dev/docs/signed-apk-android.
|
// see https://reactnative.dev/docs/signed-apk-android.
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
|
def enableShrinkResources = findProperty('android.enableShrinkResourcesInReleaseBuilds') ?: 'false'
|
||||||
minifyEnabled enableProguardInReleaseBuilds
|
shrinkResources enableShrinkResources.toBoolean()
|
||||||
|
minifyEnabled enableMinifyInReleaseBuilds
|
||||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||||
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
|
def enablePngCrunchInRelease = findProperty('android.enablePngCrunchInReleaseBuilds') ?: 'true'
|
||||||
|
crunchPngs enablePngCrunchInRelease.toBoolean()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
jniLibs {
|
jniLibs {
|
||||||
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
|
def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false'
|
||||||
|
useLegacyPackaging enableLegacyPackaging.toBoolean()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
androidResources {
|
androidResources {
|
||||||
@@ -156,15 +161,15 @@ dependencies {
|
|||||||
|
|
||||||
if (isGifEnabled) {
|
if (isGifEnabled) {
|
||||||
// For animated gif support
|
// For animated gif support
|
||||||
implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
|
implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isWebpEnabled) {
|
if (isWebpEnabled) {
|
||||||
// For webp support
|
// For webp support
|
||||||
implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
|
implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}")
|
||||||
if (isWebpAnimatedEnabled) {
|
if (isWebpAnimatedEnabled) {
|
||||||
// Animated webp support
|
// Animated webp support
|
||||||
implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
|
implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
@@ -17,7 +21,7 @@
|
|||||||
<data android:scheme="https"/>
|
<data android:scheme="https"/>
|
||||||
</intent>
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:requestLegacyExternalStorage="true" android:fullBackupContent="@xml/secure_store_backup_rules" android:dataExtractionRules="@xml/secure_store_data_extraction_rules">
|
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:requestLegacyExternalStorage="true" android:fullBackupContent="@xml/secure_store_backup_rules" android:dataExtractionRules="@xml/secure_store_data_extraction_rules" android:enableOnBackInvokedCallback="false">
|
||||||
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
|
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color"/>
|
||||||
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
|
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
|
||||||
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
|
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import com.facebook.react.ReactApplication
|
|||||||
import com.facebook.react.ReactNativeHost
|
import com.facebook.react.ReactNativeHost
|
||||||
import com.facebook.react.ReactPackage
|
import com.facebook.react.ReactPackage
|
||||||
import com.facebook.react.ReactHost
|
import com.facebook.react.ReactHost
|
||||||
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
|
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
||||||
|
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint
|
||||||
import com.facebook.react.defaults.DefaultReactNativeHost
|
import com.facebook.react.defaults.DefaultReactNativeHost
|
||||||
import com.facebook.react.soloader.OpenSourceMergedSoMapping
|
import com.facebook.react.common.ReleaseLevel
|
||||||
import com.facebook.soloader.SoLoader
|
|
||||||
|
|
||||||
import expo.modules.ApplicationLifecycleDispatcher
|
import expo.modules.ApplicationLifecycleDispatcher
|
||||||
import expo.modules.ReactNativeHostWrapper
|
import expo.modules.ReactNativeHostWrapper
|
||||||
@@ -42,11 +42,12 @@ class MainApplication : Application(), ReactApplication {
|
|||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
SoLoader.init(this, OpenSourceMergedSoMapping)
|
DefaultNewArchitectureEntryPoint.releaseLevel = try {
|
||||||
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase())
|
||||||
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
} catch (e: IllegalArgumentException) {
|
||||||
load()
|
ReleaseLevel.STABLE
|
||||||
}
|
}
|
||||||
|
loadReactNative(this)
|
||||||
ApplicationLifecycleDispatcher.onApplicationCreate(this)
|
ApplicationLifecycleDispatcher.onApplicationCreate(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
<item name="android:enforceNavigationBarContrast" tools:targetApi="29">true</item>
|
||||||
<item name="android:textColor">@android:color/black</item>
|
<item name="android:textColor">@android:color/black</item>
|
||||||
<item name="android:editTextStyle">@style/ResetEditText</item>
|
<item name="android:editTextStyle">@style/ResetEditText</item>
|
||||||
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
|
||||||
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
|
|
||||||
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
|
|
||||||
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
|
|
||||||
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
|
|
||||||
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.25'
|
|
||||||
|
|
||||||
ndkVersion = "26.1.10909125"
|
|
||||||
}
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -19,23 +10,15 @@ buildscript {
|
|||||||
classpath 'com.google.gms:google-services:4.4.1'
|
classpath 'com.google.gms:google-services:4.4.1'
|
||||||
classpath('com.android.tools.build:gradle')
|
classpath('com.android.tools.build:gradle')
|
||||||
classpath('com.facebook.react:react-native-gradle-plugin')
|
classpath('com.facebook.react:react-native-gradle-plugin')
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
|
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply plugin: "expo-root-project"
|
||||||
apply plugin: "com.facebook.react.rootproject"
|
apply plugin: "com.facebook.react.rootproject"
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
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', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim(), '../dist'))
|
|
||||||
}
|
|
||||||
|
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url 'https://www.jitpack.io' }
|
maven { url 'https://www.jitpack.io' }
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
|||||||
# your application. You should enable this flag either if you want
|
# your application. You should enable this flag either if you want
|
||||||
# to write custom TurboModules/Fabric components OR use libraries that
|
# to write custom TurboModules/Fabric components OR use libraries that
|
||||||
# are providing them.
|
# are providing them.
|
||||||
newArchEnabled=false
|
newArchEnabled=true
|
||||||
|
|
||||||
# Use this property to enable or disable the Hermes JS engine.
|
# Use this property to enable or disable the Hermes JS engine.
|
||||||
# If set to false, you will be using JSC instead.
|
# If set to false, you will be using JSC instead.
|
||||||
@@ -55,6 +55,16 @@ EX_DEV_CLIENT_NETWORK_INSPECTOR=true
|
|||||||
# Use legacy packaging to compress native libraries in the resulting APK.
|
# Use legacy packaging to compress native libraries in the resulting APK.
|
||||||
expo.useLegacyPackaging=false
|
expo.useLegacyPackaging=false
|
||||||
|
|
||||||
android.targetSdkVersion=35
|
android.targetSdkVersion=36
|
||||||
android.kotlinVersion=1.9.25
|
|
||||||
android.extraMavenRepos=[]
|
android.extraMavenRepos=[]
|
||||||
|
# Specifies whether the app is configured to use edge-to-edge via the app config or plugin
|
||||||
|
# WARNING: This property has been deprecated and will be removed in Expo SDK 55. Use `edgeToEdgeEnabled` or `react.edgeToEdgeEnabled` to determine whether the project is using edge-to-edge.
|
||||||
|
expo.edgeToEdgeEnabled=true
|
||||||
|
|
||||||
|
# Use this property to enable edge-to-edge display support.
|
||||||
|
# This allows your app to draw behind system bars for an immersive UI.
|
||||||
|
# Note: Only works with ReactActivity and should not be used with custom Activity.
|
||||||
|
edgeToEdgeEnabled=true
|
||||||
|
|
||||||
|
android.compileSdkVersion=36
|
||||||
|
android.buildToolsVersion=36.0.0
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -1,38 +1,39 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().toString())
|
def reactNativeGradlePlugin = new File(
|
||||||
|
providers.exec {
|
||||||
|
workingDir(rootDir)
|
||||||
|
commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
|
||||||
|
}.standardOutput.asText.get().trim()
|
||||||
|
).getParentFile().absolutePath
|
||||||
|
includeBuild(reactNativeGradlePlugin)
|
||||||
|
|
||||||
|
def expoPluginsPath = new File(
|
||||||
|
providers.exec {
|
||||||
|
workingDir(rootDir)
|
||||||
|
commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
|
||||||
|
}.standardOutput.asText.get().trim(),
|
||||||
|
"../android/expo-gradle-plugin"
|
||||||
|
).absolutePath
|
||||||
|
includeBuild(expoPluginsPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("com.facebook.react.settings")
|
||||||
|
id("expo-autolinking-settings")
|
||||||
}
|
}
|
||||||
plugins { id("com.facebook.react.settings") }
|
|
||||||
|
|
||||||
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
|
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
|
||||||
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
|
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
|
||||||
ex.autolinkLibrariesFromCommand()
|
ex.autolinkLibrariesFromCommand()
|
||||||
} else {
|
} else {
|
||||||
def command = [
|
ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
|
||||||
'node',
|
|
||||||
'--no-warnings',
|
|
||||||
'--eval',
|
|
||||||
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
|
|
||||||
'react-native-config',
|
|
||||||
'--json',
|
|
||||||
'--platform',
|
|
||||||
'android'
|
|
||||||
].toList()
|
|
||||||
ex.autolinkLibrariesFromCommand(command)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = 'Sauci'
|
rootProject.name = 'Sauci'
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
expoAutolinking.useExpoModules()
|
||||||
versionCatalogs {
|
expoAutolinking.useExpoVersionCatalog()
|
||||||
reactAndroidLibs {
|
|
||||||
from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../gradle/libs.versions.toml")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle");
|
|
||||||
useExpoModules()
|
|
||||||
|
|
||||||
include ':app'
|
include ':app'
|
||||||
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile())
|
includeBuild(expoAutolinking.reactNativeGradlePlugin)
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
"icon": "./assets/icon.png",
|
"icon": "./assets/icon.png",
|
||||||
"scheme": "app.sauci",
|
"scheme": "app.sauci",
|
||||||
"userInterfaceStyle": "automatic",
|
"userInterfaceStyle": "automatic",
|
||||||
"newArchEnabled": false,
|
"newArchEnabled": true,
|
||||||
"splash": {
|
"splash": {
|
||||||
"image": "./assets/splash-icon.png",
|
"image": "./assets/splash-icon.png",
|
||||||
"resizeMode": "contain",
|
"resizeMode": "contain",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"NSPhotoLibraryAddUsageDescription": "Sauci saves photos and videos from your partner's messages to your photo library when you tap the save button.",
|
"NSPhotoLibraryAddUsageDescription": "Sauci saves photos and videos from your partner's messages to your photo library when you tap the save button.",
|
||||||
"NSMicrophoneUsageDescription": "Sauci uses your microphone to record audio when you capture videos to share privately with your partner."
|
"NSMicrophoneUsageDescription": "Sauci uses your microphone to record audio when you capture videos to share privately with your partner."
|
||||||
},
|
},
|
||||||
"privacyManifest": {
|
"privacyManifests": {
|
||||||
"NSPrivacyTracking": false,
|
"NSPrivacyTracking": false,
|
||||||
"NSPrivacyCollectedDataTypes": [
|
"NSPrivacyCollectedDataTypes": [
|
||||||
{
|
{
|
||||||
@@ -205,8 +205,9 @@
|
|||||||
"expo-build-properties",
|
"expo-build-properties",
|
||||||
{
|
{
|
||||||
"android": {
|
"android": {
|
||||||
"targetSdkVersion": 35,
|
"buildToolsVersion": "36.0.0",
|
||||||
"kotlinVersion": "1.9.25",
|
"compileSdkVersion": 36,
|
||||||
|
"targetSdkVersion": 36,
|
||||||
"extraProguardRules": "-keep class com.facebook.hermes.unicode.** { *; }",
|
"extraProguardRules": "-keep class com.facebook.hermes.unicode.** { *; }",
|
||||||
"useLegacyPackaging": false,
|
"useLegacyPackaging": false,
|
||||||
"manifestPlaceholders": {
|
"manifestPlaceholders": {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export default function AppLayout() {
|
|||||||
const { initializeRevenueCat, refreshSubscriptionStatus } = useSubscriptionStore();
|
const { initializeRevenueCat, refreshSubscriptionStatus } = useSubscriptionStore();
|
||||||
const { fetchStreak } = useStreakStore();
|
const { fetchStreak } = useStreakStore();
|
||||||
const messageToastAnim = useRef(new Animated.Value(-100)).current;
|
const messageToastAnim = useRef(new Animated.Value(-100)).current;
|
||||||
const messageTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
const messageTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
const [isLocked, setIsLocked] = useState(false);
|
const [isLocked, setIsLocked] = useState(false);
|
||||||
const hasCheckedInitialBiometric = useRef(false);
|
const hasCheckedInitialBiometric = useRef(false);
|
||||||
const wentToBackgroundAt = useRef<number | null>(null);
|
const wentToBackgroundAt = useRef<number | null>(null);
|
||||||
|
|||||||
@@ -5,19 +5,19 @@
|
|||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"development": {
|
"development": {
|
||||||
"node": "20.10.0",
|
"node": "20.19.4",
|
||||||
"developmentClient": true,
|
"developmentClient": true,
|
||||||
"distribution": "internal"
|
"distribution": "internal"
|
||||||
},
|
},
|
||||||
"preview": {
|
"preview": {
|
||||||
"node": "20.10.0",
|
"node": "20.19.4",
|
||||||
"distribution": "internal",
|
"distribution": "internal",
|
||||||
"env": {
|
"env": {
|
||||||
"EXPO_PUBLIC_API_URL": "https://api.preprod.sauci.app"
|
"EXPO_PUBLIC_API_URL": "https://api.preprod.sauci.app"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"node": "20.10.0",
|
"node": "20.19.4",
|
||||||
"autoIncrement": true,
|
"autoIncrement": true,
|
||||||
"env": {
|
"env": {
|
||||||
"EXPO_PUBLIC_API_URL": "https://api.sauci.app",
|
"EXPO_PUBLIC_API_URL": "https://api.sauci.app",
|
||||||
|
|||||||
@@ -1,33 +1,3 @@
|
|||||||
const { getDefaultConfig } = require('expo/metro-config');
|
const { getDefaultConfig } = require('expo/metro-config');
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
// Find the project and workspace directories
|
module.exports = getDefaultConfig(__dirname);
|
||||||
const projectRoot = __dirname;
|
|
||||||
const workspaceRoot = path.resolve(projectRoot, '../..');
|
|
||||||
|
|
||||||
const config = getDefaultConfig(projectRoot);
|
|
||||||
|
|
||||||
// 1. Watch all files within the monorepo
|
|
||||||
// 1. Watch only relevant folders to improve performance on Windows
|
|
||||||
// watching the entire workspaceRoot is too slow
|
|
||||||
config.watchFolders = [
|
|
||||||
path.resolve(workspaceRoot, 'node_modules'),
|
|
||||||
path.resolve(workspaceRoot, 'packages/shared')
|
|
||||||
];
|
|
||||||
|
|
||||||
// 2. Let Metro know where to resolve packages and in which order
|
|
||||||
config.resolver.nodeModulesPaths = [
|
|
||||||
path.resolve(projectRoot, 'node_modules'),
|
|
||||||
path.resolve(workspaceRoot, 'node_modules'),
|
|
||||||
];
|
|
||||||
|
|
||||||
// 3. Force Metro to resolve (sub)dependencies from the `node_modules`
|
|
||||||
// of the workspace root, unless they are installed in the project root.
|
|
||||||
config.resolver.disableHierarchicalLookup = true;
|
|
||||||
|
|
||||||
// 4. Keep extraNodeModules in case we need to add monorepo overrides later
|
|
||||||
config.resolver.extraNodeModules = {
|
|
||||||
...config.resolver.extraNodeModules,
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = config;
|
|
||||||
+44
-43
@@ -23,8 +23,8 @@
|
|||||||
"@bacons/apple-targets": "^0.1.6",
|
"@bacons/apple-targets": "^0.1.6",
|
||||||
"@bittingz/expo-widgets": "^3.0.2",
|
"@bittingz/expo-widgets": "^3.0.2",
|
||||||
"@expo/ngrok": "^4.1.0",
|
"@expo/ngrok": "^4.1.0",
|
||||||
"@expo/vector-icons": "~14.0.4",
|
"@expo/vector-icons": "^15.0.3",
|
||||||
"@react-native-async-storage/async-storage": "1.23.1",
|
"@react-native-async-storage/async-storage": "2.2.0",
|
||||||
"@react-native-community/cli": "^20.1.1",
|
"@react-native-community/cli": "^20.1.1",
|
||||||
"@react-native-firebase/analytics": "^23.8.2",
|
"@react-native-firebase/analytics": "^23.8.2",
|
||||||
"@react-native-firebase/app": "^23.8.2",
|
"@react-native-firebase/app": "^23.8.2",
|
||||||
@@ -33,63 +33,64 @@
|
|||||||
"@react-navigation/bottom-tabs": "^7.0.0",
|
"@react-navigation/bottom-tabs": "^7.0.0",
|
||||||
"@react-navigation/native": "^7.0.0",
|
"@react-navigation/native": "^7.0.0",
|
||||||
"@react-navigation/native-stack": "^7.0.0",
|
"@react-navigation/native-stack": "^7.0.0",
|
||||||
"@shopify/react-native-skia": "^1.12.4",
|
"@shopify/react-native-skia": "2.2.12",
|
||||||
"@supabase/supabase-js": "^2.39.0",
|
"@supabase/supabase-js": "^2.39.0",
|
||||||
"@tanstack/react-query": "^5.17.0",
|
"@tanstack/react-query": "^5.17.0",
|
||||||
"babel-preset-expo": "~12.0.0",
|
"babel-preset-expo": "~54.0.12",
|
||||||
"base64-arraybuffer": "^1.0.2",
|
"base64-arraybuffer": "^1.0.2",
|
||||||
"expo": "~52.0.0",
|
"expo": "~54.0.0",
|
||||||
"expo-apple-authentication": "~7.1.3",
|
"expo-apple-authentication": "~8.0.8",
|
||||||
"expo-asset": "~11.0.5",
|
"expo-asset": "~12.0.13",
|
||||||
"expo-av": "~15.0.2",
|
"expo-av": "~16.0.8",
|
||||||
"expo-blur": "~14.0.3",
|
"expo-blur": "~15.0.8",
|
||||||
"expo-build-properties": "^0.13.3",
|
"expo-build-properties": "~1.0.10",
|
||||||
"expo-clipboard": "~7.0.1",
|
"expo-clipboard": "~8.0.8",
|
||||||
"expo-constants": "~17.0.0",
|
"expo-constants": "~18.0.14",
|
||||||
"expo-dev-client": "~5.0.20",
|
"expo-dev-client": "~6.0.21",
|
||||||
"expo-file-system": "~18.0.12",
|
"expo-file-system": "~19.0.24",
|
||||||
"expo-font": "~13.0.4",
|
"expo-font": "~14.0.12",
|
||||||
"expo-haptics": "~14.0.1",
|
"expo-haptics": "~15.0.8",
|
||||||
"expo-image": "~2.0.7",
|
"expo-image": "~3.0.11",
|
||||||
"expo-image-picker": "~16.0.6",
|
"expo-image-picker": "~17.0.11",
|
||||||
"expo-linear-gradient": "~14.0.2",
|
"expo-linear-gradient": "~15.0.8",
|
||||||
"expo-linking": "~7.0.0",
|
"expo-linking": "~8.0.12",
|
||||||
"expo-local-authentication": "~15.0.2",
|
"expo-local-authentication": "~17.0.9",
|
||||||
"expo-media-library": "~17.0.6",
|
"expo-media-library": "~18.2.1",
|
||||||
"expo-notifications": "~0.29.0",
|
"expo-notifications": "~0.32.17",
|
||||||
"expo-router": "~4.0.0",
|
"expo-router": "~6.0.24",
|
||||||
"expo-secure-store": "~14.0.0",
|
"expo-secure-store": "~15.0.8",
|
||||||
"expo-sharing": "~13.0.1",
|
"expo-sharing": "~14.0.8",
|
||||||
"expo-status-bar": "~2.0.0",
|
"expo-status-bar": "~3.0.9",
|
||||||
"react": "18.3.1",
|
"react": "19.1.0",
|
||||||
"react-dom": "18.3.1",
|
"react-dom": "19.1.0",
|
||||||
"react-native": "0.76.9",
|
"react-native": "0.81.5",
|
||||||
"react-native-android-widget": "^0.17.2",
|
"react-native-android-widget": "^0.22.1",
|
||||||
"react-native-compressor": "^1.13.0",
|
"react-native-compressor": "^1.13.0",
|
||||||
"react-native-gesture-handler": "~2.20.0",
|
"react-native-gesture-handler": "~2.28.0",
|
||||||
"react-native-purchases": "^9.6.12",
|
"react-native-purchases": "^9.6.12",
|
||||||
"react-native-reanimated": "~3.16.0",
|
"react-native-reanimated": "~4.1.1",
|
||||||
"react-native-safe-area-context": "4.12.0",
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
"react-native-screens": "~4.4.0",
|
"react-native-screens": "~4.16.0",
|
||||||
"react-native-svg": "15.8.0",
|
"react-native-svg": "15.12.1",
|
||||||
"react-native-url-polyfill": "^2.0.0",
|
"react-native-url-polyfill": "^2.0.0",
|
||||||
"react-native-view-shot": "^4.0.3",
|
"react-native-view-shot": "^4.0.3",
|
||||||
"react-native-web": "~0.19.13",
|
"react-native-web": "~0.21.0",
|
||||||
|
"react-native-worklets": "0.5.1",
|
||||||
"zustand": "^4.4.7"
|
"zustand": "^4.4.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.24.0",
|
"@babel/core": "^7.24.0",
|
||||||
"@testing-library/jest-native": "^5.4.3",
|
"@testing-library/jest-native": "^5.4.3",
|
||||||
"@testing-library/react-native": "^13.3.3",
|
"@testing-library/react-native": "^13.3.3",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "29.5.14",
|
||||||
"@types/react": "~18.3.12",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-test-renderer": "^19.1.0",
|
"@types/react-test-renderer": "^19.1.0",
|
||||||
"dotenv-cli": "^11.0.0",
|
"dotenv-cli": "^11.0.0",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-expo": "~8.0.1",
|
"eslint-config-expo": "~10.0.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-expo": "~52.0.0",
|
"jest-expo": "~54.0.18",
|
||||||
"react-test-renderer": "^18.3.1",
|
"react-test-renderer": "19.1.0",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "~5.9.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { renderHook, act, waitFor } from '@testing-library/react-native';
|
import { renderHook, act, waitFor } from '@testing-library/react-native';
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import * as MediaLibrary from 'expo-media-library';
|
import * as MediaLibrary from 'expo-media-library';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
import { useMediaSaver } from '@/hooks/useMediaSaver';
|
import { useMediaSaver } from '@/hooks/useMediaSaver';
|
||||||
|
|
||||||
// Mock expo-media-library
|
// Mock expo-media-library
|
||||||
@@ -11,7 +11,7 @@ jest.mock('expo-media-library', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Mock expo-file-system with all required methods
|
// Mock expo-file-system with all required methods
|
||||||
jest.mock('expo-file-system', () => ({
|
jest.mock('expo-file-system/legacy', () => ({
|
||||||
readAsStringAsync: jest.fn(async () => ''),
|
readAsStringAsync: jest.fn(async () => ''),
|
||||||
downloadAsync: jest.fn(),
|
downloadAsync: jest.fn(),
|
||||||
deleteAsync: jest.fn(),
|
deleteAsync: jest.fn(),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import ViewShot from "react-native-view-shot";
|
import ViewShot from "react-native-view-shot";
|
||||||
import * as Sharing from "expo-sharing";
|
import * as Sharing from "expo-sharing";
|
||||||
import * as FileSystem from "expo-file-system";
|
import * as FileSystem from "expo-file-system/legacy";
|
||||||
import { colors, gradients, radius, typography, spacing, blur } from "../../theme";
|
import { colors, gradients, radius, typography, spacing, blur } from "../../theme";
|
||||||
|
|
||||||
const logo = require("../../../assets/logo.png");
|
const logo = require("../../../assets/logo.png");
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { View, StyleSheet } from 'react-native';
|
import { View, StyleSheet } from 'react-native';
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
import Animated, { type AnimatedStyleProp } from 'react-native-reanimated';
|
import Animated, { type AnimatedStyle } from 'react-native-reanimated';
|
||||||
import type { ViewStyle } from 'react-native';
|
import type { ViewStyle } from 'react-native';
|
||||||
import type { IntensityLevel } from '@/types';
|
import type { IntensityLevel } from '@/types';
|
||||||
import { HEAT_COLORS } from './constants';
|
import { HEAT_COLORS } from './constants';
|
||||||
@@ -9,7 +9,7 @@ import { styles } from './styles';
|
|||||||
|
|
||||||
interface IntensitySliderTrackProps {
|
interface IntensitySliderTrackProps {
|
||||||
value: IntensityLevel;
|
value: IntensityLevel;
|
||||||
progressStyle: AnimatedStyleProp<ViewStyle>;
|
progressStyle: AnimatedStyle<ViewStyle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IntensitySliderTrack({ value, progressStyle }: IntensitySliderTrackProps) {
|
export function IntensitySliderTrack({ value, progressStyle }: IntensitySliderTrackProps) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { Ionicons } from '@expo/vector-icons';
|
|||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import ViewShot from 'react-native-view-shot';
|
import ViewShot from 'react-native-view-shot';
|
||||||
import * as Sharing from 'expo-sharing';
|
import * as Sharing from 'expo-sharing';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
import { colors, gradients, radius, typography, spacing, blur } from '../../../theme';
|
import { colors, gradients, radius, typography, spacing, blur } from '../../../theme';
|
||||||
|
|
||||||
const logo = require('../../../../assets/logo.png');
|
const logo = require('../../../../assets/logo.png');
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import type { SkImage } from '@shopify/react-native-skia';
|
import type { SkImage } from '@shopify/react-native-skia';
|
||||||
import * as MediaLibrary from 'expo-media-library';
|
import * as MediaLibrary from 'expo-media-library';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
|
|
||||||
interface UseCanvasCaptureReturn {
|
interface UseCanvasCaptureReturn {
|
||||||
makeSnapshot: React.MutableRefObject<(() => SkImage | null) | null>;
|
makeSnapshot: React.MutableRefObject<(() => SkImage | null) | null>;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState, useCallback, useRef } from 'react';
|
import { useState, useCallback, useRef } from 'react';
|
||||||
import { Alert, Platform, ActionSheetIOS } from 'react-native';
|
import { Alert, Platform, ActionSheetIOS } from 'react-native';
|
||||||
import * as ImagePicker from 'expo-image-picker';
|
import * as ImagePicker from 'expo-image-picker';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
import { uploadMedia } from '../lib/mediaApi';
|
import { uploadMedia } from '../lib/mediaApi';
|
||||||
|
|
||||||
export interface UseAvatarPickerOptions {
|
export interface UseAvatarPickerOptions {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import * as MediaLibrary from 'expo-media-library';
|
import * as MediaLibrary from 'expo-media-library';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
|
|
||||||
export function useMediaSaver() {
|
export function useMediaSaver() {
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { getMediaUrl, mediaId } from './mediaApi';
|
import { getMediaUrl, mediaId } from './mediaApi';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
// Cache for signed URLs with expiration tracking
|
// Cache for signed URLs with expiration tracking
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import * as FileSystem from 'expo-file-system';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
import { decode } from 'base64-arraybuffer';
|
import { decode } from 'base64-arraybuffer';
|
||||||
import { ApiError, apiClient, authenticatedFetch } from './apiClient';
|
import { ApiError, apiClient, authenticatedFetch } from './apiClient';
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import { useMatchStore } from "../store/matchStore";
|
|||||||
Notifications.setNotificationHandler({
|
Notifications.setNotificationHandler({
|
||||||
handleNotification: async () => ({
|
handleNotification: async () => ({
|
||||||
shouldShowAlert: false,
|
shouldShowAlert: false,
|
||||||
|
shouldShowBanner: false,
|
||||||
|
shouldShowList: false,
|
||||||
shouldPlaySound: false,
|
shouldPlaySound: false,
|
||||||
shouldSetBadge: false,
|
shouldSetBadge: false,
|
||||||
}),
|
}),
|
||||||
@@ -27,6 +29,21 @@ export interface NotificationData {
|
|||||||
count?: number;
|
count?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const notificationTypes = new Set<NotificationData["type"]>([
|
||||||
|
"match",
|
||||||
|
"message",
|
||||||
|
"match_digest",
|
||||||
|
"partner_activity",
|
||||||
|
"nudge",
|
||||||
|
"weekly_summary",
|
||||||
|
]);
|
||||||
|
|
||||||
|
function isNotificationData(value: unknown): value is NotificationData {
|
||||||
|
if (!value || typeof value !== "object") return false;
|
||||||
|
const type = (value as { type?: unknown }).type;
|
||||||
|
return typeof type === "string" && notificationTypes.has(type as NotificationData["type"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request notification permissions and get Expo push token.
|
* Request notification permissions and get Expo push token.
|
||||||
@@ -219,9 +236,9 @@ export async function checkAndRegisterPushToken(userId: string): Promise<boolean
|
|||||||
export function handleNotificationResponse(
|
export function handleNotificationResponse(
|
||||||
response: Notifications.NotificationResponse
|
response: Notifications.NotificationResponse
|
||||||
): void {
|
): void {
|
||||||
const data = response.notification.request.content.data as NotificationData;
|
const data = response.notification.request.content.data;
|
||||||
|
|
||||||
if (!data) {
|
if (!isNotificationData(data)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,13 +103,26 @@ jest.mock('expo-image-picker', () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('expo-file-system', () => ({
|
jest.mock('expo-file-system/legacy', () => ({
|
||||||
readAsStringAsync: jest.fn(async () => ''),
|
readAsStringAsync: jest.fn(async () => ''),
|
||||||
EncodingType: {
|
EncodingType: {
|
||||||
Base64: 'base64',
|
Base64: 'base64',
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('expo-av', () => ({
|
||||||
|
Audio: {
|
||||||
|
requestPermissionsAsync: jest.fn(async () => ({ status: 'granted' })),
|
||||||
|
setAudioModeAsync: jest.fn(async () => undefined),
|
||||||
|
Recording: {
|
||||||
|
createAsync: jest.fn(),
|
||||||
|
},
|
||||||
|
RecordingOptionsPresets: {
|
||||||
|
HIGH_QUALITY: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('react-native-compressor', () => ({
|
jest.mock('react-native-compressor', () => ({
|
||||||
Video: {
|
Video: {
|
||||||
compress: jest.fn(async (uri: string) => uri),
|
compress: jest.fn(async (uri: string) => uri),
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.0.0",
|
"@types/node": "^20.0.0",
|
||||||
"@types/react": "^18.3.0",
|
"@types/react": "~19.1.10",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "~19.1.7",
|
||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
"eslint-config-next": "14.2.35",
|
"eslint-config-next": "14.2.35",
|
||||||
|
|||||||
Generated
+3853
-5466
File diff suppressed because it is too large.
Load diff
+12
-2
@@ -34,8 +34,18 @@
|
|||||||
"clean": "turbo clean",
|
"clean": "turbo clean",
|
||||||
"typecheck": "turbo typecheck"
|
"typecheck": "turbo typecheck"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"expo-router": "~6.0.24",
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"react-native-safe-area-context": "~5.6.0",
|
||||||
|
"react-native-screens": "~4.16.0"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/react": "~19.1.10",
|
||||||
|
"@types/react-dom": "~19.1.7",
|
||||||
"patch-package": "^8.0.1",
|
"patch-package": "^8.0.1",
|
||||||
|
"react-test-renderer": "19.1.0",
|
||||||
"supabase": "^2.39.2",
|
"supabase": "^2.39.2",
|
||||||
"pg": "^8.17.2",
|
"pg": "^8.17.2",
|
||||||
"turbo": "^2.3.3",
|
"turbo": "^2.3.3",
|
||||||
@@ -48,8 +58,8 @@
|
|||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"rollup": "4.54.0",
|
"rollup": "4.54.0",
|
||||||
"react-native": "0.76.9",
|
"react-native": "0.81.5",
|
||||||
"expo": "~52.0.0"
|
"expo": "~54.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.54.0",
|
"@rollup/rollup-linux-arm64-musl": "4.54.0",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const path = require('path');
|
|||||||
|
|
||||||
const ROOT = path.resolve(__dirname, '..');
|
const ROOT = path.resolve(__dirname, '..');
|
||||||
const MOBILE_NM = path.join(ROOT, 'apps', 'mobile', 'node_modules');
|
const MOBILE_NM = path.join(ROOT, 'apps', 'mobile', 'node_modules');
|
||||||
|
const WEB_NM = path.join(ROOT, 'apps', 'web', 'node_modules');
|
||||||
const ROOT_NM = path.join(ROOT, 'node_modules');
|
const ROOT_NM = path.join(ROOT, 'node_modules');
|
||||||
|
|
||||||
// Packages that must live in apps/mobile/node_modules, not root
|
// Packages that must live in apps/mobile/node_modules, not root
|
||||||
@@ -40,3 +41,25 @@ for (const pkg of PACKAGES_TO_FIX) {
|
|||||||
fs.renameSync(rootPkg, localPkg);
|
fs.renameSync(rootPkg, localPkg);
|
||||||
console.log(`fix-hoisting: moved ${pkg} → apps/mobile/node_modules/`);
|
console.log(`fix-hoisting: moved ${pkg} → apps/mobile/node_modules/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Next and its React-facing tooling must resolve the web workspace's React 18
|
||||||
|
// runtime, not the React 19 runtime hoisted for Expo SDK 54 / React Native.
|
||||||
|
for (const pkg of ['next', 'styled-jsx', 'eslint-config-next']) {
|
||||||
|
const rootPkg = path.join(ROOT_NM, pkg);
|
||||||
|
const localPkg = path.join(WEB_NM, pkg);
|
||||||
|
if (!fs.existsSync(rootPkg) || fs.existsSync(localPkg)) continue;
|
||||||
|
|
||||||
|
fs.mkdirSync(WEB_NM, { recursive: true });
|
||||||
|
fs.renameSync(rootPkg, localPkg);
|
||||||
|
console.log(`fix-hoisting: moved ${pkg} → apps/web/node_modules/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const localNext = path.join(WEB_NM, 'next');
|
||||||
|
if (fs.existsSync(localNext)) {
|
||||||
|
const localBinDir = path.join(WEB_NM, '.bin');
|
||||||
|
const localBin = path.join(localBinDir, 'next');
|
||||||
|
fs.mkdirSync(localBinDir, { recursive: true });
|
||||||
|
if (!fs.existsSync(localBin)) {
|
||||||
|
fs.symlinkSync(path.join('..', 'next', 'dist', 'bin', 'next'), localBin);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user