diff --git a/.github/workflows/feature_test.yml b/.github/workflows/feature_test.yml index 1e19b75421..0292f655fa 100644 --- a/.github/workflows/feature_test.yml +++ b/.github/workflows/feature_test.yml @@ -34,6 +34,10 @@ on: required: false type: boolean default: false + RABBY_MOBILE_NEW_ARCH_ENABLED: + required: false + type: boolean + default: true defaults: run: @@ -125,8 +129,6 @@ jobs: RABBY_MOBILE_UNLOCK_KEYCHAIN_PASS=${{ secrets.KEYCHAIN_PASS }} fi security unlock-keychain -p $RABBY_MOBILE_UNLOCK_KEYCHAIN_PASS login.keychain - # cd ios && bundle install && bundle exec pod install --deployment; - # cd ../; ./scripts/deploy-ios-adhoc.sh # # cleanup packager @@ -150,6 +152,7 @@ jobs: SENTRY_DISABLE_AUTO_UPLOAD: ${{ inputs.SENTRY_DISABLE_AUTO_UPLOAD }} DISABLE_AWS_CLI_HTTPS_VALIDATION: ${{ inputs.__DANGEROUS_NO_VERIFY_SSL }} GHA_MOCK_BUILD_FAILED: ${{ inputs.GHA_MOCK_BUILD_FAILED }} + RABBY_MOBILE_NEW_ARCH_ENABLED: ${{ inputs.RABBY_MOBILE_NEW_ARCH_ENABLED }} CONFIGURATION: release TYPE: adhoc RABBY_MOBILE_BUILD_ENV: regression diff --git a/.yarn/patches/@gorhom-bottom-sheet-npm-5.1.8-d4532753f1.patch b/.yarn/patches/@gorhom-bottom-sheet-npm-5.1.8-d4532753f1.patch new file mode 100644 index 0000000000..96ca61ada3 --- /dev/null +++ b/.yarn/patches/@gorhom-bottom-sheet-npm-5.1.8-d4532753f1.patch @@ -0,0 +1,26 @@ +diff --git a/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx b/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx +index d721fee7a0b133027df45d00d6fcf07e66b797f4..34e7982120159917291a3e8ec02973f2be659113 100644 +--- a/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx ++++ b/src/components/bottomSheetDraggableView/BottomSheetDraggableView.tsx +@@ -30,7 +30,7 @@ const BottomSheetDraggableViewComponent = ({ + + //#region variables + const simultaneousHandlers = useMemo(() => { +- const refs = []; ++ const refs: any[] = []; + + if (nativeGestureRef) { + refs.push(nativeGestureRef); +diff --git a/src/components/bottomSheetHandle/BottomSheetHandleContainer.tsx b/src/components/bottomSheetHandle/BottomSheetHandleContainer.tsx +index 9b6a054459bb7f109249d80c5ffde3c395fa70eb..c52f43a02b2882b0ffbeb99857f4b011cb2e1327 100644 +--- a/src/components/bottomSheetHandle/BottomSheetHandleContainer.tsx ++++ b/src/components/bottomSheetHandle/BottomSheetHandleContainer.tsx +@@ -41,7 +41,7 @@ function BottomSheetHandleContainerComponent({ + + //#region variables + const simultaneousHandlers = useMemo(() => { +- const refs = []; ++ const refs: any[] = []; + + if (_internalSimultaneousHandlers) { + refs.push(_internalSimultaneousHandlers); diff --git a/.yarn/patches/react-native-mmkv-npm-2.12.2-9efa7abf70.patch b/.yarn/patches/react-native-mmkv-npm-2.12.2-9efa7abf70.patch deleted file mode 100644 index 9bd3f7a7ef..0000000000 --- a/.yarn/patches/react-native-mmkv-npm-2.12.2-9efa7abf70.patch +++ /dev/null @@ -1,288 +0,0 @@ -diff --git a/android/src/main/cpp/MmkvHostObject.cpp b/android/src/main/cpp/MmkvHostObject.cpp -index 1ffbdc2d960f800cae56de82ae4cff2d6586a477..9ccc10fc28f5a4a0aebd9ded4c266592d000f781 100644 ---- a/android/src/main/cpp/MmkvHostObject.cpp -+++ b/android/src/main/cpp/MmkvHostObject.cpp -@@ -52,6 +52,7 @@ std::vector MmkvHostObject::getPropertyNames(jsi::Runtime& rt) - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("getAllKeys"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("deleteAll"))); - result.push_back(jsi::PropNameID::forUtf8(rt, std::string("recrypt"))); -+ result.push_back(jsi::PropNameID::forUtf8(rt, std::string("trim"))); - return result; - } - -@@ -86,9 +87,9 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro - } else if (arguments[1].isObject()) { - // object - auto object = arguments[1].asObject(runtime); -- if (isTypedArray(runtime, object)) { -+ if (rnmmkv::isTypedArray(runtime, object)) { - // Uint8Array -- auto typedArray = getTypedArray(runtime, object); -+ auto typedArray = rnmmkv::getTypedArray(runtime, object); - auto bufferValue = typedArray.getBuffer(runtime); - mmkv::MMBuffer buffer(bufferValue.data(runtime), bufferValue.size(runtime), - mmkv::MMBufferCopyFlag::MMBufferNoCopy); -@@ -191,7 +192,7 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro - bool hasValue = instance->getBytes(keyName, buffer); - if (hasValue) { - auto length = buffer.length(); -- TypedArray array(runtime, length); -+ rnmmkv::TypedArray array(runtime, length); - auto data = static_cast(buffer.getPtr()); - std::vector vector(length); - vector.assign(data, data + length); -@@ -286,5 +287,18 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro - }); - } - -+ if (propName == "trim") { -+ // MMKV.trim() -+ return jsi::Function::createFromHostFunction( -+ runtime, jsi::PropNameID::forAscii(runtime, propName), 0, -+ [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, -+ size_t count) -> jsi::Value { -+ instance->clearMemoryCache(); -+ instance->trim(); -+ -+ return jsi::Value::undefined(); -+ }); -+ } -+ - return jsi::Value::undefined(); - } -diff --git a/android/src/main/cpp/cpp-adapter.cpp b/android/src/main/cpp/cpp-adapter.cpp -index 976a2789bd3d1437d40ceec84a580afd1f52a97d..d4a728b0bbc8f0fd3f8878409b100d23aad1afbf 100644 ---- a/android/src/main/cpp/cpp-adapter.cpp -+++ b/android/src/main/cpp/cpp-adapter.cpp -@@ -37,7 +37,7 @@ void install(jsi::Runtime& jsiRuntime) { - - // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets - // destroyed and the cache gets invalidated. -- auto propNameIdCache = std::make_shared(jsiRuntime); -+ auto propNameIdCache = std::make_shared(jsiRuntime); - jsiRuntime.global().setProperty(jsiRuntime, "mmkvArrayBufferPropNameIdCache", - jsi::Object::createFromHostObject(jsiRuntime, propNameIdCache)); - } -diff --git a/cpp/TypedArray.cpp b/cpp/TypedArray.cpp -index 5ad11ee6909221b599ac42a4054588ea68126a1a..def1a450d94c8a90212c6b1e4b56d28ce941685b 100644 ---- a/cpp/TypedArray.cpp -+++ b/cpp/TypedArray.cpp -@@ -15,6 +15,8 @@ - #include - #include - -+namespace rnmmkv { -+ - template using ContentType = typename typedArrayTypeMap::type; - - enum class Prop { -@@ -320,3 +322,5 @@ template class TypedArray; - template class TypedArray; - template class TypedArray; - template class TypedArray; -+ -+} -\ No newline at end of file -diff --git a/cpp/TypedArray.h b/cpp/TypedArray.h -index c58140bc012f5ccef3ab9acc128d0ab0eed90635..02db7c168d54143750273194da5213137f412836 100644 ---- a/cpp/TypedArray.h -+++ b/cpp/TypedArray.h -@@ -14,6 +14,8 @@ - - namespace jsi = facebook::jsi; - -+namespace rnmmkv { -+ - enum class TypedArrayKind { - Int8Array, - Int16Array, -@@ -110,7 +112,7 @@ TypedArrayBase getTypedArray(jsi::Runtime& runtime, const jsi::Object& jsObj); - - std::vector arrayBufferToVector(jsi::Runtime& runtime, jsi::Object& jsObj); - void arrayBufferUpdate(jsi::Runtime& runtime, jsi::ArrayBuffer& buffer, std::vector data, -- size_t offset); -+ size_t offset); - - template class TypedArray : public TypedArrayBase { - public: -@@ -151,3 +153,5 @@ template TypedArray TypedArrayBase::as(jsi::Runtime& runti - } - return std::move(*this).get(runtime); - } -+ -+} -diff --git a/ios/MmkvHostObject.mm b/ios/MmkvHostObject.mm -index 16045fd7d4b020e9fcb10d0550d5668501b385fb..fb80fb9790f40669b6f4ee0bc48ba8798d0317e8 100644 ---- a/ios/MmkvHostObject.mm -+++ b/ios/MmkvHostObject.mm -@@ -97,9 +97,9 @@ - } else if (arguments[1].isObject()) { - // object - auto object = arguments[1].asObject(runtime); -- if (isTypedArray(runtime, object)) { -+ if (rnmmkv::isTypedArray(runtime, object)) { - // Uint8Array -- auto typedArray = getTypedArray(runtime, object); -+ auto typedArray = rnmmkv::getTypedArray(runtime, object); - auto bufferValue = typedArray.getBuffer(runtime); - auto data = [[NSData alloc] initWithBytes:bufferValue.data(runtime) - length:bufferValue.length(runtime)]; -@@ -198,7 +198,7 @@ - auto keyName = convertJSIStringToNSString(runtime, arguments[0].getString(runtime)); - auto data = [instance getDataForKey:keyName]; - if (data != nil) { -- TypedArray array(runtime, data.length); -+ rnmmkv::TypedArray array(runtime, data.length); - auto charArray = static_cast([data bytes]); - std::vector vector(data.length); - vector.assign(charArray, charArray + data.length); -@@ -291,5 +291,17 @@ - }); - } - -+ if (propName == "trim") { -+ // MMKV.trim() -+ return jsi::Function::createFromHostFunction( -+ runtime, jsi::PropNameID::forAscii(runtime, funcName), 0, -+ [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, -+ size_t count) -> jsi::Value { -+ [instance clearMemoryCache]; -+ [instance trim]; -+ return jsi::Value::undefined(); -+ }); -+ } -+ - return jsi::Value::undefined(); - } -diff --git a/ios/MmkvModule.mm b/ios/MmkvModule.mm -index 85f93830ebaebe7887f77fccc01bccc682413f25..b2974ac1b7df1ae2258b1fa2fcdea0333a3e0c95 100644 ---- a/ios/MmkvModule.mm -+++ b/ios/MmkvModule.mm -@@ -90,7 +90,7 @@ + (NSString*)getPropertyAsStringOrNilFromObject:(jsi::Object&)object - - // Adds the PropNameIDCache object to the Runtime. If the Runtime gets destroyed, the Object gets - // destroyed and the cache gets invalidated. -- auto propNameIdCache = std::make_shared(runtime); -+ auto propNameIdCache = std::make_shared(runtime); - runtime.global().setProperty(runtime, "mmkvArrayBufferPropNameIdCache", - jsi::Object::createFromHostObject(runtime, propNameIdCache)); - -diff --git a/lib/module/MMKV.js b/lib/module/MMKV.js -index c7b6cddc2287ea71841eac6fced4a0f02bc527e4..e6f28cedc4476859347b9b4df9c98ac72a026edf 100644 ---- a/lib/module/MMKV.js -+++ b/lib/module/MMKV.js -@@ -83,6 +83,10 @@ export class MMKV { - const func = this.getFunctionFromCache('recrypt'); - return func(key); - } -+ trim() { -+ const func = this.getFunctionFromCache('trim'); -+ return func(); -+ } - toString() { - return `MMKV (${this.id}): [${this.getAllKeys().join(', ')}]`; - } -diff --git a/lib/typescript/MMKV.d.ts b/lib/typescript/MMKV.d.ts -index 98de6b8fefec0ffcc46de4544d8c3cfb002d342c..f2d0b4f2c9f1db500a431fe64472847dcd68ea83 100644 ---- a/lib/typescript/MMKV.d.ts -+++ b/lib/typescript/MMKV.d.ts -@@ -100,6 +100,16 @@ interface MMKVInterface { - * Encryption keys can have a maximum length of 16 bytes. - */ - recrypt: (key: string | undefined) => void; -+ /** -+ * Trims the storage space and clears memory cache. -+ * -+ * Since MMKV does not resize itself after deleting keys, you can call `trim()` -+ * after deleting a bunch of keys to manually trim the memory- and -+ * disk-file to reduce storage and memory usage. -+ * -+ * In most applications, this is not needed at all. -+ */ -+ trim: () => void; - /** - * Adds a value changed listener. The Listener will be called whenever any value - * in this storage instance changes (set or delete). -@@ -108,7 +118,7 @@ interface MMKVInterface { - */ - addOnValueChangedListener: (onValueChanged: (key: string) => void) => Listener; - } --export type NativeMMKV = Pick; -+export type NativeMMKV = Pick; - /** - * A single MMKV instance. - */ -@@ -134,6 +144,7 @@ export declare class MMKV implements MMKVInterface { - getAllKeys(): string[]; - clearAll(): void; - recrypt(key: string | undefined): void; -+ trim(): void; - toString(): string; - toJSON(): object; - addOnValueChangedListener(onValueChanged: (key: string) => void): Listener; -diff --git a/react-native-mmkv.podspec b/react-native-mmkv.podspec -index 599f39e20baad5a1db037a80560f5105a0ad7d20..34c5f847d787e44f53f7ed7da632a3ed39edf061 100644 ---- a/react-native-mmkv.podspec -+++ b/react-native-mmkv.podspec -@@ -27,7 +27,7 @@ Pod::Spec.new do |s| - 'ios/**/*.h' - ] - -- s.dependency "MMKV", ">= 1.3.3" -+ s.dependency "MMKV", "= 1.3.5" - if respond_to?(:install_modules_dependencies, true) - install_modules_dependencies(s) - else -diff --git a/src/MMKV.ts b/src/MMKV.ts -index 973a5e74244c28ab22c47b2bffba078e20b84fe1..5b32d703ff898c2ad732f011c54d259e1027fde0 100644 ---- a/src/MMKV.ts -+++ b/src/MMKV.ts -@@ -106,6 +106,16 @@ interface MMKVInterface { - * Encryption keys can have a maximum length of 16 bytes. - */ - recrypt: (key: string | undefined) => void; -+ /** -+ * Trims the storage space and clears memory cache. -+ * -+ * Since MMKV does not resize itself after deleting keys, you can call `trim()` -+ * after deleting a bunch of keys to manually trim the memory- and -+ * disk-file to reduce storage and memory usage. -+ * -+ * In most applications, this is not needed at all. -+ */ -+ trim: () => void; - /** - * Adds a value changed listener. The Listener will be called whenever any value - * in this storage instance changes (set or delete). -@@ -129,6 +139,7 @@ export type NativeMMKV = Pick< - | 'getBuffer' - | 'set' - | 'recrypt' -+ | 'trim' - >; - - const onValueChangedListeners = new Map void)[]>(); -@@ -227,6 +238,10 @@ export class MMKV implements MMKVInterface { - const func = this.getFunctionFromCache('recrypt'); - return func(key); - } -+ trim() { -+ const func = this.getFunctionFromCache('trim'); -+ return func(); -+ } - - toString(): string { - return `MMKV (${this.id}): [${this.getAllKeys().join(', ')}]`; -diff --git a/src/createMMKV.mock.ts b/src/createMMKV.mock.ts -index c81bb57129a2934e4647a5f3dfc06a4bb15be198..29ebc9168ef7a58dc11abeb4f3992e2b5c66d6f9 100644 ---- a/src/createMMKV.mock.ts -+++ b/src/createMMKV.mock.ts -@@ -29,5 +29,8 @@ export const createMockMMKV = (): NativeMMKV => { - recrypt: () => { - console.warn('Encryption is not supported in mocked MMKV instances!'); - }, -+ trim: () => { -+ console.warn('trim() is not supported in mocked MMKV instances!'); -+ } - }; - }; diff --git a/.yarn/patches/react-native-reanimated-npm-3.17.1-c34570df61.patch b/.yarn/patches/react-native-reanimated-npm-3.17.1-c34570df61.patch new file mode 100644 index 0000000000..a1d9bbbf6b --- /dev/null +++ b/.yarn/patches/react-native-reanimated-npm-3.17.1-c34570df61.patch @@ -0,0 +1,13 @@ +diff --git a/src/platform-specific/findHostInstance.ts b/src/platform-specific/findHostInstance.ts +index da56c8eb67f4be89ac42ad22bc38f27500247f82..32f5baa54420800a31ce64441eb1acedaf68c43c 100644 +--- a/src/platform-specific/findHostInstance.ts ++++ b/src/platform-specific/findHostInstance.ts +@@ -86,7 +86,7 @@ export function findHostInstance( + a valid React ref. + */ + return findHostInstance_DEPRECATED( +- !isFabric() || (component as IAnimatedComponentInternal).hasAnimatedRef() ++ !isFabric() || (typeof (component as IAnimatedComponentInternal).hasAnimatedRef === 'function' && (component as IAnimatedComponentInternal).hasAnimatedRef()) + ? (component as IAnimatedComponentInternal)._componentRef + : component + ); diff --git a/.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch b/.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch index c648ca04e3..deecbab4fa 100644 --- a/.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch +++ b/.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch @@ -277,7 +277,7 @@ index 6664b6f6eacb37743d049556dc55f613c0244517..7d639e3c139cb506fc8ef23044e3e121 public void onHostResume() { // do nothing diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java -index d59e19ce82a5a03a60c558b35171af713719af4a..95d4b70232583266d81abf9262a3c8fbc3c01c46 100644 +index d59e19ce82a5a03a60c558b35171af713719af4a..1179dc4d407a6faac186ee60cc7b7c55bb61f261 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java @@ -1,7 +1,9 @@ @@ -442,14 +442,14 @@ index 4600a8dc5c448a2236d25e40172453f93ae92c45..4550481079f5b59e9a11029082958bf6 } \ No newline at end of file diff --git a/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java -index 5bae4aa9e66897473a9083a2c9320c99d72e80d7..456547621a60911296e878fe45d9aa55ae6ebf80 100644 +index 5bae4aa9e66897473a9083a2c9320c99d72e80d7..658f23b62bffb5fec8ed8bd15b4dc0ce430d95aa 100644 --- a/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -331,6 +331,12 @@ public class RNCWebViewManager extends ViewGroupManager mRNCWebViewManagerImpl.setWebviewDebuggingEnabled(view, value); } -+ @Override ++ // @Override + @ReactProp(name = "disableJsPromptLike") + public void setDisableJsPromptLike(RNCWebViewWrapper view, boolean value) { + mRNCWebViewManagerImpl.setDisableJsPromptLike(view, value); diff --git a/apps/mobile/.eslintrc.js b/apps/mobile/.eslintrc.js index 70aec17b5e..bf9ad4e2fb 100644 --- a/apps/mobile/.eslintrc.js +++ b/apps/mobile/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { root: true, // extends: '@react-native', - extends: '@react-native-community', + extends: ['@react-native-community'], rules: { 'react/react-in-jsx-scope': 'off', 'react-hooks/exhaustive-deps': 'error', diff --git a/apps/mobile/android/app/build.gradle b/apps/mobile/android/app/build.gradle index 6842d7211b..b0c7398ae4 100644 --- a/apps/mobile/android/app/build.gradle +++ b/apps/mobile/android/app/build.gradle @@ -61,7 +61,8 @@ react { def enableProguardInReleaseBuilds = true def isNewArchitectureEnabled() { - return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" + // get from rootProject, or from env + return (rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true") || (System.getenv("RABBY_MOBILE_NEW_ARCH_ENABLED") == "true"); } /** @@ -97,6 +98,7 @@ android { versionCode 100142 versionName "0.6.40" missingDimensionStrategy "store", "play" + buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()) } splits { abi { @@ -171,11 +173,15 @@ android { if (isNewArchitectureEnabled()) { java.srcDirs += [ "src/newarch", + "src/newarch/com/debank/rabbymobile", // This is needed to build Kotlin project with NewArch enabled "${project.buildDir}/generated/source/codegen/java" ] } else { - java.srcDirs += ["src/oldarch"] + java.srcDirs += [ + "src/oldarch", + "src/oldarch/com/debank/rabbymobile" + ] } } } diff --git a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainActivity.java b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainActivity.java index 28c202d57a..4fb7972c0c 100644 --- a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainActivity.java +++ b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainActivity.java @@ -46,6 +46,7 @@ protected Bundle getLaunchOptions() { } else { initialProperties.putString("rabbitCode", "RABBY_MOBILE_CODE_DEV"); } + initialProperties.putBoolean("turboModuleEnabled", BuildConfig.IS_NEW_ARCHITECTURE_ENABLED); return initialProperties; } }; diff --git a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainApplication.kt b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainApplication.kt index fb64c54cca..4fcb5ba4c4 100644 --- a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainApplication.kt +++ b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/MainApplication.kt @@ -13,6 +13,7 @@ import com.facebook.react.soloader.OpenSourceMergedSoMapping import com.facebook.soloader.SoLoader import com.facebook.react.modules.network.OkHttpClientProvider; +import com.google.firebase.FirebaseApp class MainApplication : Application(), ReactApplication { @@ -46,6 +47,7 @@ class MainApplication : Application(), ReactApplication { if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { // If you opted-in for the New Architecture, we load the native entry point for this app. load() + // FirebaseApp.initializeApp(this); } } } diff --git a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNHelpersImpl.java b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNHelpersImpl.java new file mode 100644 index 0000000000..93ef9d4899 --- /dev/null +++ b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNHelpersImpl.java @@ -0,0 +1,11 @@ +package com.debank.rabbymobile; + +import android.os.Process; + +public class RNHelpersImpl { + public static final String NAME = "RNHelpers"; + + public static void forceExitApp() { + Process.killProcess(Process.myPid()); + } +} diff --git a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNScreenshotPreventImpl.java b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNScreenshotPreventImpl.java new file mode 100644 index 0000000000..9a0f702a35 --- /dev/null +++ b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNScreenshotPreventImpl.java @@ -0,0 +1,105 @@ +package com.debank.rabbymobile; + +import android.app.Activity; +import android.view.WindowManager; +import android.view.ViewGroup; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.widget.RelativeLayout; +import android.widget.ImageView; +import android.graphics.Color; + +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactContext; +import com.debank.rabbymobile.RabbyUtils; + +import java.io.IOException; +import java.net.URL; + +public class RNScreenshotPreventImpl { + public static final String NAME = "RNScreenshotPrevent"; + + private static RelativeLayout overlayLayout; + + private static ViewGroup activityGetRootView(Activity activity) { + ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView().getRootView(); + return rootView; + } + + private static boolean activityIsSecure(Activity activity) { + int flags = activity.getWindow().getAttributes().flags; + return (flags & WindowManager.LayoutParams.FLAG_SECURE) != 0; + } + + private static void activitySetSecure(Activity activity) { + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); + } + + private static void activityCancelSecure(Activity activity) { + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + + public static void togglePreventScreenshot(Activity activity, boolean isPrevent, ReactContext reactContext) { + WritableMap params = Arguments.createMap(); + params.putBoolean("isPrevent", isPrevent); + params.putBoolean("success", false); + + if (activity != null) { + if (isPrevent) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activitySetSecure(activity); + } + }); + } else { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activityCancelSecure(activity); + } + }); + } + params.putBoolean("success", true); + } + + RabbyUtils.rnCtxSendEvent(reactContext, "preventScreenshotChanged", params); + } + + private static void createOverlay(Activity activity, String imagePath) { + overlayLayout = new RelativeLayout(activity); + overlayLayout.setBackgroundColor(Color.parseColor("#7084FF")); + + // Create an ImageView + ImageView imageView = new ImageView(activity); + RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.MATCH_PARENT, + RelativeLayout.LayoutParams.WRAP_CONTENT); + imageParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); + + imageView.setLayoutParams(imageParams); + + // Set image resource + Bitmap bitmap = decodeImageUrl(imagePath); + + if (bitmap != null) { + int imageHeight = (int)(bitmap.getHeight() * ((float) activity.getResources().getDisplayMetrics().widthPixels / bitmap.getWidth())); + Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, activity.getResources().getDisplayMetrics().widthPixels, imageHeight, true); + imageView.setImageBitmap(scaledBitmap); + } + + overlayLayout.addView(imageView); + } + + private static Bitmap decodeImageUrl(String imagePath) { + try { + URL imageUrl = new URL(imagePath); + Bitmap bitmap = BitmapFactory.decodeStream(imageUrl.openConnection().getInputStream()); + return bitmap; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNTimeChangedImpl.java b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNTimeChangedImpl.java new file mode 100644 index 0000000000..b0a320793c --- /dev/null +++ b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/RNTimeChangedImpl.java @@ -0,0 +1,46 @@ +package com.debank.rabbymobile; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Build; + +import com.facebook.react.ReactApplication; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactContext; +import com.debank.rabbymobile.RabbyUtils; + +public class RNTimeChangedImpl { + public static final String NAME = "RNTimeChanged"; + + public static class TimeChangeBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + WritableMap params = Arguments.createMap(); + String action = intent.getAction(); + params.putString("androidAction", action); + + ReactApplication rnApp = (ReactApplication) context.getApplicationContext(); + ReactContext reactContext = rnApp.getReactNativeHost().getReactInstanceManager() + .getCurrentReactContext(); + + if (Intent.ACTION_TIME_CHANGED.equals(action)) { + params.putString("reason", "timeSet"); + RabbyUtils.rnCtxSendEvent(reactContext, "onTimeChanged", params); + } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { + params.putString("reason", "timeZoneChanged"); + RabbyUtils.rnCtxSendEvent(reactContext, "onTimeChanged", params); + }/* else { + params.putString("reason", "unknown"); + RabbyUtils.rnCtxSendEvent(reactContext, "onTimeChanged", params); + } */ + } + } + + public static void exitAppForSecurity() { + android.os.Process.killProcess(android.os.Process.myPid()); + } +} \ No newline at end of file diff --git a/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/ReactNativeSecurityImpl.java b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/ReactNativeSecurityImpl.java new file mode 100644 index 0000000000..4c93834057 --- /dev/null +++ b/apps/mobile/android/app/src/main/java/com/debank/rabbymobile/ReactNativeSecurityImpl.java @@ -0,0 +1,30 @@ +package com.debank.rabbymobile; + +import android.app.Activity; +import android.view.WindowManager; + +public class ReactNativeSecurityImpl { + public static final String NAME = "ReactNativeSecurity"; + + public static void blockScreen(Activity activity) { + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); + } + }); + } + } + + public static void unblockScreen(Activity activity) { + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + }); + } + } +} \ No newline at end of file diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/EventEmitterPackage.java.bak b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/EventEmitterPackage.java.bak new file mode 100644 index 0000000000..d05c085bb7 --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/EventEmitterPackage.java.bak @@ -0,0 +1,43 @@ +package com.debank.rabbymobile; + +abstract class EventEmitterPackage { + // private static final List mListeners = new CopyOnWriteArrayList<>(); + + private int listenerCount = 0; + /** + * @notice addListener/removeListeners is required for RN built in Event Emitter Calls. + * You may subscribe it in javascript like: + * + * ```js + * const eventEmitter = new NativeEventEmitter(nativeModule); + * eventEmitter.addListener(...) + * ``` + * + * call `new NativeEventEmitter` requires explicit exported method `addListener` and `removeListeners` + * implementation on Package for current RN version, it was not required for previous RN versions. + * + * But you don't need real implementation for these methods, you can just keep them empty. + */ + /** + * @see https://stackoverflow.com/a/69649068 + * @why Keep: Required for RN built in Event Emitter Calls. + */ + @ReactMethod + public void addListener(String eventName) { + if (listenerCount == 0) {} + + listenerCount += 1; + } + + /** + * @see https://stackoverflow.com/a/69649068 + * @why Keep: Required for RN built in Event Emitter Calls. + */ + @ReactMethod + public void removeListeners(Integer count) { + listenerCount -= count; + if (listenerCount == 0) { + // Remove upstream listeners, stop unnecessary background tasks + } + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNHelpersModule.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNHelpersModule.java new file mode 100644 index 0000000000..fe0c5f28db --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNHelpersModule.java @@ -0,0 +1,50 @@ +package com.debank.rabbymobile; + +import android.os.Build; +import android.app.Activity; +import androidx.annotation.NonNull; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import com.facebook.react.ReactApplication; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.module.annotations.ReactModule; +import android.view.WindowManager; + +import com.debank.rabbymobile.NativeRNHelpersSpec; + +@ReactModule(name = RNHelpersImpl.NAME) +public class RNHelpersModule extends NativeRNHelpersSpec /* implements LifecycleEventListener */ { + private final ReactApplicationContext reactContext; + + public RNHelpersModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + + // reactContext.addLifecycleEventListener(this); + } + + @Override + @NonNull + public String getName() { + return RNHelpersImpl.NAME; + } + + @ReactMethod + public void forceExitApp() { + RNHelpersImpl.forceExitApp(); + } + + @ReactMethod + public void iosExcludeFileFromBackup(String filePath, Promise promise) { + promise.resolve(null); + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNHelpersPackage.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNHelpersPackage.java new file mode 100644 index 0000000000..6e4ef76b25 --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNHelpersPackage.java @@ -0,0 +1,45 @@ +package com.debank.rabbymobile; + +import androidx.annotation.Nullable; + +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.TurboReactPackage; + +import java.util.HashMap; +import java.util.Map; + +public class RNHelpersPackage extends TurboReactPackage { + + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(RNHelpersImpl.NAME)) { + return new RNHelpersModule(reactContext); + } else { + return null; + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + moduleInfos.put( + RNHelpersImpl.NAME, + new ReactModuleInfo( + RNHelpersImpl.NAME, + RNHelpersImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + )); + return moduleInfos; + }; + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNScreenshotPreventModule.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNScreenshotPreventModule.java new file mode 100644 index 0000000000..ed4b10a5ec --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNScreenshotPreventModule.java @@ -0,0 +1,94 @@ +package com.debank.rabbymobile; + +import androidx.annotation.NonNull; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.RelativeLayout; +import android.widget.ImageView; + +import com.facebook.proguard.annotations.DoNotStrip; +import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.core.DeviceEventManagerModule; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.uimanager.events.EventDispatcherListener; + +import java.io.IOException; +import java.net.URL; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +@ReactModule(name = RNScreenshotPreventImpl.NAME) +public class RNScreenshotPreventModule extends NativeRNScreenshotPreventSpec { +// private static final String NAME = RNScreenshotPreventImpl.NAME; + private final ReactApplicationContext reactContext; + + public RNScreenshotPreventModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + + // reactContext.addLifecycleEventListener(this); + } + + @Override + @NonNull + public String getName() { + return RNScreenshotPreventImpl.NAME; + } + + @Override + public void addListener(String eventType) {}; + + @Override + public void removeListeners(double count) {}; + + @Override + public void togglePreventScreenshot(boolean isPrevent) { + if (this.reactContext.hasCurrentActivity()) { + final Activity activity = this.reactContext.getCurrentActivity(); + RNScreenshotPreventImpl.togglePreventScreenshot(activity, isPrevent, this.reactContext); + } + } + + @Override + public void iosProtectFromScreenRecording(final Promise promise) { + if (BuildConfig.DEBUG) { + promise.reject("Not implemented for Android"); + } else { + promise.resolve(null); + } + + this.togglePreventScreenshot(true); + } + + @Override + public void iosUnprotectFromScreenRecording(final Promise promise) { + if (BuildConfig.DEBUG) { + promise.reject("Not implemented for Android"); + } else { + promise.resolve(null); + } + + this.togglePreventScreenshot(false); + } + + @Override + public boolean iosIsBeingCaptured() { + if (BuildConfig.DEBUG) { + // promise.reject("Not implemented for Android"); + System.out.println("Not implemented for Android"); + } + return false; + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNScreenshotPreventPackage.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNScreenshotPreventPackage.java new file mode 100644 index 0000000000..21162dde6d --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNScreenshotPreventPackage.java @@ -0,0 +1,52 @@ +package com.debank.rabbymobile; + +import androidx.annotation.Nullable; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.TurboReactPackage; + +import java.util.HashMap; +import java.util.Map; +// import java.util.Collections; +// import java.util.Arrays; +// import java.util.ArrayList; +import java.util.List; + +import com.debank.rabbymobile.RNScreenshotPreventModule; + +public class RNScreenshotPreventPackage extends TurboReactPackage /* implements ReactPackage */ { + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(RNScreenshotPreventImpl.NAME)) { + return new RNScreenshotPreventModule(reactContext); + } else { + return null; + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + moduleInfos.put( + RNScreenshotPreventImpl.NAME, + new ReactModuleInfo( + RNScreenshotPreventImpl.NAME, + RNScreenshotPreventImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + )); + return moduleInfos; + }; + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNTimeChangedModule.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNTimeChangedModule.java new file mode 100644 index 0000000000..e201c1e48d --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNTimeChangedModule.java @@ -0,0 +1,73 @@ +package com.debank.rabbymobile; + +import android.os.Build; +import android.app.Activity; +import androidx.annotation.NonNull; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import com.facebook.react.ReactApplication; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.LifecycleEventListener; + +import com.facebook.react.module.annotations.ReactModule; + +import android.view.WindowManager; + +@ReactModule(name = RNTimeChangedImpl.NAME) +public class RNTimeChangedModule extends NativeRNTimeChangedSpec implements LifecycleEventListener { + private final ReactApplicationContext reactContext; + + public RNTimeChangedModule(ReactApplicationContext reactContext) { + super(reactContext); + this.reactContext = reactContext; + + reactContext.addLifecycleEventListener(this); + } + + @Override + @NonNull + public String getName() { + return RNTimeChangedImpl.NAME; + } + + @Override + public void addListener(String eventType) {}; + + @Override + public void removeListeners(double count) {}; + + + @ReactMethod + public void exitAppForSecurity() { + RNTimeChangedImpl.exitAppForSecurity(); + } + + @Override + public void onHostResume() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + + RNTimeChangedImpl.TimeChangeBroadcastReceiver tcreceiver = new RNTimeChangedImpl.TimeChangeBroadcastReceiver(); + reactContext.registerReceiver(tcreceiver , filter); + + if (Build.VERSION.SDK_INT >= 34) { + reactContext.registerReceiver(tcreceiver, filter, Context.RECEIVER_EXPORTED); + } else { + reactContext.registerReceiver(tcreceiver, filter); + } + } + @Override + public void onHostPause() {} + @Override + public void onHostDestroy() { +// reactContext.unregisterReceiver(midnightBroadcastReceiver); + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNTimeChangedPackage.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNTimeChangedPackage.java new file mode 100644 index 0000000000..a9bbf21c99 --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/RNTimeChangedPackage.java @@ -0,0 +1,45 @@ +package com.debank.rabbymobile; + +import androidx.annotation.Nullable; + +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.TurboReactPackage; + +import java.util.HashMap; +import java.util.Map; + +public class RNTimeChangedPackage extends TurboReactPackage { + + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(RNTimeChangedImpl.NAME)) { + return new RNTimeChangedModule(reactContext); + } else { + return null; + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + moduleInfos.put( + RNTimeChangedImpl.NAME, + new ReactModuleInfo( + RNTimeChangedImpl.NAME, + RNTimeChangedImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + )); + return moduleInfos; + }; + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/ReactNativeSecurityModule.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/ReactNativeSecurityModule.java new file mode 100644 index 0000000000..36fbdd2e18 --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/ReactNativeSecurityModule.java @@ -0,0 +1,44 @@ +package com.debank.rabbymobile; + +import android.app.Activity; +import androidx.annotation.NonNull; + +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; +import android.view.WindowManager; + + +@ReactModule(name = ReactNativeSecurityImpl.NAME) +public class ReactNativeSecurityModule extends NativeReactNativeSecuritySpec { + ReactNativeSecurityModule(ReactApplicationContext context) { + super(context); + } + + @Override + @NonNull + public String getName() { + return ReactNativeSecurityImpl.NAME; + } + + @Override + // @ReactMethod + public void blockScreen() { + final Activity activity = getCurrentActivity(); + + if (activity != null) { + ReactNativeSecurityImpl.blockScreen(activity); + } + } + + @Override + // @ReactMethod + public void unblockScreen() { + final Activity activity = getCurrentActivity(); + + if (activity != null) { + ReactNativeSecurityImpl.unblockScreen(activity); + } + } +} diff --git a/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/ReactNativeSecurityPackage.java b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/ReactNativeSecurityPackage.java new file mode 100644 index 0000000000..cf3381b4e7 --- /dev/null +++ b/apps/mobile/android/app/src/newarch/com/debank/rabbymobile/ReactNativeSecurityPackage.java @@ -0,0 +1,45 @@ +package com.debank.rabbymobile; + +import androidx.annotation.Nullable; + +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.module.model.ReactModuleInfo; +import com.facebook.react.module.model.ReactModuleInfoProvider; +import com.facebook.react.TurboReactPackage; + +import java.util.HashMap; +import java.util.Map; + +public class ReactNativeSecurityPackage extends TurboReactPackage { + + @Nullable + @Override + public NativeModule getModule(String name, ReactApplicationContext reactContext) { + if (name.equals(ReactNativeSecurityImpl.NAME)) { + return new ReactNativeSecurityModule(reactContext); + } else { + return null; + } + } + + @Override + public ReactModuleInfoProvider getReactModuleInfoProvider() { + return () -> { + final Map moduleInfos = new HashMap<>(); + boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; + moduleInfos.put( + ReactNativeSecurityImpl.NAME, + new ReactModuleInfo( + ReactNativeSecurityImpl.NAME, + ReactNativeSecurityImpl.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + false, // hasConstants + false, // isCxxModule + isTurboModule // isTurboModule + )); + return moduleInfos; + }; + } +} diff --git a/apps/mobile/android/app/src/oldarch/EventEmitterPackageSpec.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/EventEmitterPackageSpec.java similarity index 100% rename from apps/mobile/android/app/src/oldarch/EventEmitterPackageSpec.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/EventEmitterPackageSpec.java diff --git a/apps/mobile/android/app/src/oldarch/RNHelpersModule.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNHelpersModule.java similarity index 87% rename from apps/mobile/android/app/src/oldarch/RNHelpersModule.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNHelpersModule.java index 292f95a856..fa53f0b2b1 100644 --- a/apps/mobile/android/app/src/oldarch/RNHelpersModule.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNHelpersModule.java @@ -15,10 +15,11 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.module.annotations.ReactModule; import android.view.WindowManager; +@ReactModule(name = RNHelpersImpl.NAME) public class RNHelpersModule extends EventEmitterPackageSpec /* implements LifecycleEventListener */ { - public static final String NAME = "RNHelpers"; private final ReactApplicationContext reactContext; public RNHelpersModule(ReactApplicationContext reactContext) { @@ -31,11 +32,11 @@ public RNHelpersModule(ReactApplicationContext reactContext) { @Override @NonNull public String getName() { - return NAME; + return RNHelpersImpl.NAME; } @ReactMethod public void forceExitApp() { - android.os.Process.killProcess(android.os.Process.myPid()); + RNHelpersImpl.forceExitApp(); } } diff --git a/apps/mobile/android/app/src/oldarch/RNHelpersPackage.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNHelpersPackage.java similarity index 88% rename from apps/mobile/android/app/src/oldarch/RNHelpersPackage.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNHelpersPackage.java index e00b5b5222..8892ce0c9a 100644 --- a/apps/mobile/android/app/src/oldarch/RNHelpersPackage.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNHelpersPackage.java @@ -16,7 +16,7 @@ public class RNHelpersPackage extends TurboReactPackage { @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { - if (name.equals(RNHelpersModule.NAME)) { + if (name.equals(RNHelpersImpl.NAME)) { return new RNHelpersModule(reactContext); } else { return null; @@ -29,10 +29,10 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { final Map moduleInfos = new HashMap<>(); boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; moduleInfos.put( - RNHelpersModule.NAME, + RNHelpersImpl.NAME, new ReactModuleInfo( - RNHelpersModule.NAME, - RNHelpersModule.NAME, + RNHelpersImpl.NAME, + RNHelpersImpl.NAME, false, // canOverrideExistingModule false, // needsEagerInit true, // hasConstants diff --git a/apps/mobile/android/app/src/oldarch/RNScreenshotPreventModule.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNScreenshotPreventModule.java similarity index 56% rename from apps/mobile/android/app/src/oldarch/RNScreenshotPreventModule.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNScreenshotPreventModule.java index 7d61782458..5bfa8179b2 100644 --- a/apps/mobile/android/app/src/oldarch/RNScreenshotPreventModule.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNScreenshotPreventModule.java @@ -19,6 +19,7 @@ import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.Arguments; +import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.uimanager.events.EventDispatcherListener; import java.io.IOException; @@ -27,8 +28,8 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -public class RNScreenshotPreventModule extends EventEmitterPackageSpec /* implements LifecycleEventListener */ { - public static final String NAME = "RNScreenshotPrevent"; +@ReactModule(name = RNScreenshotPreventImpl.NAME) +public class RNScreenshotPreventModule extends EventEmitterPackageSpec { private final ReactApplicationContext reactContext; private RelativeLayout overlayLayout; @@ -42,56 +43,15 @@ public RNScreenshotPreventModule(ReactApplicationContext reactContext) { @Override @NonNull public String getName() { - return NAME; - } - - private static ViewGroup activityGetRootView(Activity activity) { - ViewGroup rootView = (ViewGroup) activity.getWindow().getDecorView().getRootView(); - return rootView; - } - - private static boolean activityIsSecure(Activity activity) { - int flags = activity.getWindow().getAttributes().flags; - return (flags & WindowManager.LayoutParams.FLAG_SECURE) != 0; - } - - private static void activitySetSecure(Activity activity) { - activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); - } - - private static void activityCancelSecure(Activity activity) { - activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + return RNScreenshotPreventImpl.NAME; } @ReactMethod public void togglePreventScreenshot(boolean isPrevent) { - WritableMap params = Arguments.createMap(); - params.putBoolean("isPrevent", isPrevent); - params.putBoolean("success", false); - if (this.reactContext.hasCurrentActivity()) { final Activity activity = this.reactContext.getCurrentActivity(); - if (activity != null) { - if (isPrevent) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activitySetSecure(activity); - } - }); - } else { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activityCancelSecure(activity); - } - }); - } - params.putBoolean("success", true); - } + RNScreenshotPreventImpl.togglePreventScreenshot(activity, isPrevent, this.reactContext); } - - RabbyUtils.rnCtxSendEvent(reactContext, "preventScreenshotChanged", params); } @ReactMethod @@ -125,31 +85,6 @@ public boolean iosIsBeingCaptured() { return false; } - private void createOverlay(Activity activity, String imagePath) { - overlayLayout = new RelativeLayout(activity); - overlayLayout.setBackgroundColor(Color.parseColor("#7084FF")); - - // Create an ImageView - ImageView imageView = new ImageView(activity); - RelativeLayout.LayoutParams imageParams = new RelativeLayout.LayoutParams( - RelativeLayout.LayoutParams.MATCH_PARENT, - RelativeLayout.LayoutParams.WRAP_CONTENT); - imageParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); - - imageView.setLayoutParams(imageParams); - - // Set image resource - Bitmap bitmap = decodeImageUrl(imagePath); - - if (bitmap != null) { - int imageHeight = (int)(bitmap.getHeight() * ((float) activity.getResources().getDisplayMetrics().widthPixels / bitmap.getWidth())); - Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, activity.getResources().getDisplayMetrics().widthPixels, imageHeight, true); - imageView.setImageBitmap(scaledBitmap); - } - - overlayLayout.addView(imageView); - } - // @Override // public void onHostResume() { // // Activity currentActivity = this.reactContext.getCurrentActivity(); @@ -161,7 +96,7 @@ private void createOverlay(Activity activity, String imagePath) { // // @Override // // public void run() { // // if (overlayLayout != null) { - // // activityGetRootView(currentActivity).removeView(overlayLayout); + // // RNScreenshotPreventImpl.activityGetRootView(currentActivity).removeView(overlayLayout); // // overlayLayout = null; // // } // // } @@ -180,7 +115,7 @@ private void createOverlay(Activity activity, String imagePath) { // // currentActivity.runOnUiThread(new Runnable() { // // @Override // // public void run() { - // // ViewGroup rootView = activityGetRootView(currentActivity); + // // ViewGroup rootView = RNScreenshotPreventImpl.activityGetRootView(currentActivity); // // createOverlay(currentActivity, ""); // // RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( @@ -196,15 +131,4 @@ private void createOverlay(Activity activity, String imagePath) { // public void onHostDestroy() { // // Cleanup if needed // } - - private Bitmap decodeImageUrl(String imagePath) { - try { - URL imageUrl = new URL(imagePath); - Bitmap bitmap = BitmapFactory.decodeStream(imageUrl.openConnection().getInputStream()); - return bitmap; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } } diff --git a/apps/mobile/android/app/src/oldarch/RNScreenshotPreventPackage.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNScreenshotPreventPackage.java similarity index 90% rename from apps/mobile/android/app/src/oldarch/RNScreenshotPreventPackage.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNScreenshotPreventPackage.java index aaef4a36ae..a49206062a 100644 --- a/apps/mobile/android/app/src/oldarch/RNScreenshotPreventPackage.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNScreenshotPreventPackage.java @@ -35,7 +35,7 @@ public class RNScreenshotPreventPackage extends TurboReactPackage /* implements @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { - if (name.equals(RNScreenshotPreventModule.NAME)) { + if (name.equals(RNScreenshotPreventImpl.NAME)) { return new RNScreenshotPreventModule(reactContext); } else { return null; @@ -48,10 +48,10 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { final Map moduleInfos = new HashMap<>(); boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; moduleInfos.put( - RNScreenshotPreventModule.NAME, + RNScreenshotPreventImpl.NAME, new ReactModuleInfo( - RNScreenshotPreventModule.NAME, - RNScreenshotPreventModule.NAME, + RNScreenshotPreventImpl.NAME, + RNScreenshotPreventImpl.NAME, false, // canOverrideExistingModule false, // needsEagerInit true, // hasConstants diff --git a/apps/mobile/android/app/src/oldarch/RNTimeChangedModule.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNTimeChangedModule.java similarity index 57% rename from apps/mobile/android/app/src/oldarch/RNTimeChangedModule.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNTimeChangedModule.java index 2777ce5118..372b24f191 100644 --- a/apps/mobile/android/app/src/oldarch/RNTimeChangedModule.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNTimeChangedModule.java @@ -15,10 +15,11 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.LifecycleEventListener; +import com.facebook.react.module.annotations.ReactModule; import android.view.WindowManager; +@ReactModule(name = RNTimeChangedImpl.NAME) public class RNTimeChangedModule extends EventEmitterPackageSpec implements LifecycleEventListener { - public static final String NAME = "RNTimeChanged"; private final ReactApplicationContext reactContext; public RNTimeChangedModule(ReactApplicationContext reactContext) { @@ -31,36 +32,12 @@ public RNTimeChangedModule(ReactApplicationContext reactContext) { @Override @NonNull public String getName() { - return NAME; - } - - private class TimeChangeBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - WritableMap params = Arguments.createMap(); - String action = intent.getAction(); - params.putString("androidAction", action); - - ReactApplication rnApp = (ReactApplication) context.getApplicationContext(); - ReactContext reactContext = rnApp.getReactNativeHost().getReactInstanceManager() - .getCurrentReactContext(); - - if (Intent.ACTION_TIME_CHANGED.equals(action)) { - params.putString("reason", "timeSet"); - RabbyUtils.rnCtxSendEvent(reactContext, "onTimeChanged", params); - } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) { - params.putString("reason", "timeZoneChanged"); - RabbyUtils.rnCtxSendEvent(reactContext, "onTimeChanged", params); - }/* else { - params.putString("reason", "unknown"); - RabbyUtils.rnCtxSendEvent(reactContext, "onTimeChanged", params); - } */ - } + return RNTimeChangedImpl.NAME; } @ReactMethod public void exitAppForSecurity() { - android.os.Process.killProcess(android.os.Process.myPid()); + RNTimeChangedImpl.exitAppForSecurity(); } @Override @@ -69,7 +46,7 @@ public void onHostResume() { filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - TimeChangeBroadcastReceiver tcreceiver = new TimeChangeBroadcastReceiver(); + RNTimeChangedImpl.TimeChangeBroadcastReceiver tcreceiver = new RNTimeChangedImpl.TimeChangeBroadcastReceiver(); reactContext.registerReceiver(tcreceiver , filter); if (Build.VERSION.SDK_INT >= 34) { diff --git a/apps/mobile/android/app/src/oldarch/RNTimeChangedPackage.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNTimeChangedPackage.java similarity index 87% rename from apps/mobile/android/app/src/oldarch/RNTimeChangedPackage.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNTimeChangedPackage.java index 998ae23085..c82052db58 100644 --- a/apps/mobile/android/app/src/oldarch/RNTimeChangedPackage.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/RNTimeChangedPackage.java @@ -16,7 +16,7 @@ public class RNTimeChangedPackage extends TurboReactPackage { @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { - if (name.equals(RNTimeChangedModule.NAME)) { + if (name.equals(RNTimeChangedImpl.NAME)) { return new RNTimeChangedModule(reactContext); } else { return null; @@ -29,10 +29,10 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { final Map moduleInfos = new HashMap<>(); boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; moduleInfos.put( - RNTimeChangedModule.NAME, + RNTimeChangedImpl.NAME, new ReactModuleInfo( - RNTimeChangedModule.NAME, - RNTimeChangedModule.NAME, + RNTimeChangedImpl.NAME, + RNTimeChangedImpl.NAME, false, // canOverrideExistingModule false, // needsEagerInit true, // hasConstants diff --git a/apps/mobile/android/app/src/oldarch/ReactNativeSecurityModule.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/ReactNativeSecurityModule.java similarity index 60% rename from apps/mobile/android/app/src/oldarch/ReactNativeSecurityModule.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/ReactNativeSecurityModule.java index c9bf9d29af..aabd46b648 100644 --- a/apps/mobile/android/app/src/oldarch/ReactNativeSecurityModule.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/ReactNativeSecurityModule.java @@ -6,11 +6,11 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.module.annotations.ReactModule; import android.view.WindowManager; +@ReactModule(name = ReactNativeSecurityImpl.NAME) public class ReactNativeSecurityModule extends SimplePackageSpec { - public static final String NAME = "ReactNativeSecurity"; - ReactNativeSecurityModule(ReactApplicationContext context) { super(context); } @@ -18,7 +18,7 @@ public class ReactNativeSecurityModule extends SimplePackageSpec { @Override @NonNull public String getName() { - return NAME; + return ReactNativeSecurityImpl.NAME; } @ReactMethod @@ -26,12 +26,7 @@ public void blockScreen() { final Activity activity = getCurrentActivity(); if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); - } - }); + ReactNativeSecurityImpl.blockScreen(activity); } } @@ -40,12 +35,7 @@ public void unblockScreen() { final Activity activity = getCurrentActivity(); if (activity != null) { - activity.runOnUiThread(new Runnable() { - @Override - public void run() { - activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); - } - }); + ReactNativeSecurityImpl.unblockScreen(activity); } } } diff --git a/apps/mobile/android/app/src/oldarch/ReactNativeSecurityPackage.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/ReactNativeSecurityPackage.java similarity index 85% rename from apps/mobile/android/app/src/oldarch/ReactNativeSecurityPackage.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/ReactNativeSecurityPackage.java index ee311d4ab8..9915a3393c 100644 --- a/apps/mobile/android/app/src/oldarch/ReactNativeSecurityPackage.java +++ b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/ReactNativeSecurityPackage.java @@ -16,7 +16,7 @@ public class ReactNativeSecurityPackage extends TurboReactPackage { @Nullable @Override public NativeModule getModule(String name, ReactApplicationContext reactContext) { - if (name.equals(ReactNativeSecurityModule.NAME)) { + if (name.equals(ReactNativeSecurityImpl.NAME)) { return new ReactNativeSecurityModule(reactContext); } else { return null; @@ -29,10 +29,10 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() { final Map moduleInfos = new HashMap<>(); boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; moduleInfos.put( - ReactNativeSecurityModule.NAME, + ReactNativeSecurityImpl.NAME, new ReactModuleInfo( - ReactNativeSecurityModule.NAME, - ReactNativeSecurityModule.NAME, + ReactNativeSecurityImpl.NAME, + ReactNativeSecurityImpl.NAME, false, // canOverrideExistingModule false, // needsEagerInit true, // hasConstants diff --git a/apps/mobile/android/app/src/oldarch/SimplePackageSpec.java b/apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/SimplePackageSpec.java similarity index 100% rename from apps/mobile/android/app/src/oldarch/SimplePackageSpec.java rename to apps/mobile/android/app/src/oldarch/com/debank/rabbymobile/SimplePackageSpec.java diff --git a/apps/mobile/android/gradle.properties b/apps/mobile/android/gradle.properties index a1d42293e2..d12cdc1c38 100644 --- a/apps/mobile/android/gradle.properties +++ b/apps/mobile/android/gradle.properties @@ -36,7 +36,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 # your application. You should enable this flag either if you want # to write custom TurboModules/Fabric components OR use libraries that # are providing them. -newArchEnabled=false +newArchEnabled=true # Use this property to enable or disable the Hermes JS engine. # If set to false, you will be using JSC instead. diff --git a/apps/mobile/babel.config.js b/apps/mobile/babel.config.js index 181c68abbc..b389a5fd7d 100644 --- a/apps/mobile/babel.config.js +++ b/apps/mobile/babel.config.js @@ -93,7 +93,7 @@ module.exports = { ['module:react-native-dotenv', { moduleName: '@env' }], ['nativewind/babel', {}], ['@babel/plugin-proposal-decorators', { legacy: true }], - ['react-native-reanimated/plugin'], + ['react-native-reanimated/plugin', { processNestedWorklets: true }], ], env: { production: { diff --git a/apps/mobile/ios/Podfile.lock b/apps/mobile/ios/Podfile.lock index c83e32a593..0d398b3573 100644 --- a/apps/mobile/ios/Podfile.lock +++ b/apps/mobile/ios/Podfile.lock @@ -143,9 +143,6 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - MMKV (1.3.5): - - MMKVCore (~> 1.3.5) - - MMKVCore (1.3.14) - MultiplatformBleAdapter (0.2.0) - nanopb (2.30909.1): - nanopb/decode (= 2.30909.1) @@ -1567,11 +1564,10 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-mmkv (2.12.2): + - react-native-mmkv (3.3.1): - DoubleConversion - glog - hermes-engine - - MMKV (= 1.3.5) - RCT-Folly (= 2024.10.14.00) - RCTRequired - RCTTypeSafety @@ -1591,7 +1587,7 @@ PODS: - Yoga - react-native-netinfo (11.4.1): - React-Core - - react-native-pager-view (6.7.0): + - react-native-pager-view (6.9.0): - DoubleConversion - glog - hermes-engine @@ -1688,8 +1684,27 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-view-shot (3.7.0): + - react-native-view-shot (4.0.3): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.10.14.00) + - RCTRequired + - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-webview (13.10.5): - DoubleConversion - glog @@ -1995,12 +2010,12 @@ PODS: - React-Core - SDWebImage (~> 5.11.1) - SDWebImageWebPCoder (~> 0.8.4) - - RNFBAnalytics (18.8.0): - - Firebase/Analytics (= 10.20.0) + - RNFBAnalytics (21.3.0): + - Firebase/Analytics (<= 11.4.0) - React-Core - RNFBApp - - RNFBApp (18.8.0): - - Firebase/CoreOnly (= 10.20.0) + - RNFBApp (21.3.0): + - Firebase/CoreOnly (<= 11.4.0) - React-Core - RNFlashList (1.8.0): - DoubleConversion @@ -2419,8 +2434,6 @@ SPEC REPOS: - GTMSessionFetcher - libwebp - lottie-ios - - MMKV - - MMKVCore - MultiplatformBleAdapter - nanopb - OpenSSL-Universal @@ -2680,8 +2693,6 @@ SPEC CHECKSUMS: libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 lottie-ios: a881093fab623c467d3bce374367755c272bdd59 lottie-react-native: a068f2f23e19d825a0db2f3991af322deb42f7b9 - MMKV: 506311d0494023c2f7e0b62cc1f31b7370fa3cfb - MMKVCore: 3f40b896e9ab522452df9df3ce983471aa2449ba MultiplatformBleAdapter: b1fddd0d499b96b607e00f0faa8e60648343dc1d nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2 @@ -2725,9 +2736,9 @@ SPEC CHECKSUMS: react-native-get-random-values: 384787fd76976f5aec9465aff6fa9e9129af1e74 react-native-ios-context-menu: e529171ba760a1af7f2ef0729f5a7f4d226171c5 react-native-keyboard-controller: 88ad370bd43ecaa7b3aea76f9df4726edb0236c9 - react-native-mmkv: 5fc4966efbe7bf2b317be36c613518b6672d5855 + react-native-mmkv: fe6cb18b10463c8f1a4cde3fe69e3f4bae146202 react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac - react-native-pager-view: 31ec5d2c3bb0298e353bb704234dd94e6240a6fc + react-native-pager-view: bd603218c5b8175a62f1d7905f74b9da82753fb7 react-native-quick-crypto: dc51e77fcb59697adaff88b30b36fcfdc4804a3f react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846 react-native-safe-area-context: 8870dc3e45c8d241336cd8ee3fa3fc76f3a040ac @@ -2735,7 +2746,7 @@ SPEC CHECKSUMS: react-native-sqlite-storage: 539c4cc1ad30de152e3e04ee8d556e825fec4432 react-native-version-check: 6cd36aad4e30b8e3216747e3b4ddeb09e0647af8 react-native-video: dceb1fe91d9c495885c0a57ef1aa384f15ec07b3 - react-native-view-shot: f5507655f122e6b104888a11130f267a427f0d57 + react-native-view-shot: 4d1484f4902d1f60129205c4aae76cf44534c574 react-native-webview: f05bd802524a640e3d2eff578a8fb62e71e301ff React-nativeconfig: 415626a63057638759bcc75e0a96e2e07771a479 React-NativeModulesApple: bffc60f55895c2723b1e5472fa40567fe3df4923 @@ -2762,15 +2773,15 @@ SPEC CHECKSUMS: React-runtimescheduler: 222c73a654f32e3544a1384b2ced809bd51df2af React-timing: a693c531e5627dcc200fc7286cbbebf73d73469d React-utils: 52cb73e127a39fc2d9f02f503b2a7b3b0abd23dd - ReactCodegen: 31fcff227d0035956575be0c013a2edcc687a53c + ReactCodegen: 8e0386e1b1b895debc4e026488d742eb0fb5936f ReactCommon: 78c49c7cf7df16983ebc3c646b4f47398437f2ec ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60 RNCClipboard: 60fed4b71560d7bfe40e9d35dea9762b024da86d RNCMaskedView: 090213d32d8b3bb83a4dcb7d12c18f0152591906 RNDeviceInfo: feea80a690d2bde1fe51461cf548039258bd03f2 RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8 - RNFBAnalytics: 991772a4cd8c90de9a5eec33ef24dbba6e028c5b - RNFBApp: a4f5b074984cf612e4c97d68b42be690c59e2638 + RNFBAnalytics: f2d2de1d546f626bbe9ca1be75fdf156930a8efe + RNFBApp: def68a9cfa45d685d540a2934bab81bc32e8cc87 RNFlashList: 6803b075d8c3134c1ea3a413bedbf7e3d1736db8 RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNGestureHandler: db8f75c5eeead4943d127b5e261b830c2680c738 diff --git a/apps/mobile/ios/RabbyMobile.xcodeproj/project.pbxproj b/apps/mobile/ios/RabbyMobile.xcodeproj/project.pbxproj index f22f4fe163..71165d0d38 100644 --- a/apps/mobile/ios/RabbyMobile.xcodeproj/project.pbxproj +++ b/apps/mobile/ios/RabbyMobile.xcodeproj/project.pbxproj @@ -394,7 +394,7 @@ name = "[CP-User] [RNFB] Core Configuration"; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##########################################################################\n##########################################################################\n#\n# NOTE THAT IF YOU CHANGE THIS FILE YOU MUST RUN pod install AFTERWARDS\n#\n# This file is installed as an Xcode build script in the project file\n# by cocoapods, and you will not see your changes until you pod install\n#\n##########################################################################\n##########################################################################\n\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -Ku -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n if ! python3 --version >/dev/null 2>&1; then echo \"python3 not found, firebase.json file processing error.\" && exit 1; fi\n _JSON_OUTPUT_BASE64=$(python3 -c 'import json,sys,base64;print(base64.b64encode(bytes(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"', '\"'rb'\"').read())['${_JSON_ROOT}']), '\"'utf-8'\"')).decode())' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_analytics_storage\n _ANALYTICS_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_analytics_storage\")\n if [[ $_ANALYTICS_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_ANALYTICS_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_storage\n _ANALYTICS_AD_STORAGE=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_storage\")\n if [[ $_ANALYTICS_AD_STORAGE ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_STORAGE\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_STORAGE\")\")\n fi\n\n # config.analytics_default_allow_ad_user_data\n _ANALYTICS_AD_USER_DATA=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_user_data\")\n if [[ $_ANALYTICS_AD_USER_DATA ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_USER_DATA\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AD_USER_DATA\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.analytics_registration_with_ad_network_enabled\n _ANALYTICS_REGISTRATION_WITH_AD_NETWORK=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_registration_with_ad_network_enabled\")\n if [[ $_ANALYTICS_REGISTRATION_WITH_AD_NETWORK ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_REGISTRATION_WITH_AD_NETWORK_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_REGISTRATION_WITH_AD_NETWORK\")\")\n fi\n\n # config.google_analytics_automatic_screen_reporting_enabled\n _ANALYTICS_AUTO_SCREEN_REPORTING=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"google_analytics_automatic_screen_reporting_enabled\")\n if [[ $_ANALYTICS_AUTO_SCREEN_REPORTING ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAutomaticScreenReportingEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_SCREEN_REPORTING\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; }; 97C8DB28D26F4537BDE36325 /* Upload Debug Symbols to Sentry */ = { isa = PBXShellScriptBuildPhase; diff --git a/apps/mobile/ios/RabbyMobile/AppDelegate.mm b/apps/mobile/ios/RabbyMobile/AppDelegate.mm index f350217a62..51be38976d 100644 --- a/apps/mobile/ios/RabbyMobile/AppDelegate.mm +++ b/apps/mobile/ios/RabbyMobile/AppDelegate.mm @@ -55,8 +55,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.moduleName = @"RabbyMobile"; NSString *rabbitCodeFromBundle = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"rabbit_code"]; + NSString *turboModuleEnabled = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"turbo_module_enabled"]; NSString *rabbitCode = rabbitCodeFromBundle ?: @"RABBY_MOBILE_CODE_DEV"; - self.initialProps = @{ @"rabbitCode": rabbitCode }; + self.initialProps = @{ @"rabbitCode": rabbitCode, @"turboModuleEnabled": @(turboModuleEnabled.boolValue) }; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; diff --git a/apps/mobile/ios/RabbyMobile/Info.plist b/apps/mobile/ios/RabbyMobile/Info.plist index 4ecbe096d1..c2f4a90d95 100644 --- a/apps/mobile/ios/RabbyMobile/Info.plist +++ b/apps/mobile/ios/RabbyMobile/Info.plist @@ -119,5 +119,7 @@ rabbit_code $(RABBY_MOBILE_CODE) + turbo_module_enabled + $(RABBY_MOBILE_NEW_ARCH_ENABLED) diff --git a/apps/mobile/metro.config.js b/apps/mobile/metro.config.js index 4cc41a5539..9523885ced 100644 --- a/apps/mobile/metro.config.js +++ b/apps/mobile/metro.config.js @@ -67,6 +67,11 @@ const config = { transform: { experimentalImportSupport: false, inlineRequires: true, + // // it's recommended to disable on new arch enabled + // ...(process.env.NODE_ENV === 'production' && + // process.env.RABBY_MOBILE_NEW_ARCH_ENABLED !== 'true' && { + // inlineRequires: false, + // }), }, }), }, diff --git a/apps/mobile/package.json b/apps/mobile/package.json index e67b5dc736..8a7d954618 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -25,12 +25,14 @@ "check-nodeengines": "node -v | grep -E '^v(22|24)' > /dev/null || (echo \"Error: Node.js v22 or higher is required. Current version: $(node -v)\"; exit 1)", "restart": "yarn start --reset-cache", "start": "yarn check-nodeengines && yarn ensure-git-hooks && yarn build:deps && yarn build-inpage && cross-env NODE_OPTIONS=--max_old_space_size=8192 react-native start", + "start:newarch": "cross-env RABBY_MOBILE_NEW_ARCH_ENABLED=true yarn start", "sync:data": "node ./scripts/sync.js", "syncrnversion": "./node_modules/.bin/react-native-version --never-amend --never-increment-build", "rnversion": "yarn syncrnversion && yarn android:buildversion", "android:buildversion": "react-native-version --never-amend --target android --increment-build", "ios:clean:podlock": "rimraf ./ios/Pods ./ios/Podfile.lock", - "ios:installpod": "cd ios && bundle install && bundle exec pod install && cd ..", + "ios:installpod": "cd ios && bundle install && cross-env bundle exec pod install && cd ..", + "ios:installpod:newarch": "cd ios && bundle install && cross-env RCT_NEW_ARCH_ENABLED=1 bundle exec pod install && cd ..", "ios:podlock": "yarn && yarn ios:clean:podlock && yarn ios:installpod", "test": "jest", "postversion": "react-native-version --never-amend" @@ -51,7 +53,7 @@ "@ethereumjs/common": "4.2.0", "@ethereumjs/tx": "5.1.0", "@ethereumjs/util": "^9.0.1", - "@gorhom/bottom-sheet": "5.0.0-alpha.9", + "@gorhom/bottom-sheet": "5.1.8", "@ledgerhq/react-native-hw-transport-ble": "6.33.4", "@metamask/abi-utils": "3.0.0", "@metamask/browser-passworder": "6.0.0", @@ -81,14 +83,14 @@ "@react-native-community/blur": "4.4.1", "@react-native-community/hooks": "100.1.0", "@react-native-community/netinfo": "11.4.1", - "@react-native-firebase/analytics": "18.8.0", - "@react-native-firebase/app": "18.8.0", + "@react-native-firebase/analytics": "21.3.0", + "@react-native-firebase/app": "21.3.0", "@react-native-google-signin/google-signin": "13.2.0", "@react-native-masked-view/masked-view": "^0.3.1", "@react-native-menu/menu": "1.2.3", - "@react-navigation/bottom-tabs": "^6.5.11", - "@react-navigation/native": "^6.1.9", - "@react-navigation/native-stack": "^6.9.17", + "@react-navigation/bottom-tabs": "7.4.7", + "@react-navigation/native": "7.1.17", + "@react-navigation/native-stack": "7.3.26", "@rematch/core": "^2.2.0", "@rneui/base": "^4.0.0-rc.8", "@rneui/themed": "^4.0.0-rc.8", @@ -143,7 +145,7 @@ "react-native-ble-plx": "3.1.2", "react-native-bundle-splitter": "^3.0.1", "react-native-cloud-storage": "^1.4.1", - "react-native-collapsible-tab-view": "^6.2.1", + "react-native-collapsible-tab-view": "7.0.1", "react-native-crypto-js": "^1.0.0", "react-native-device-info": "14.0.4", "react-native-dotenv": "^3.4.9", @@ -163,8 +165,8 @@ "react-native-keychain": "8.0.0", "react-native-linear-gradient": "^2.8.3", "react-native-localize": "3.3.0", - "react-native-mmkv": "^2.12.2", - "react-native-pager-view": "6.7.0", + "react-native-mmkv": "3.3.1", + "react-native-pager-view": "6.9.0", "react-native-permissions": "5.3.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-crypto": "0.7.13", @@ -181,7 +183,7 @@ "react-native-vector-icons": "^10.0.2", "react-native-version-check": "^3.4.7", "react-native-video": "6.12.0", - "react-native-view-shot": "3.7.0", + "react-native-view-shot": "4.0.3", "react-native-vision-camera": "4.6.4", "react-native-wagmi-charts": "^2.3.2", "react-native-walkthrough-tooltip": "^1.5.0", @@ -258,5 +260,13 @@ }, "installConfig": { "hoistingLimits": "workspaces" + }, + "codegenConfig": { + "name": "RabbyMobileSpec", + "type": "modules", + "jsSrcsDir": "src/core/native/specs", + "android": { + "javaPackageName": "com.debank.rabbymobile" + } } } diff --git a/apps/mobile/react-native.config.js b/apps/mobile/react-native.config.js index 60b5b11f40..0e1990faab 100644 --- a/apps/mobile/react-native.config.js +++ b/apps/mobile/react-native.config.js @@ -1,7 +1,9 @@ +/** @type {import("@react-native-community/cli-types").Config} */ module.exports = { assets: ['./assets/fonts', './assets/custom'], iosAssets: [], androidAssets: [], + // unstable_reactLegacyComponentNames: [], dependencies: { 'react-native-ios-context-menu': { platforms: { diff --git a/apps/mobile/scripts/deploy-android.sh b/apps/mobile/scripts/deploy-android.sh index bbdeaf0808..18532d45d5 100755 --- a/apps/mobile/scripts/deploy-android.sh +++ b/apps/mobile/scripts/deploy-android.sh @@ -34,6 +34,11 @@ deployment_local_dir="$script_dir/deployments/android" rm -rf $deployment_local_dir && mkdir -p $deployment_local_dir; +if [ "$RABBY_MOBILE_NEW_ARCH_ENABLED" == "true" ]; then + cp $project_dir/android/gradle.properties $project_dir/android/gradle.properties.bak + sed -i.bak 's/^newArchEnabled=[^[:space:]]*$/newArchEnabled=true/' $project_dir/android/gradle.properties +fi + build_selfhost() { export RABBY_MOBILE_BUILD_ENV="regression"; [ -z "$CI" ] && yarn; diff --git a/apps/mobile/scripts/deploy-ios-adhoc.sh b/apps/mobile/scripts/deploy-ios-adhoc.sh index d350f34d84..b6509a57a2 100755 --- a/apps/mobile/scripts/deploy-ios-adhoc.sh +++ b/apps/mobile/scripts/deploy-ios-adhoc.sh @@ -57,6 +57,9 @@ build_adhoc() { yarn; yarn syncrnversion; cd $project_dir/ios; + if [ "$RABBY_MOBILE_NEW_ARCH_ENABLED" == "true" ]; then + export RCT_NEW_ARCH_ENABLED=1; + fi bundle install && bundle exec pod install --repo-update; cd $project_dir; bundle exec fastlane ios adhoc; diff --git a/apps/mobile/scripts/newarch-codegen.sh b/apps/mobile/scripts/newarch-codegen.sh new file mode 100755 index 0000000000..699bfc067b --- /dev/null +++ b/apps/mobile/scripts/newarch-codegen.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +script_dir="$( cd "$( dirname "$0" )" && pwd )" +project_dir=$(dirname $script_dir) + +cd $project_dir/android && ./gradlew generateCodegenArtifactsFromSchema; + +# node $project_dir/node_modules/react-native/scripts/generate-codegen-artifacts.js \ +# --path . \ +# --outputPath . \ +# --targetPlatform android + +# node node_modules/react-native/scripts/generate-codegen-artifacts.js \ +# --path . \ +# --outputPath ios/ \ +# --targetPlatform ios diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx index 5071a868f3..d1c3b43958 100644 --- a/apps/mobile/src/App.tsx +++ b/apps/mobile/src/App.tsx @@ -53,9 +53,9 @@ const rneuiTheme = createTheme({ }, }); -type AppProps = { rabbitCode: string }; +type AppProps = { rabbitCode: string; turboModuleEnabled: boolean }; -function MainScreen({ rabbitCode }: AppProps) { +function MainScreen({ rabbitCode, turboModuleEnabled }: AppProps) { const { isAppUnlocked } = useInitializeAppOnTop(); const { couldRender, securityChainOnTop } = useBootstrapApp({ rabbitCode }); const { binaryTheme } = useAppTheme({ isAppTop: true }); @@ -102,7 +102,7 @@ function MainScreen({ rabbitCode }: AppProps) { ); } -function App({ rabbitCode }: AppProps): JSX.Element { +function App({ rabbitCode, turboModuleEnabled }: AppProps): JSX.Element { return ( @@ -114,6 +114,7 @@ function App({ rabbitCode }: AppProps): JSX.Element { {/* read from native bundle on production */} {/* */} diff --git a/apps/mobile/src/AppNavigation.tsx b/apps/mobile/src/AppNavigation.tsx index 25976c9361..495070a731 100644 --- a/apps/mobile/src/AppNavigation.tsx +++ b/apps/mobile/src/AppNavigation.tsx @@ -1,8 +1,10 @@ import { createCustomNativeStackNavigator as createNativeStackNavigator } from '@/utils/CustomNativeStackNavigator'; +// import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { DarkTheme, DefaultTheme, NavigationContainer, + NavigationIndependentTree, } from '@react-navigation/native'; import React, { useCallback, useMemo, useRef } from 'react'; import { Appearance, BackHandler, ColorSchemeName } from 'react-native'; @@ -20,7 +22,7 @@ import { useSetNavigationReady, useStackScreenConfig, } from './hooks/navigation'; -import { analytics, matomoLogScreenView } from './utils/analytics'; +// import { analytics, matomoLogScreenView } from './utils/analytics'; import { TestkitsNavigator, @@ -407,11 +409,11 @@ export default function AppNavigation({ } onRouteChange(readyRootName); - analytics.logScreenView({ - screen_name: readyRootName, - screen_class: readyRootName, - }); - matomoLogScreenView({ name: readyRootName }); + // analytics.logScreenView({ + // screen_name: readyRootName, + // screen_class: readyRootName, + // }); + // matomoLogScreenView({ name: readyRootName }); }, [setNavigationReady, isAppUnlocked, onRouteChange]); const { hasActiveDapp: isShowingDappCard } = useOpenedActiveDappState(); @@ -447,11 +449,11 @@ export default function AppNavigation({ ); } - analytics.logScreenView({ - screen_name: routeNameRef.current, - screen_class: routeNameRef.current, - }); - matomoLogScreenView({ name: currentRouteName! }); + // analytics.logScreenView({ + // screen_name: routeNameRef.current, + // screen_class: routeNameRef.current, + // }); + // matomoLogScreenView({ name: currentRouteName! }); } routeNameRef.current = currentRouteName; }, @@ -476,46 +478,47 @@ export default function AppNavigation({ {/* */} - - - - - + + + + + null}> - - - {/* null}> + + + {/* */} - - - - - - + + + + + + + {/** @warning put all business stub components before this modal */} diff --git a/apps/mobile/src/components/GlobalBottomSheetModal/GlobalBottomSheetModal.tsx b/apps/mobile/src/components/GlobalBottomSheetModal/GlobalBottomSheetModal.tsx index eeb8db4843..8411e80f78 100644 --- a/apps/mobile/src/components/GlobalBottomSheetModal/GlobalBottomSheetModal.tsx +++ b/apps/mobile/src/components/GlobalBottomSheetModal/GlobalBottomSheetModal.tsx @@ -106,12 +106,11 @@ export const GlobalBottomSheetModal = () => { }; modalRefs.current[id] = newModal.ref; - setTimeout(() => { - handlePresent(id); - }, 100); - return [...prev, newModal]; }); + setTimeout(() => { + handlePresent(id); + }, 0); }, [getApproval, handlePresent], ); diff --git a/apps/mobile/src/components/Toast.tsx b/apps/mobile/src/components/Toast.tsx index 81d6553761..57780fe94e 100644 --- a/apps/mobile/src/components/Toast.tsx +++ b/apps/mobile/src/components/Toast.tsx @@ -5,6 +5,7 @@ import { ActivityIndicator, StyleProp, TextStyle, + Dimensions, } from 'react-native'; import Toast, { ToastOptions } from 'react-native-root-toast'; import { SvgProps } from 'react-native-svg'; @@ -17,6 +18,7 @@ import { } from '@/assets/icons/common'; import React from 'react'; import { ThemeColors } from '@/constant/theme'; +import { makeDebugBorder } from '@/utils/styles'; const config: ToastOptions = { position: Toast.positions.TOP + 80, @@ -190,6 +192,7 @@ const styles = StyleSheet.create({ container: { flexDirection: 'row', alignItems: 'center', + maxWidth: Dimensions.get('window').width - 32, }, icon: { marginRight: 8, diff --git a/apps/mobile/src/components/patches/BottomSheetBackdrop.tsx b/apps/mobile/src/components/patches/BottomSheetBackdrop.tsx index f64683c5be..340550ece4 100644 --- a/apps/mobile/src/components/patches/BottomSheetBackdrop.tsx +++ b/apps/mobile/src/components/patches/BottomSheetBackdrop.tsx @@ -1,25 +1,30 @@ -// patch from file:///./../../../node_modules/@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/BottomSheetBackdrop.tsx - -import React, { memo, useCallback, useMemo, useState } from 'react'; -import { ViewProps } from 'react-native'; +import React, { + memo, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import type { ViewProps } from 'react-native'; +import { Gesture, GestureDetector } from 'react-native-gesture-handler'; import Animated, { interpolate, - Extrapolate, useAnimatedStyle, useAnimatedReaction, - useAnimatedGestureHandler, runOnJS, + Extrapolation, } from 'react-native-reanimated'; -import { - TapGestureHandler, - TapGestureHandlerGestureEvent, -} from 'react-native-gesture-handler'; import { useBottomSheet } from '@gorhom/bottom-sheet'; import { - DEFAULT_OPACITY, + DEFAULT_ACCESSIBILITY_HINT, + DEFAULT_ACCESSIBILITY_LABEL, + DEFAULT_ACCESSIBILITY_ROLE, + DEFAULT_ACCESSIBLE, DEFAULT_APPEARS_ON_INDEX, DEFAULT_DISAPPEARS_ON_INDEX, DEFAULT_ENABLE_TOUCH_THROUGH, + DEFAULT_OPACITY, DEFAULT_PRESS_BEHAVIOR, } from '@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/constants'; import { styles } from '@gorhom/bottom-sheet/src/components/bottomSheetBackdrop/styles'; @@ -41,9 +46,14 @@ const BottomSheetBackdropComponent = ({ onPress, style, children, + accessible: _providedAccessible = DEFAULT_ACCESSIBLE, + accessibilityRole: _providedAccessibilityRole = DEFAULT_ACCESSIBILITY_ROLE, + accessibilityLabel: _providedAccessibilityLabel = DEFAULT_ACCESSIBILITY_LABEL, + accessibilityHint: _providedAccessibilityHint = DEFAULT_ACCESSIBILITY_HINT, }: BottomSheetDefaultBackdropProps) => { //#region hooks const { snapToIndex, close } = useBottomSheet(); + const isMounted = useRef(false); //#endregion const { isLight } = useTheme2024(); @@ -77,36 +87,36 @@ const BottomSheetBackdropComponent = ({ }, [snapToIndex, close, disappearsOnIndex, pressBehavior, onPress]); const handleContainerTouchability = useCallback( (shouldDisableTouchability: boolean) => { - setPointerEvents(shouldDisableTouchability ? 'none' : 'auto'); + isMounted.current && + setPointerEvents(shouldDisableTouchability ? 'none' : 'auto'); }, [], ); //#endregion //#region tap gesture - const gestureHandler = - useAnimatedGestureHandler( - { - onFinish: () => { - runOnJS(handleOnPress)(); - }, - }, - [handleOnPress], - ); + const tapHandler = useMemo(() => { + const gesture = Gesture.Tap().onEnd(() => { + runOnJS(handleOnPress)(); + }); + return gesture; + }, [handleOnPress]); //#endregion //#region styles - const containerAnimatedStyle = useAnimatedStyle(() => ({ - opacity: interpolate( - animatedIndex.value, - [-1, disappearsOnIndex, appearsOnIndex], - [0, 0, opacity], - Extrapolate.CLAMP, - ), - flex: 1, - })); + const containerAnimatedStyle = useAnimatedStyle( + () => ({ + opacity: interpolate( + animatedIndex.value, + [-1, disappearsOnIndex, appearsOnIndex], + [0, 0, opacity], + Extrapolation.CLAMP, + ), + }), + [animatedIndex, appearsOnIndex, disappearsOnIndex, opacity], + ); const containerStyle = useMemo( - () => [styles.container, style, containerAnimatedStyle], + () => [styles.backdrop, style, containerAnimatedStyle], [style, containerAnimatedStyle], ); //#endregion @@ -122,32 +132,43 @@ const BottomSheetBackdropComponent = ({ }, [disappearsOnIndex], ); + + // addressing updating the state after unmounting. + // [link](https://github.com/gorhom/react-native-bottom-sheet/issues/1376) + useEffect(() => { + isMounted.current = true; + return () => { + isMounted.current = false; + }; + }, []); //#endregion - return ( - - {pressBehavior !== 'none' ? ( - - {children} - - ) : ( - - {children} - - )} - + const AnimatedView = ( + + {children} + + ); + + return pressBehavior !== 'none' ? ( + {AnimatedView} + ) : ( + AnimatedView ); }; -const AppBottomSheetBackdrop = memo(BottomSheetBackdropComponent); +export const AppBottomSheetBackdrop = memo(BottomSheetBackdropComponent); AppBottomSheetBackdrop.displayName = 'BottomSheetBackdrop'; export default AppBottomSheetBackdrop; diff --git a/apps/mobile/src/constant/env.ts b/apps/mobile/src/constant/env.ts index 119e7c0a8a..efbde19595 100644 --- a/apps/mobile/src/constant/env.ts +++ b/apps/mobile/src/constant/env.ts @@ -33,6 +33,8 @@ export function getSentryEnv() { export const SENTRY_DEBUG = APP_RUNTIME_ENV !== 'production'; export const IS_HERMES_ENABLED = !!(global as any).HermesInternal; +export const isTurboModuleEnabled = !!global.__turboModuleProxy; +export const isFabricEnabled = !!global.nativeFabricUIManager; export const isSelfhostRegPkg = BUILD_CHANNEL === 'selfhost-reg'; export const isNonPublicProductionEnv = isSelfhostRegPkg || __DEV__; diff --git a/apps/mobile/src/core/apis/address.ts b/apps/mobile/src/core/apis/address.ts index fb0c9bcc75..988ac0e5f6 100644 --- a/apps/mobile/src/core/apis/address.ts +++ b/apps/mobile/src/core/apis/address.ts @@ -1,4 +1,3 @@ -import { isSameAccount } from '@/hooks/accountsSwitcher'; import { KeyringAccountWithAlias } from '@/hooks/account'; import { KEYRING_TYPE } from '@rabby-wallet/keyring-utils'; import { @@ -13,6 +12,7 @@ import { import { getKeyring } from './keyring'; import { addressUtils } from '@rabby-wallet/base-utils'; import { BroadcastEvent } from '@/constant/event'; +import { isSameAccount } from '@/utils/account'; export async function addWatchAddress(address: string) { const keyring = await getKeyring(KEYRING_TYPE.WatchAddressKeyring); diff --git a/apps/mobile/src/core/apis/provider.ts b/apps/mobile/src/core/apis/provider.ts index a0a557b4fe..94f3989d3c 100644 --- a/apps/mobile/src/core/apis/provider.ts +++ b/apps/mobile/src/core/apis/provider.ts @@ -51,7 +51,7 @@ export default function buildUnserializedTransaction(txMeta) { return TransactionFactory.fromTxData(txParams, { common }); } -export { sendRequest } from './sendRequest'; +// export { sendRequest } from './sendRequest'; export const requestETHRpc = ( data: { method: string; params: any }, diff --git a/apps/mobile/src/core/native/RNHelpers.ts b/apps/mobile/src/core/native/RNHelpers.ts index dab90c6431..6b967d36dd 100644 --- a/apps/mobile/src/core/native/RNHelpers.ts +++ b/apps/mobile/src/core/native/RNHelpers.ts @@ -1,31 +1,34 @@ +import { NativeModuleNames } from './specs/types'; import { makeRnEEClass, resolveNativeModule, wrapPlatformOnlyMethod, } from './utils'; -const { RNHelpers: nativeModule } = resolveNativeModule('RNHelpers'); +const { RNHelpers: nativeModule } = resolveNativeModule( + NativeModuleNames.RNHelpers, +); -type Listeners = {}; -const { NativeEventEmitter } = makeRnEEClass(); -const eventEmitter = new NativeEventEmitter(nativeModule); +// type Listeners = {}; +// const { NativeEventEmitter } = makeRnEEClass(); +// const eventEmitter = new NativeEventEmitter(nativeModule); -function makeDefaultHandler(fn: Listeners[T]) { - if (typeof fn !== 'function') { - console.error('RNHelpers: addListener requires valid callback function'); +// function makeDefaultHandler(fn: Listeners[T]) { +// if (typeof fn !== 'function') { +// console.error('RNHelpers: addListener requires valid callback function'); - return { - remove: (): void => { - console.error( - 'RNHelpers: remove not work because addListener requires valid callback function', - ); - }, - }; - } -} +// return { +// remove: (): void => { +// console.error( +// 'RNHelpers: remove not work because addListener requires valid callback function', +// ); +// }, +// }; +// } +// } const RNHelpers = Object.freeze({ - ...nativeModule, + forceExitApp: nativeModule.forceExitApp, iosExcludeFileFromBackup: wrapPlatformOnlyMethod({ method: nativeModule.iosExcludeFileFromBackup, platform: 'ios', diff --git a/apps/mobile/src/core/native/RNScreenshotPrevent.ts b/apps/mobile/src/core/native/RNScreenshotPrevent.ts index 50123d61da..8e1eb84337 100644 --- a/apps/mobile/src/core/native/RNScreenshotPrevent.ts +++ b/apps/mobile/src/core/native/RNScreenshotPrevent.ts @@ -1,43 +1,17 @@ -import { PermissionsAndroid } from 'react-native'; +import { NativeModuleNames } from './specs/types'; import { - IS_ANDROID, - IS_IOS, + EventEmitterRecordToListeners, makeRnEEClass, resolveNativeModule, } from './utils'; -import i18next from 'i18next'; const { RNScreenshotPrevent: nativeModule } = resolveNativeModule( - 'RNScreenshotPrevent', + NativeModuleNames.RNScreenshotPrevent, ); -type Listeners = { - /** - * @platform iOS, Android >= 14 - */ - userDidTakeScreenshot: (ret?: { - androidScanEmpty?: string; - androidHasPermission?: boolean; - captured?: boolean; - path?: string; - height?: string | number; - width?: string | number; - imageBase64?: string; - imageType?: 'jpeg' | 'png'; - name?: string; - }) => any; - screenCapturedChanged: (ret: { isBeingCaptured: boolean }) => any; - screenCaptureDetectionChanged: (ret: { enabled: boolean }) => any; - /** - * @description subscribe to android app state change, pause means app is in background, resume means app is in foreground - */ - androidOnLifeCycleChanged: (ret: { state: 'resume' | 'pause' }) => any; - /** @description pointless now */ - preventScreenshotChanged: (ret: { - isPrevent: boolean; - success: boolean; - }) => any; -}; +type Listeners = EventEmitterRecordToListeners< + import('./specs/NativeRNScreenshotPrevent').EventEmitterRecord +>; const { NativeEventEmitter } = makeRnEEClass(); const eventEmitter = new NativeEventEmitter(nativeModule); @@ -118,7 +92,10 @@ if (__DEV__) { * @see https://github.com/killserver/react-native-screenshot-prevent/issues/17 */ const RNScreenshotPrevent = Object.freeze({ - ...nativeModule, + togglePreventScreenshot: nativeModule.togglePreventScreenshot, + iosIsBeingCaptured: nativeModule.iosIsBeingCaptured, + iosProtectFromScreenRecording: nativeModule.iosProtectFromScreenRecording, + iosUnprotectFromScreenRecording: nativeModule.iosUnprotectFromScreenRecording, onPreventScreenshotChanged, // iosToggleBlurView(bool: boolean) { // nativeModule.iosToggleBlurView(!!bool); diff --git a/apps/mobile/src/core/native/RNTimeChanged.ts b/apps/mobile/src/core/native/RNTimeChanged.ts index e9d3027ed9..4755fdd4df 100644 --- a/apps/mobile/src/core/native/RNTimeChanged.ts +++ b/apps/mobile/src/core/native/RNTimeChanged.ts @@ -1,14 +1,17 @@ -import { makeRnEEClass, resolveNativeModule } from './utils'; - -const { RNTimeChanged: nativeModule } = resolveNativeModule('RNTimeChanged'); - -type Listeners = { - onTimeChanged: (ctx: { - androidAction?: string; - iosEvent?: string; - reason: 'timeSet' | 'timeZoneChanged' | 'unknown'; - }) => any; -}; +import { NativeModuleNames } from './specs/types'; +import { + EventEmitterRecordToListeners, + makeRnEEClass, + resolveNativeModule, +} from './utils'; + +const { RNTimeChanged: nativeModule } = resolveNativeModule( + NativeModuleNames.RNTimeChanged, +); + +type Listeners = EventEmitterRecordToListeners< + import('./specs/NativeRNTimeChanged').EventEmitterRecord +>; const { NativeEventEmitter } = makeRnEEClass(); const eventEmitter = new NativeEventEmitter(nativeModule); @@ -36,7 +39,7 @@ function subscribeTimeChanged(fn: Listeners['onTimeChanged']) { } const RNTimeChanged = Object.freeze({ - ...nativeModule, + exitAppForSecurity: nativeModule.exitAppForSecurity, subscribeTimeChanged, }); diff --git a/apps/mobile/src/core/native/ReactNativeSecurity.ts b/apps/mobile/src/core/native/ReactNativeSecurity.ts index 57b96d3796..ff1b1ccd8b 100644 --- a/apps/mobile/src/core/native/ReactNativeSecurity.ts +++ b/apps/mobile/src/core/native/ReactNativeSecurity.ts @@ -1,7 +1,10 @@ import { Platform } from 'react-native'; import { resolveNativeModule, IS_ANDROID } from './utils'; +import { NativeModuleNames } from './specs/types'; -const { ReactNativeSecurity } = resolveNativeModule('ReactNativeSecurity'); +const { ReactNativeSecurity } = resolveNativeModule( + NativeModuleNames.ReactNativeSecurity, +); export function nativeBlockScreen() { if (IS_ANDROID) { diff --git a/apps/mobile/src/core/native/specs/NativeRNHelpers.ts b/apps/mobile/src/core/native/specs/NativeRNHelpers.ts new file mode 100644 index 0000000000..049d767c24 --- /dev/null +++ b/apps/mobile/src/core/native/specs/NativeRNHelpers.ts @@ -0,0 +1,22 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; +import { ExtractEventEmitters, ExtractMethods } from './types'; + +export interface Spec extends TurboModule { + forceExitApp(): void; + /** + * @description try to set a file to not be backed up by iCloud + * @param filePath + */ + iosExcludeFileFromBackup(filePath: string): Promise; + // /** + // * @description try to set a directory's files(including files in subdirectories) to not be backed up by iCloud + // */ + // iosExcludeDirectoryFromBackup?(directoryPath: string): Promise; +} + +export default TurboModuleRegistry.getEnforcing('RNHelpers'); + +export type Methods = ExtractMethods; + +export type EventEmitterRecord = ExtractEventEmitters; diff --git a/apps/mobile/src/core/native/specs/NativeRNScreenshotPrevent.ts b/apps/mobile/src/core/native/specs/NativeRNScreenshotPrevent.ts new file mode 100644 index 0000000000..7ca555dd63 --- /dev/null +++ b/apps/mobile/src/core/native/specs/NativeRNScreenshotPrevent.ts @@ -0,0 +1,47 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; +import type { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes'; +import { ExtractEventEmitters, ExtractMethods, TrimNeverValues } from './types'; + +export interface Spec extends TurboModule { + readonly addListener: (eventType: string) => void; + readonly removeListeners: (count: number) => void; + + togglePreventScreenshot: (isPrevent: boolean) => void; + iosIsBeingCaptured(): boolean; + // iosToggleBlurView(isProtected: boolean): void; + iosProtectFromScreenRecording(): Promise; + iosUnprotectFromScreenRecording(): Promise; + + /** + * @platform iOS, Android >= 14 + */ + userDidTakeScreenshot: EventEmitter<{ + androidScanEmpty?: string; + androidHasPermission?: boolean; + captured?: boolean; + path?: string; + height?: string | number; + width?: string | number; + imageBase64?: string; + imageType?: 'jpeg' | 'png'; + name?: string; + }>; + screenCapturedChanged: EventEmitter<{ isBeingCaptured: boolean }>; + screenCaptureDetectionChanged: EventEmitter<{ enabled: boolean }>; + /** + * @description subscribe to android app state change, pause means app is in background, resume means app is in foreground + */ + androidOnLifeCycleChanged: EventEmitter<{ state: 'resume' | 'pause' }>; + /** @description pointless now */ + preventScreenshotChanged: EventEmitter<{ + isPrevent: boolean; + success: boolean; + }>; +} + +export default TurboModuleRegistry.getEnforcing('RNScreenshotPrevent'); + +export type Methods = ExtractMethods; + +export type EventEmitterRecord = ExtractEventEmitters; diff --git a/apps/mobile/src/core/native/specs/NativeRNTimeChanged.ts b/apps/mobile/src/core/native/specs/NativeRNTimeChanged.ts new file mode 100644 index 0000000000..081cf49dc2 --- /dev/null +++ b/apps/mobile/src/core/native/specs/NativeRNTimeChanged.ts @@ -0,0 +1,22 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; +import { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes'; +import { ExtractEventEmitters, ExtractMethods } from './types'; + +export interface Spec extends TurboModule { + readonly addListener: (eventType: string) => void; + readonly removeListeners: (count: number) => void; + + exitAppForSecurity(): void; + onTimeChanged: EventEmitter<{ + androidAction?: string; + iosEvent?: string; + reason: 'timeSet' | 'timeZoneChanged' | 'unknown'; + }>; +} + +export default TurboModuleRegistry.getEnforcing('RNTimeChanged'); + +export type Methods = ExtractMethods; + +export type EventEmitterRecord = ExtractEventEmitters; diff --git a/apps/mobile/src/core/native/specs/NativeReactNativeSecurity.ts b/apps/mobile/src/core/native/specs/NativeReactNativeSecurity.ts new file mode 100644 index 0000000000..2167835714 --- /dev/null +++ b/apps/mobile/src/core/native/specs/NativeReactNativeSecurity.ts @@ -0,0 +1,21 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +import { ExtractEventEmitters, ExtractMethods } from './types'; + +export interface Spec extends TurboModule { + /** + * @description Blocks the screen + */ + blockScreen(): void; + /** + * @description Unblocks the screen + */ + unblockScreen(): void; +} + +export default TurboModuleRegistry.getEnforcing('ReactNativeSecurity'); + +export type Methods = ExtractMethods; + +export type EventEmitterRecord = ExtractEventEmitters; diff --git a/apps/mobile/src/core/native/specs/index.ts b/apps/mobile/src/core/native/specs/index.ts new file mode 100644 index 0000000000..4382c320be --- /dev/null +++ b/apps/mobile/src/core/native/specs/index.ts @@ -0,0 +1,13 @@ +import { NativeModuleNames } from './types'; + +import RNHelpers from './NativeRNHelpers'; +import ReactNativeSecurity from './NativeReactNativeSecurity'; +import RNScreenshotPrevent from './NativeRNScreenshotPrevent'; +import RNTimeChanged from './NativeRNTimeChanged'; + +export const TurboNativeModules = { + [NativeModuleNames.RNHelpers]: RNHelpers, + [NativeModuleNames.ReactNativeSecurity]: ReactNativeSecurity, + [NativeModuleNames.RNScreenshotPrevent]: RNScreenshotPrevent, + [NativeModuleNames.RNTimeChanged]: RNTimeChanged, +}; diff --git a/apps/mobile/src/core/native/specs/types.ts b/apps/mobile/src/core/native/specs/types.ts new file mode 100644 index 0000000000..e41e1714f3 --- /dev/null +++ b/apps/mobile/src/core/native/specs/types.ts @@ -0,0 +1,28 @@ +import { type EventEmitter } from 'react-native/Libraries/Types/CodegenTypes'; + +// export type TrimNeverValues> = { +// [K in keyof T]-?: T[K] extends never ? never : T[K]; +// }; +export type TrimNeverValues> = { + [K in keyof T as T[K] extends never ? never : K]: T[K]; +}; + +export type ExtractEventEmitters> = + TrimNeverValues<{ + [P in keyof T as T[P] extends (...args: any[]) => void + ? P + : never]: T[P] extends EventEmitter ? T[P] : never; + }>; + +export type ExtractMethods> = TrimNeverValues<{ + [P in keyof T as T[P] extends (...args: any[]) => void + ? P + : never]: T[P] extends EventEmitter ? never : T[P]; +}>; + +export const enum NativeModuleNames { + RNHelpers = 'RNHelpers', + ReactNativeSecurity = 'ReactNativeSecurity', + RNScreenshotPrevent = 'RNScreenshotPrevent', + RNTimeChanged = 'RNTimeChanged', +} diff --git a/apps/mobile/src/core/native/utils.ts b/apps/mobile/src/core/native/utils.ts index e4411a3d73..04fb0ce7ea 100644 --- a/apps/mobile/src/core/native/utils.ts +++ b/apps/mobile/src/core/native/utils.ts @@ -6,55 +6,42 @@ import { Platform, UIManager, } from 'react-native'; +import { EventEmitter } from 'react-native/Libraries/Types/CodegenTypes'; import { enableLayoutAnimations } from 'react-native-reanimated'; +import { TurboNativeModules } from './specs'; +import { NativeModuleNames } from './specs/types'; -interface NativeModulesStatic { - ReactNativeSecurity: /* NativeModule & */ { - blockScreen(): void; - unblockScreen(): void; - }; - RNScreenshotPrevent: NativeModule & { - togglePreventScreenshot: (isPrevent: boolean) => void; - iosIsBeingCaptured(): boolean; - // iosToggleBlurView(isProtected: boolean): void; - iosProtectFromScreenRecording(): Promise; - iosUnprotectFromScreenRecording(): Promise; - }; - RNTimeChanged: NativeModule & { - exitAppForSecurity(): void; - }; - RNHelpers: NativeModule & { - forceExitApp(): void; - /** - * @description try to set a file to not be backed up by iCloud - * @param filePath - */ - iosExcludeFileFromBackup?(filePath: string): Promise; - // /** - // * @description try to set a directory's files(including files in subdirectories) to not be backed up by iCloud - // */ - // iosExcludeDirectoryFromBackup?(directoryPath: string): Promise; - }; -} +const isTurboModuleEnabled = global.__turboModuleProxy != null; + +type NativeModulesStatic = { + [NativeModuleNames.ReactNativeSecurity]: /* NativeModule & */ import('./specs/NativeReactNativeSecurity').Methods; + [NativeModuleNames.RNScreenshotPrevent]: NativeModule & + import('./specs/NativeRNScreenshotPrevent').Methods; + [NativeModuleNames.RNTimeChanged]: NativeModule & + import('./specs/NativeRNTimeChanged').Methods; + [NativeModuleNames.RNHelpers]: NativeModule & + import('./specs/NativeRNHelpers').Methods; +}; export const IS_ANDROID = Platform.OS === 'android'; export const IS_IOS = Platform.OS === 'ios'; if (IS_ANDROID) { enableLayoutAnimations(false); - UIManager.setLayoutAnimationEnabledExperimental && - UIManager.setLayoutAnimationEnabledExperimental(false); + // TODO: only use it if new arch not enabled + // UIManager.setLayoutAnimationEnabledExperimental && + // UIManager.setLayoutAnimationEnabledExperimental(false); } -export function resolveNativeModule( - name: T, -) { +export function resolveNativeModule(name: T) { const NATIVE_ERROR = `The native module '${name}' doesn't seem to be added. Make sure: \n\n` + '- You rebuilt the app after native code changed\n' + '- You are not using Expo managed workflow\n'; - const nModule = NativeModules[name]; + const nModule = isTurboModuleEnabled + ? TurboNativeModules[name] + : NativeModules[name]; const module: NativeModulesStatic[T] = nModule ? nModule @@ -74,6 +61,10 @@ export function resolveNativeModule( }; } +type EventEmitterDef = Record>; +export type EventEmitterRecordToListeners = { + [K in keyof T]: Parameters[0]; +}; type Listener = (resp?: any) => void; export function makeRnEEClass>() { diff --git a/apps/mobile/src/core/services/customRPCService.ts b/apps/mobile/src/core/services/customRPCService.ts index 4fbc16f6af..973be38661 100644 --- a/apps/mobile/src/core/services/customRPCService.ts +++ b/apps/mobile/src/core/services/customRPCService.ts @@ -89,7 +89,7 @@ const fetchDefaultRpc = async () => { return data.rpcs as RPCDefaultItem[]; }; -class CustomRPCService { +export class CustomRPCService { store: RPCServiceStore = { customRPC: {}, defaultRPC: {}, diff --git a/apps/mobile/src/core/services/preference.ts b/apps/mobile/src/core/services/preference.ts index a596be3138..bf580fb156 100644 --- a/apps/mobile/src/core/services/preference.ts +++ b/apps/mobile/src/core/services/preference.ts @@ -208,15 +208,19 @@ export class PreferenceService { private _allowedToNotifyAccountsChanged = false; + // private _matomoRequestEvent: typeof import('@/utils/analytics').matomoRequestEvent; + constructor( options: StorageAdapaterOptions & { keyringService: KeyringService; sessionService: import('./session').SessionService; + // matomoRequestEvent: typeof import('@/utils/analytics').matomoRequestEvent; }, ) { const defaultLang = 'en'; this.keyringService = options.keyringService; this.sessionService = options.sessionService; + // this._matomoRequestEvent = options.matomoRequestEvent; this.store = createPersistStore( { name: APP_STORE_NAMES.preference, diff --git a/apps/mobile/src/core/services/shared.ts b/apps/mobile/src/core/services/shared.ts index 3ef913c123..f991112f7d 100644 --- a/apps/mobile/src/core/services/shared.ts +++ b/apps/mobile/src/core/services/shared.ts @@ -44,6 +44,7 @@ import { TrezorKeyring } from '../keyring-bridge/trezor/trezor-keyring'; import { MetamaskModeService } from './metamaskModeService'; import { SyncChainService } from './syncChainService'; import { PerpsService } from './perpsService'; +import { setPreferenceServiceRef } from '@/utils/analytics'; import { CurrencyService } from './currencyService'; migrateAppStorage(appStorage); @@ -127,6 +128,7 @@ export const preferenceService = new PreferenceService({ keyringService, sessionService, }); +setPreferenceServiceRef(preferenceService); try_catch_issue_on_preference({ pos: 'after_preference' }); diff --git a/apps/mobile/src/core/services/transactionHistory.ts b/apps/mobile/src/core/services/transactionHistory.ts index 70adab45fb..7e39ce4a45 100644 --- a/apps/mobile/src/core/services/transactionHistory.ts +++ b/apps/mobile/src/core/services/transactionHistory.ts @@ -36,6 +36,7 @@ import { import { REPORT_TIMEOUT_ACTION_KEY } from './type'; import { updateExpiredTime } from '@/databases/sync/utils'; import { matomoRequestEvent } from '@/utils/analytics'; +import { customRPCService } from './customRPCService'; export interface TransactionHistoryItem { address: string; @@ -909,7 +910,7 @@ export class TransactionHistoryService { }); } else { // Use standard RPC to get transaction receipt - return getRpcTxReceipt(chain.serverId, tx.hash!); + return getRpcTxReceipt(chain.serverId, tx.hash!, customRPCService); } }), ); diff --git a/apps/mobile/src/core/storage/mmkv.ts b/apps/mobile/src/core/storage/mmkv.ts index 4fedac6f46..d82a01c543 100644 --- a/apps/mobile/src/core/storage/mmkv.ts +++ b/apps/mobile/src/core/storage/mmkv.ts @@ -1,7 +1,7 @@ // https://github.com/mrousavy/react-native-mmkv/blob/master/docs/WRAPPER_JOTAI.md // AsyncStorage 有 bug,会闪白屏 -import { MMKV, MMKVConfiguration } from 'react-native-mmkv'; +import { MMKV, Configuration as MMKVConfiguration } from 'react-native-mmkv'; import { stringUtils } from '@rabby-wallet/base-utils'; import { StorageAdapater } from '@rabby-wallet/persist-store'; diff --git a/apps/mobile/src/core/utils/tx.ts b/apps/mobile/src/core/utils/tx.ts index fd2f6664ca..2995a6369a 100644 --- a/apps/mobile/src/core/utils/tx.ts +++ b/apps/mobile/src/core/utils/tx.ts @@ -1,6 +1,6 @@ import { sortBy } from 'lodash'; import type { TransactionHistoryItem } from '../services/transactionHistory'; -import { customRPCService } from '../services'; +import type { CustomRPCService } from '../services/customRPCService'; const getGasPrice = (tx: TransactionHistoryItem) => { return Number(tx.rawTx.gasPrice || tx.rawTx.maxFeePerGas || 0); @@ -16,7 +16,11 @@ export const findMaxGasTx = (txs: TransactionHistoryItem[]) => { return list[0]; }; -export const getRpcTxReceipt = (chainServerId: string, hash: string) => { +export const getRpcTxReceipt = async ( + chainServerId: string, + hash: string, + customRPCService: CustomRPCService, +) => { return customRPCService .defaultEthRPC({ chainServerId, @@ -40,3 +44,7 @@ export const getRpcTxReceipt = (chainServerId: string, hash: string) => { }; }); }; + +export const isNFTTokenId = (tokenId: string) => { + return tokenId.length === 32; +}; diff --git a/apps/mobile/src/databases/entities/historyItem.ts b/apps/mobile/src/databases/entities/historyItem.ts index e70ef0eb1b..851c3d88ef 100644 --- a/apps/mobile/src/databases/entities/historyItem.ts +++ b/apps/mobile/src/databases/entities/historyItem.ts @@ -10,10 +10,7 @@ import { EntityAddressAssetBase } from './base'; import { columnConverter, badRealTransformer } from './_helpers'; import { prepareAppDataSource } from '../imports'; import { HistoryItemCateType } from '@/screens/Transaction/components/type'; -import { - fetchHistoryTokenItem, - isNFTTokenId, -} from '@/screens/Transaction/components/utils'; +import { fetchHistoryTokenItem, isNFTTokenId } from '@/utils/assets'; import { IManageToken } from '@/core/services/preference'; import { GAS_ACCOUNT_RECEIVED_ADDRESS, diff --git a/apps/mobile/src/hooks/accountsSelector.ts b/apps/mobile/src/hooks/accountsSelector.ts index 2d7fbf25c1..85aaa5e0c3 100644 --- a/apps/mobile/src/hooks/accountsSelector.ts +++ b/apps/mobile/src/hooks/accountsSelector.ts @@ -4,12 +4,10 @@ import { useCallback, useMemo } from 'react'; import { atom, useAtom } from 'jotai'; import { useSortAddressList } from '@/screens/Address/useSortAddressList'; import { KEYRING_CLASS } from '@rabby-wallet/keyring-utils'; +import { SceneAccount } from '@/utils/account'; export type AccountSwitcherScene = 'Receive' | 'GasAccount'; -type SceneAccount = Account & { - isPinned?: boolean; -}; export function useSortAccountOnSelector() { const { accounts } = useAccounts({ disableAutoFetch: true }); diff --git a/apps/mobile/src/hooks/accountsSwitcher.ts b/apps/mobile/src/hooks/accountsSwitcher.ts index 6d8eea29ea..30092f4377 100644 --- a/apps/mobile/src/hooks/accountsSwitcher.ts +++ b/apps/mobile/src/hooks/accountsSwitcher.ts @@ -14,6 +14,7 @@ import { SceneAccountInfo, sceneAccountInfoAtom, } from './sceneAccountInfoAtom'; +import { SceneAccount } from '@/utils/account'; export type PropsForAccountSwitchScreen = { isForMultipleAddress?: boolean; @@ -231,18 +232,10 @@ export function useSwitchSceneCurrentAccount() { }; } -export function isSameAccount( - account: Account, - saccount?: SceneAccount | null, -) { - if (!saccount) return false; +import { isSameAccount as _isSameAccount } from '@/utils/account'; - return ( - saccount?.address?.toLowerCase() === account.address.toLowerCase() && - saccount?.brandName === account.brandName && - saccount?.type === account.type - ); -} +/** @deprecated */ +export const isSameAccount = _isSameAccount; const ScenesSupportAllAccounts: AccountSwitcherScene[] = [ // 'Swap', @@ -325,9 +318,6 @@ function computeSceneAccountInfo({ return result; } -type SceneAccount = Account & { - isPinned?: boolean; -}; export function useSceneAccountInfo(options: { forScene: AccountSwitcherScene; }) { diff --git a/apps/mobile/src/hooks/navigation.tsx b/apps/mobile/src/hooks/navigation.tsx index 294672ce3e..40b8795369 100644 --- a/apps/mobile/src/hooks/navigation.tsx +++ b/apps/mobile/src/hooks/navigation.tsx @@ -115,6 +115,7 @@ export const useStackScreenConfig = () => { headerTintColor: colors['neutral-title-1'], headerLeft: ({ tintColor }) => ( @@ -157,6 +158,7 @@ export const useStackScreenConfig = () => { headerTintColor: colors2024['neutral-title-1'], headerLeft: ({ tintColor }) => ( @@ -219,6 +221,7 @@ export function useBottomTabScreenConfig() { headerTintColor: colors2024['neutral-title-1'], headerLeft: ({ tintColor }) => ( diff --git a/apps/mobile/src/navigation-type.ts b/apps/mobile/src/navigation-type.ts index 93863b6761..0bd03d5b03 100644 --- a/apps/mobile/src/navigation-type.ts +++ b/apps/mobile/src/navigation-type.ts @@ -37,7 +37,7 @@ import { } from './screens/Approvals/useApprovalsPage'; import { HistoryItemCateType } from './screens/Transaction/components/type'; import type { AddrDescResponse } from '@rabby-wallet/rabby-api/dist/types'; -import { TabType } from './screens/CopyTrading/component/CopyTradingTokenDetail'; +import { TabType } from './screens/CopyTrading/component/SameNameTokens'; import { DisplayedProject } from './screens/Home/utils/project'; /** @@ -445,15 +445,6 @@ export type GetNestedScreensParamsList< T extends _NestedScreensParamsName, K extends keyof _NestedScreensParamsDict[T] & string, > = _NestedScreensParamsDict[T][K]; - -/** @deprecated use `GetNestedScreenRouteProp` directly */ -export type GetNestedScreenNavigationProps< - T extends _NestedScreensParamsName, - K extends keyof _NestedScreensParamsDict[T] & string, -> = CompositeScreenProps< - NativeStackScreenProps<_NestedScreensParamsDict[T], K>, - NativeStackScreenProps ->; export type GetNestedScreenRouteProp< T extends _NestedScreensParamsName, K extends keyof _NestedScreensParamsDict[T] & string, diff --git a/apps/mobile/src/screens/Address/AddressListScreenButton.tsx b/apps/mobile/src/screens/Address/AddressListScreenButton.tsx index be7c05040e..33c81f194d 100644 --- a/apps/mobile/src/screens/Address/AddressListScreenButton.tsx +++ b/apps/mobile/src/screens/Address/AddressListScreenButton.tsx @@ -1,4 +1,4 @@ -import { TouchableOpacity } from 'react-native'; +import { TouchableOpacity } from 'react-native-gesture-handler'; import { StackActions, useNavigation } from '@react-navigation/core'; import { createGlobalBottomSheetModal2024, diff --git a/apps/mobile/src/screens/Address/CloudBackupButton.tsx b/apps/mobile/src/screens/Address/CloudBackupButton.tsx index 284d27ddde..0d839220da 100644 --- a/apps/mobile/src/screens/Address/CloudBackupButton.tsx +++ b/apps/mobile/src/screens/Address/CloudBackupButton.tsx @@ -1,5 +1,5 @@ import { CustomTouchableOpacity } from '@/components/CustomTouchableOpacity'; -import { HeaderButtonProps } from '@react-navigation/native-stack/lib/typescript/src/types'; +import { NativeStackHeaderRightProps } from '@react-navigation/native-stack'; import React from 'react'; import { RootNames } from '@/constant/layout'; import { navigate } from '@/utils/navigation'; @@ -14,7 +14,9 @@ const hitSlop = { }; /** @deprecated */ -export const CloudBackupButton: React.FC = ({}) => { +export const CloudBackupButton: React.FC< + NativeStackHeaderRightProps +> = ({}) => { const onPress = React.useCallback(() => { navigate(RootNames.StackAddress, { screen: RootNames.RestoreFromCloud, diff --git a/apps/mobile/src/screens/Address/CloudBackupButton2024.tsx b/apps/mobile/src/screens/Address/CloudBackupButton2024.tsx index d8f70218cd..a94696b471 100644 --- a/apps/mobile/src/screens/Address/CloudBackupButton2024.tsx +++ b/apps/mobile/src/screens/Address/CloudBackupButton2024.tsx @@ -1,5 +1,5 @@ import { CustomTouchableOpacity } from '@/components/CustomTouchableOpacity'; -import { HeaderButtonProps } from '@react-navigation/native-stack/lib/typescript/src/types'; +import { NativeStackHeaderRightProps } from '@react-navigation/native-stack'; import React from 'react'; import { IS_IOS } from '@/core/native/utils'; import { Image, Keyboard } from 'react-native'; @@ -18,7 +18,9 @@ const hitSlop = { }; /** @deprecated */ -export const CloudBackupButton2024: React.FC = ({}) => { +export const CloudBackupButton2024: React.FC< + NativeStackHeaderRightProps +> = ({}) => { const { shouldRedirectToSetPasswordBefore2024 } = useSetPasswordFirst(); const onPress = React.useCallback(() => { diff --git a/apps/mobile/src/screens/Address/ImportMoreAddressScreenButton.tsx b/apps/mobile/src/screens/Address/ImportMoreAddressScreenButton.tsx index 3a8d030b7f..2bfcf1a21f 100644 --- a/apps/mobile/src/screens/Address/ImportMoreAddressScreenButton.tsx +++ b/apps/mobile/src/screens/Address/ImportMoreAddressScreenButton.tsx @@ -5,7 +5,7 @@ import { } from '@/components/GlobalBottomSheetModal'; import { MODAL_NAMES } from '@/components/GlobalBottomSheetModal/types'; import { RcIconHeaderSettings } from '@/assets/icons/home'; -import { HeaderButtonProps } from '@react-navigation/native-stack/lib/typescript/src/types'; +import { NativeStackHeaderRightProps } from '@react-navigation/native-stack'; import { useRoute } from '@react-navigation/native'; import { GetNestedScreenRouteProp } from '@/navigation-type'; import { RootNames } from '@/constant/layout'; @@ -19,9 +19,9 @@ const hitSlop = { right: 10, }; -export const ImportMoreAddressScreenButton: React.FC = ({ - tintColor, -}) => { +export const ImportMoreAddressScreenButton: React.FC< + NativeStackHeaderRightProps +> = ({ tintColor }) => { const route = useRoute< GetNestedScreenRouteProp<'AddressNavigatorParamList', 'ImportMoreAddress'> diff --git a/apps/mobile/src/screens/BatchRevoke/BatchRevoke.tsx b/apps/mobile/src/screens/BatchRevoke/BatchRevoke.tsx index b19a3c5c7e..0912ffb5f5 100644 --- a/apps/mobile/src/screens/BatchRevoke/BatchRevoke.tsx +++ b/apps/mobile/src/screens/BatchRevoke/BatchRevoke.tsx @@ -2,12 +2,7 @@ import { FooterButtonContainer2024Props, FooterButtonScreenContainer, } from '@/components2024/ScreenContainer/FooterButtonScreenContainer'; -import { RootNames } from '@/constant/layout'; -import { TransactionNavigatorParamList } from '@/navigation-type'; -import { - UNSTABLE_usePreventRemove as usePreventRemove, - useRoute, -} from '@react-navigation/native'; +import { usePreventRemove, useRoute } from '@react-navigation/native'; import { GetNestedScreenRouteProp } from '@/navigation-type'; import React from 'react'; import { useTranslation } from 'react-i18next'; diff --git a/apps/mobile/src/screens/Bridge/components/BridgeHeader.tsx b/apps/mobile/src/screens/Bridge/components/BridgeHeader.tsx index 68a29dc52e..2dd10cd7cc 100644 --- a/apps/mobile/src/screens/Bridge/components/BridgeHeader.tsx +++ b/apps/mobile/src/screens/Bridge/components/BridgeHeader.tsx @@ -14,7 +14,8 @@ import { import TouchableView from '@/components/Touchable/TouchableView'; import { BridgeTxHistory } from './BridgeHistory'; import { RabbyFeePopup } from '@/components/RabbyFeePopup'; -import { Keyboard, TouchableOpacity, View } from 'react-native'; +import { Keyboard, View } from 'react-native'; +import { Pressable } from 'react-native-gesture-handler'; // import { RcIconSwapHistory } from '@/assets/icons/swap'; import RcIconSwapHistory from '@/assets2024/icons/common/IconHistoryCC.svg'; import { useTheme2024, useThemeColors } from '@/hooks/theme'; @@ -93,11 +94,11 @@ export const BridgeHeader = forwardRef< return ( <> - + {/* not very accurate */} {/* {Boolean(showRedDot) && } */} - + { }); } }}> - + @@ -262,6 +262,7 @@ const getStyle = createGetStyles2024(({ colors2024, isLight }) => { borderTopLeftRadius: 20, borderTopRightRadius: 20, overflow: 'hidden', + height: '100%', }, customHandleContainer: { position: 'absolute', diff --git a/apps/mobile/src/screens/CopyTrading/component/CopyTradingTokenDetail.tsx b/apps/mobile/src/screens/CopyTrading/component/CopyTradingTokenDetail.tsx index 911ff2439c..b2c519c734 100644 --- a/apps/mobile/src/screens/CopyTrading/component/CopyTradingTokenDetail.tsx +++ b/apps/mobile/src/screens/CopyTrading/component/CopyTradingTokenDetail.tsx @@ -20,6 +20,7 @@ import { Linking, ImageBackground, } from 'react-native'; +import { Pressable } from 'react-native-gesture-handler'; import { naviPush } from '@/utils/navigation'; import { RootNames } from '@/constant/layout'; import ImgTwitter from '@/assets2024/icons/copyTrading/ImgTwitter.png'; @@ -40,7 +41,7 @@ import { RcIconRightCC, RcIconSelectCC } from '@/assets/icons/common'; import { TokenInfo } from './TokenInfo'; import { SmartWallets } from './SmartWallets'; -import { SameNameTokens } from './SameNameTokens'; +import { SameNameTokens, TabType } from './SameNameTokens'; import { toast } from '@/components/Toast'; import { openapi } from '@/core/request'; import { removeAllGlobalBottomSheetModals2024 } from '@/components2024/GlobalBottomSheetModal'; @@ -57,12 +58,6 @@ import { useAccountInfo } from '@/screens/Address/components/MultiAssets/hooks'; import { useSwitchSceneCurrentAccount } from '@/hooks/accountsSwitcher'; import { isSameAddress } from '@rabby-wallet/base-utils/dist/isomorphic/address'; -export enum TabType { - tokenInfo = 'tokenInfo', - smartWallets = 'smartWallets', - sameNameTokens = 'sameNameTokens', -} - export default function CopyTradingTokenDetail() { const { t } = useTranslation(); const { styles, colors2024, isLight } = useTheme2024({ getStyle }); @@ -223,9 +218,7 @@ export default function CopyTradingTokenDetail() { const getHeaderRight = useCallback(() => { return ( - + {t('page.copyTrading.twitterNews')} @@ -235,7 +228,7 @@ export default function CopyTradingTokenDetail() { height={18} color={colors2024['neutral-title-1']} /> - + ); }, [styles, handleTwitterPress, t, colors2024]); diff --git a/apps/mobile/src/screens/CopyTrading/component/EarningDialog.tsx b/apps/mobile/src/screens/CopyTrading/component/EarningDialog.tsx index 1706569dcc..0077264293 100644 --- a/apps/mobile/src/screens/CopyTrading/component/EarningDialog.tsx +++ b/apps/mobile/src/screens/CopyTrading/component/EarningDialog.tsx @@ -30,7 +30,7 @@ import { removeGlobalBottomSheetModal2024, } from '@/components2024/GlobalBottomSheetModal'; import { MODAL_NAMES } from '@/components2024/GlobalBottomSheetModal/types'; -import { TabType } from './CopyTradingTokenDetail'; +import { TabType } from './SameNameTokens'; import { TokenItem } from '@rabby-wallet/rabby-api/dist/types'; import { useMemoizedFn } from 'ahooks'; import { QueryCopyTradingBuyItemResult } from '@/databases/entities/copyTradingBuyItem'; diff --git a/apps/mobile/src/screens/CopyTrading/component/SameNameTokens.tsx b/apps/mobile/src/screens/CopyTrading/component/SameNameTokens.tsx index 0d043cd523..5f2e40eeb0 100644 --- a/apps/mobile/src/screens/CopyTrading/component/SameNameTokens.tsx +++ b/apps/mobile/src/screens/CopyTrading/component/SameNameTokens.tsx @@ -29,7 +29,6 @@ import { createGlobalBottomSheetModal2024, removeGlobalBottomSheetModal2024, } from '@/components2024/GlobalBottomSheetModal'; -import { TabType } from './CopyTradingTokenDetail'; import { MODAL_NAMES } from '@/components2024/GlobalBottomSheetModal/types'; import { toast } from '@/components2024/Toast'; import { LoadingLinear } from '@/screens/TokenDetail/components/TokenPriceChart/LoadingLinear'; @@ -37,6 +36,12 @@ import { RootNames } from '@/constant/layout'; import { naviPush } from '@/utils/navigation'; import { chain } from 'lodash'; +export enum TabType { + tokenInfo = 'tokenInfo', + smartWallets = 'smartWallets', + sameNameTokens = 'sameNameTokens', +} + interface SameNameTokensProps { tradingTokenItem: TokenItem; updateSingleTokenPrice: ( diff --git a/apps/mobile/src/screens/CopyTrading/component/SmartWallets.tsx b/apps/mobile/src/screens/CopyTrading/component/SmartWallets.tsx index cfc9bceb3c..edfe1fb03f 100644 --- a/apps/mobile/src/screens/CopyTrading/component/SmartWallets.tsx +++ b/apps/mobile/src/screens/CopyTrading/component/SmartWallets.tsx @@ -400,7 +400,7 @@ export const SmartWallets: React.FC = ({ onEndReachedThreshold={0.3} ListFooterComponent={renderFooter} ListEmptyComponent={renderEmptyComponent} - removeClippedSubviews={true} + removeClippedSubviews={false} initialNumToRender={LIMIT} maxToRenderPerBatch={LIMIT} windowSize={10} diff --git a/apps/mobile/src/screens/CopyTrading/index.tsx b/apps/mobile/src/screens/CopyTrading/index.tsx index b24180c14e..f6f1e3347e 100644 --- a/apps/mobile/src/screens/CopyTrading/index.tsx +++ b/apps/mobile/src/screens/CopyTrading/index.tsx @@ -64,7 +64,7 @@ import { formatUsdValueKMBWithSign, } from '../Home/utils/price'; import { useProfit } from './component/useProfit'; -import { TabType } from './component/CopyTradingTokenDetail'; +import { TabType } from './component/SameNameTokens'; import { LoadingLinear } from '@/screens/TokenDetail/components/TokenPriceChart/LoadingLinear'; import { matomoRequestEvent } from '@/utils/analytics'; const DEFAULT_COUNT = 10; diff --git a/apps/mobile/src/screens/DeFiDetail/index.tsx b/apps/mobile/src/screens/DeFiDetail/index.tsx index 2768ba2257..66a52ef579 100644 --- a/apps/mobile/src/screens/DeFiDetail/index.tsx +++ b/apps/mobile/src/screens/DeFiDetail/index.tsx @@ -150,7 +150,7 @@ export const RightMore: React.FC<{ menuActions: menuActions, }} triggerProps={{ action: 'press' }}> - + @@ -242,6 +242,7 @@ export const DeFiDetailScreen = () => { const getHeaderLeft = useMemoizedFn(() => { return ( diff --git a/apps/mobile/src/screens/GasAccount/components/HeaderRight.tsx b/apps/mobile/src/screens/GasAccount/components/HeaderRight.tsx index cdb2f7b464..341013dde0 100644 --- a/apps/mobile/src/screens/GasAccount/components/HeaderRight.tsx +++ b/apps/mobile/src/screens/GasAccount/components/HeaderRight.tsx @@ -2,7 +2,7 @@ import { RcIconGasAccountHeaderRight } from '@/assets/icons/gas-account'; import { useGetBinaryMode, useTheme2024, useThemeColors } from '@/hooks/theme'; import { useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Pressable, Text, View } from 'react-native'; +import { Text, View } from 'react-native'; import { Tip } from '@/components'; import { CustomTouchableOpacity } from '@/components/CustomTouchableOpacity'; import { @@ -48,6 +48,7 @@ export const GasAccountHeader: React.FC = () => { content={ @@ -60,6 +61,7 @@ export const GasAccountHeader: React.FC = () => { @@ -71,7 +73,8 @@ export const GasAccountHeader: React.FC = () => { }> - setVisible(true)} hitSlop={10}> @@ -82,7 +85,7 @@ export const GasAccountHeader: React.FC = () => { style={styles.walletIcon} /> */} - + ); }; diff --git a/apps/mobile/src/screens/Home/HeaderArea.tsx b/apps/mobile/src/screens/Home/HeaderArea.tsx index 9bf67c96c0..f638e1e8ae 100644 --- a/apps/mobile/src/screens/Home/HeaderArea.tsx +++ b/apps/mobile/src/screens/Home/HeaderArea.tsx @@ -1,10 +1,10 @@ import React, { useCallback, useMemo } from 'react'; -import { TouchableOpacity, View } from 'react-native'; +import { View } from 'react-native'; import RcIconCopy from '@/assets2024/singleHome/copy.svg'; import { useTheme2024 } from '@/hooks/theme'; -import { createGetStyles2024 } from '@/utils/styles'; +import { createGetStyles2024, makeDebugBorder } from '@/utils/styles'; import { Text } from '@/components'; import { toastCopyAddressSuccess } from '@/components/AddressViewer/CopyAddress'; @@ -18,6 +18,7 @@ import { refreshingAtom } from './hooks/project'; import { useAtomValue } from 'jotai'; import LoadingCircle from '@/components2024/RotateLoadingCircle'; import { loadingCurveAtom } from '@/hooks/useCurve'; +import { TouchableOpacity } from 'react-native-gesture-handler'; export default function HomeHeaderArea({ account: currentAccount, @@ -36,8 +37,8 @@ export default function HomeHeaderArea({ const handleCopyAddress = useCallback< React.ComponentProps['onPress'] & object >( - evt => { - evt.stopPropagation(); + (evt?) => { + evt?.stopPropagation(); if (!currentAccount?.address) { return; } @@ -61,7 +62,7 @@ export default function HomeHeaderArea({ - + ({ container: { width: '100%', marginLeft: 8, + // ...makeDebugBorder('red'), }, innerBox: { width: '100%', @@ -109,6 +111,7 @@ const getStyles = createGetStyles2024(ctx => ({ justifyContent: 'center', alignItems: 'center', gap: 4, + // ...makeDebugBorder('yellow'), }, accountBox: { flexDirection: 'row', @@ -119,6 +122,7 @@ const getStyles = createGetStyles2024(ctx => ({ paddingRight: 4, paddingBottom: 4, overflow: 'visible', + // ...makeDebugBorder(), }, titleText: { flexShrink: 1, diff --git a/apps/mobile/src/screens/Home/Home.tsx b/apps/mobile/src/screens/Home/Home.tsx index 71dbcd7248..2a9e06d0ef 100644 --- a/apps/mobile/src/screens/Home/Home.tsx +++ b/apps/mobile/src/screens/Home/Home.tsx @@ -12,6 +12,7 @@ import { useHeaderHeight } from '@react-navigation/elements'; import { useRoute } from '@react-navigation/native'; import { GetNestedScreenRouteProp } from '@/navigation-type'; import { RightArea } from './SingleHomeRightArea'; +import { HomeNativeStackHeader } from './components/NativeStackHeader'; function HomeScreen(): JSX.Element { const { navigation, setNavigationOptions } = useSafeSetNavigationOptions(); @@ -68,14 +69,14 @@ function HomeScreen(): JSX.Element { React.useEffect(() => { setNavigationOptions({ + header: props => , headerTitle: renderHeaderTitle, headerRight: renderHeaderRight, }); }, [ - currentAccount.address, - navigation, - renderHeaderRight, + currentAccount, renderHeaderTitle, + renderHeaderRight, setNavigationOptions, ]); diff --git a/apps/mobile/src/screens/Home/SingleHomeRightArea.tsx b/apps/mobile/src/screens/Home/SingleHomeRightArea.tsx index 9dfd7032d2..1fd8e4117a 100644 --- a/apps/mobile/src/screens/Home/SingleHomeRightArea.tsx +++ b/apps/mobile/src/screens/Home/SingleHomeRightArea.tsx @@ -117,7 +117,10 @@ export const HeaderRightHistory: React.FC = ({ ]); return ( - + {pendingTxCount > 0 ? ( @@ -176,7 +179,10 @@ export const RightArea: React.FC<{ return ( <> - + diff --git a/apps/mobile/src/screens/Home/components/DappActions/index.tsx b/apps/mobile/src/screens/Home/components/DappActions/index.tsx index 5d42951ad4..029ed12f63 100644 --- a/apps/mobile/src/screens/Home/components/DappActions/index.tsx +++ b/apps/mobile/src/screens/Home/components/DappActions/index.tsx @@ -15,7 +15,7 @@ import { import { useTheme2024 } from '@/hooks/theme'; import { createGetStyles2024 } from '@/utils/styles'; import { useDappAction } from './hook'; -import { sendRequest } from '@/core/apis/provider'; +import { sendRequest } from '@/core/apis/sendRequest'; import { toast } from '@/components2024/Toast'; import { useMiniApproval } from '@/hooks/useMiniApproval'; import { DappActionHeader } from './DappActionHeader'; diff --git a/apps/mobile/src/screens/Home/components/NativeStackHeader.tsx b/apps/mobile/src/screens/Home/components/NativeStackHeader.tsx new file mode 100644 index 0000000000..150d61d845 --- /dev/null +++ b/apps/mobile/src/screens/Home/components/NativeStackHeader.tsx @@ -0,0 +1,105 @@ +// pick from file:///./../../../../node_modules/@react-navigation/native-stack/src/views/NativeStackView.tsx +// @see file:///./../../../../node_modules/@react-navigation/elements/src/Header/Header.tsx + +import { Image } from 'react-native'; +import { + Header, + getHeaderTitle, + HeaderBackButton, +} from '@react-navigation/elements'; +import { NativeStackHeaderProps } from '@react-navigation/native-stack'; +import { StyleSheet } from 'react-native'; +import { makeDebugBorder } from '@/utils/styles'; +import { useSafeAreaInsets } from 'react-native-safe-area-context'; + +export function HomeNativeStackHeader(props: NativeStackHeaderProps) { + const { options, navigation, route } = props; + + const canGoBack = true; + + const { + headerTintColor, + headerBackImageSource, + headerLeft, + headerRight, + headerTitle, + headerStyle, + headerShadowVisible, + headerTransparent, + headerBackTitle, + } = options; + + const insets = useSafeAreaInsets(); + + return ( +
+ headerLeft({ + ...rest, + label: headerBackTitle ?? label, + }) + : headerLeft === undefined && canGoBack + ? ({ tintColor, label, ...rest }) => ( + ( + + ) + : undefined + } + onPress={navigation.goBack} + /> + ) + : headerLeft + } + headerTitleContainerStyle={ + { + // ...makeDebugBorder('pink') + } + } + headerRight={ + typeof headerRight === 'function' + ? ({ tintColor }) => headerRight({ tintColor, canGoBack }) + : headerRight + } + headerRightContainerStyle={{ + paddingRight: 12, + }} + headerTitle={ + typeof headerTitle === 'function' + ? ({ children, tintColor }) => headerTitle({ children, tintColor }) + : headerTitle + } + headerTransparent={headerTransparent} + headerShadowVisible={headerShadowVisible} + headerStyle={[styles.header, headerStyle]} + /> + ); +} + +const styles = StyleSheet.create({ + header: {}, + backImage: { + height: 24, + width: 24, + margin: 3, + resizeMode: 'contain', + }, +}); diff --git a/apps/mobile/src/screens/Home/components/OfflineChainNotify.tsx b/apps/mobile/src/screens/Home/components/OfflineChainNotify.tsx index a7453cf820..69e2c64b7c 100644 --- a/apps/mobile/src/screens/Home/components/OfflineChainNotify.tsx +++ b/apps/mobile/src/screens/Home/components/OfflineChainNotify.tsx @@ -21,17 +21,9 @@ import { import { useMockDataForHomeCenterArea } from '@/screens/Settings/sheetModals/DevUIHomeCenterArea'; import { isNonPublicProductionEnv } from '@/constant/env'; -const closedTipsChainsAtom = atom(offlineChainService.getCloseTipsChains()); - -export const useMockClearOfflineChainTips = () => { - const [, setClosedTipsChain] = useAtom(closedTipsChainsAtom); - const clearOfflineChainTips = useCallback(() => { - offlineChainService.mockClearCloseTipsChains(); - setClosedTipsChain([]); - }, [setClosedTipsChain]); - - return { clearOfflineChainTips }; -}; +export const closedTipsChainsAtom = atom( + offlineChainService.getCloseTipsChains(), +); export const useOfflineChain = () => { const [closedTipsChains, _setClosedTipsChain] = useAtom(closedTipsChainsAtom); diff --git a/apps/mobile/src/screens/Navigators/AddressNavigator.tsx b/apps/mobile/src/screens/Navigators/AddressNavigator.tsx index e31a91d089..2462bc6142 100644 --- a/apps/mobile/src/screens/Navigators/AddressNavigator.tsx +++ b/apps/mobile/src/screens/Navigators/AddressNavigator.tsx @@ -217,7 +217,7 @@ export function AddressNavigator() { options={{ title: t('screens.addressStackTitle.ImportSuccess'), headerTintColor: colors2024['neutral-bg-1'], - statusBarColor: colors2024['neutral-bg-1'], + statusBarBackgroundColor: colors2024['neutral-bg-1'], }} /> { diff --git a/apps/mobile/src/screens/Send/SubScreens/SelectPolyScreen/HeaderRight.tsx b/apps/mobile/src/screens/Send/SubScreens/SelectPolyScreen/HeaderRight.tsx index c59816bfa9..942260d64d 100644 --- a/apps/mobile/src/screens/Send/SubScreens/SelectPolyScreen/HeaderRight.tsx +++ b/apps/mobile/src/screens/Send/SubScreens/SelectPolyScreen/HeaderRight.tsx @@ -1,13 +1,8 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useTheme2024 } from '@/hooks/theme'; import { createGetStyles2024 } from '@/utils/styles'; -import { - View, - StyleProp, - ViewStyle, - TouchableOpacity, - Keyboard, -} from 'react-native'; +import { View, StyleProp, ViewStyle, Keyboard } from 'react-native'; +import { Pressable } from 'react-native-gesture-handler'; import RcIconSwapHistory from '@/assets2024/icons/common/IconHistoryCC.svg'; import { SendHistory } from './SendHistory'; import PendingTx from '@/screens/Bridge/components/PendingTx'; @@ -16,7 +11,6 @@ import { useReadSendPendingCount, useReadSendSuccessTxList, } from '../../hooks/useSendPendingCount'; -import { useFocusEffect } from '@react-navigation/native'; interface IProps { isForMultipleAddress?: boolean; @@ -55,11 +49,11 @@ export const SendHeaderRight = ({ return ( <> - + {/* not very accurate */} {/* {Boolean(isShowDot) && } */} - + { const hash = resp as string; console.debug('hash', hash); diff --git a/apps/mobile/src/screens/Settings/Settings.tsx b/apps/mobile/src/screens/Settings/Settings.tsx index fde0cac6a0..0c4317d035 100644 --- a/apps/mobile/src/screens/Settings/Settings.tsx +++ b/apps/mobile/src/screens/Settings/Settings.tsx @@ -41,6 +41,7 @@ import { IS_HERMES_ENABLED, isNonPublicProductionEnv, isSelfhostRegPkg, + isTurboModuleEnabled, NEED_DEVSETTINGBLOCKS, } from '@/constant/env'; import { RootNames } from '@/constant/layout'; @@ -168,6 +169,7 @@ function AlertBuildInfo() { `Runtime Env: ${APP_RUNTIME_ENV}`, `Commit Hash: ${BUILD_GIT_INFO.BUILD_GIT_HASH}`, `Hermes Enabled: ${IS_HERMES_ENABLED}`, + `Turbo Module Enabled: ${isTurboModuleEnabled}`, ' ', !!BUILD_GIT_INFO.BUILD_GIT_HASH_TIME && `Lastest Commit: ${dayjs(BUILD_GIT_INFO.BUILD_GIT_HASH_TIME).format( @@ -191,6 +193,7 @@ function AlertBuildInfo() { `Runtime Env: ${APP_RUNTIME_ENV}`, `Revision: ${BUILD_GIT_INFO.BUILD_GIT_HASH}`, `Hermes Enabled: ${IS_HERMES_ENABLED}`, + `Turbo Module Enabled: ${isTurboModuleEnabled}`, ] .filter(Boolean) .join('\n'), diff --git a/apps/mobile/src/screens/Settings/sheetModals/DevUIHomeCenterArea.tsx b/apps/mobile/src/screens/Settings/sheetModals/DevUIHomeCenterArea.tsx index 76a5894334..9a876faeec 100644 --- a/apps/mobile/src/screens/Settings/sheetModals/DevUIHomeCenterArea.tsx +++ b/apps/mobile/src/screens/Settings/sheetModals/DevUIHomeCenterArea.tsx @@ -16,11 +16,22 @@ import { DevTestItem, makeNoop, GeneralTestItem } from './testDevUtils'; import { useMakeMockDataForRateGuideExposure } from '@/components/RateModal/hooks'; import { AppSwitch2024 } from '@/components/customized/Switch2024'; import { isNonPublicProductionEnv } from '@/constant/env'; -import { useMockClearOfflineChainTips } from '@/screens/Home/components/OfflineChainNotify'; import { FORCE_DISABLE_FEEDBACK_BY_SCREENSHOT, useViewedHomeTip, } from '@/components/Screenshot/hooks'; +import { closedTipsChainsAtom } from '@/screens/Home/components/OfflineChainNotify'; +import { offlineChainService } from '@/core/services'; + +export const useMockClearOfflineChainTips = () => { + const [, setClosedTipsChain] = useAtom(closedTipsChainsAtom); + const clearOfflineChainTips = useCallback(() => { + offlineChainService.mockClearCloseTipsChains(); + setClosedTipsChain([]); + }, [setClosedTipsChain]); + + return { clearOfflineChainTips }; +}; const MAKE_DEFAULT_MOCK_DATA = () => ({ forceShowFundWallet: false, diff --git a/apps/mobile/src/screens/Swap/hooks/swap.tsx b/apps/mobile/src/screens/Swap/hooks/swap.tsx index e60b53a019..866b21e1e9 100644 --- a/apps/mobile/src/screens/Swap/hooks/swap.tsx +++ b/apps/mobile/src/screens/Swap/hooks/swap.tsx @@ -11,7 +11,7 @@ import { swapService, transactionHistoryService, } from '@/core/services'; -import { sendRequest } from '@/core/apis/provider'; +import { sendRequest } from '@/core/apis/sendRequest'; import { navigationRef } from '@/utils/navigation'; import { StackActions } from '@react-navigation/native'; import { RootNames } from '@/constant/layout'; diff --git a/apps/mobile/src/screens/Transaction/MultiAddressHistory.tsx b/apps/mobile/src/screens/Transaction/MultiAddressHistory.tsx index 41077cedf1..4b52861581 100644 --- a/apps/mobile/src/screens/Transaction/MultiAddressHistory.tsx +++ b/apps/mobile/src/screens/Transaction/MultiAddressHistory.tsx @@ -55,7 +55,6 @@ import { useHistoryTokenDict } from '@/hooks/historyTokenDict'; import { TransactionAlert } from '../TransactionRecord/components/TransactionAlert'; import { ensureHistoryListItemFromDb, - fetchHistoryTokenItem, getHistoryItemType, judgeIsSmallUsdTx, } from './components/utils'; @@ -65,6 +64,7 @@ import { KEYRING_CLASS } from '@rabby-wallet/keyring-utils'; import { useTranslation } from 'react-i18next'; import { useAccountInfo } from '../Address/components/MultiAssets/hooks'; import { HistoryItemCateType } from './components/type'; +import { fetchHistoryTokenItem } from '@/utils/assets'; const _PAGE_COUNT = 200; const REALL_TIME_API_PAGE_COUNT = 20; diff --git a/apps/mobile/src/screens/Transaction/components/HistoryBottomBtn.tsx b/apps/mobile/src/screens/Transaction/components/HistoryBottomBtn.tsx index a8b0b088f3..1f3e130571 100644 --- a/apps/mobile/src/screens/Transaction/components/HistoryBottomBtn.tsx +++ b/apps/mobile/src/screens/Transaction/components/HistoryBottomBtn.tsx @@ -21,7 +21,6 @@ import { CHAINS_ENUM } from '@debank/common'; import { approveToken, revokeNFTApprove } from '@/core/apis/approvals'; import { resetNavigationTo } from '@/hooks/navigation'; import { HistoryDisplayItem } from '../MultiAddressHistory'; -import { fetchHistoryTokenUUId } from './utils'; import { useMyAccounts } from '@/hooks/account'; import { useSwitchSceneCurrentAccount } from '@/hooks/accountsSwitcher'; import { HistoryItemCateType } from './type'; diff --git a/apps/mobile/src/screens/Transaction/components/HistoryGroupList.tsx b/apps/mobile/src/screens/Transaction/components/HistoryGroupList.tsx index c2d52b903a..95914d9296 100644 --- a/apps/mobile/src/screens/Transaction/components/HistoryGroupList.tsx +++ b/apps/mobile/src/screens/Transaction/components/HistoryGroupList.tsx @@ -231,7 +231,7 @@ export const HistoryList = forwardRef( } onEndReached={loadMore} onEndReachedThreshold={0.5} - removeClippedSubviews={true} + removeClippedSubviews={false} ListFooterComponent={ loadingMore ? : } diff --git a/apps/mobile/src/screens/Transaction/components/HistoryItemTokenArea.tsx b/apps/mobile/src/screens/Transaction/components/HistoryItemTokenArea.tsx index 7fabbcf0ce..6592bb6162 100644 --- a/apps/mobile/src/screens/Transaction/components/HistoryItemTokenArea.tsx +++ b/apps/mobile/src/screens/Transaction/components/HistoryItemTokenArea.tsx @@ -12,7 +12,7 @@ import { useTheme2024 } from '@/hooks/theme'; import { createGetStyles2024 } from '@/utils/styles'; import { HistoryItemCateType } from './type'; import { TokenChangeDataItem } from './HistoryItem'; -import { isNFTTokenId } from './utils'; +import { isNFTTokenId } from '@/utils/assets'; interface ItemIconProps { type?: HistoryItemCateType | undefined; diff --git a/apps/mobile/src/screens/Transaction/components/HistoryTokenList.tsx b/apps/mobile/src/screens/Transaction/components/HistoryTokenList.tsx index 94e74b519b..808a5552d0 100644 --- a/apps/mobile/src/screens/Transaction/components/HistoryTokenList.tsx +++ b/apps/mobile/src/screens/Transaction/components/HistoryTokenList.tsx @@ -23,7 +23,6 @@ import { naviPush } from '@/utils/navigation'; import { RootNames } from '@/constant/layout'; import { ensureAbstractPortfolioToken } from '@/screens/Home/utils/token'; import { HistoryDisplayItem } from '../MultiAddressHistory'; -import { fetchHistoryTokenUUId } from './utils'; import { HistoryItemTokenPrice } from './HistoryItemTokenPrice'; import { ellipsisOverflowedText } from '@/utils/text'; import BuyWalletSVG from '@/assets2024/icons/swap/buy-wallet.svg'; diff --git a/apps/mobile/src/screens/Transaction/components/utils.ts b/apps/mobile/src/screens/Transaction/components/utils.ts index f6d1479716..c849af90eb 100644 --- a/apps/mobile/src/screens/Transaction/components/utils.ts +++ b/apps/mobile/src/screens/Transaction/components/utils.ts @@ -24,6 +24,7 @@ import { GAS_ACCOUNT_WITHDRAWED_ADDRESS, L2_DEPOSIT_ADDRESS_MAP, } from '@/constant/gas-account'; +import { fetchHistoryTokenUUId, isNFTTokenId } from '@/utils/assets'; export function getApproveTokeName(data: HistoryDisplayItem): string { const tokenId = data.token_approve?.token_id || ''; @@ -84,22 +85,6 @@ export function getHistoryItemType(data: TxHistoryItem): HistoryItemCateType { return HistoryItemCateType.UnKnown; } -export const fetchHistoryTokenUUId = ( - token_id: string, - chain: string, -): string => { - return `${chain}_token:${token_id}`; -}; - -export const fetchHistoryTokenItem = ( - token_id: string, - chain: string, - tokenDict: Record, -) => { - const tokenUUID = `${chain}_token:${token_id}`; - return tokenDict[tokenUUID] || tokenDict[token_id] || {}; -}; - export const ensureHistoryListItemFromDb = (item: HistoryItemEntity) => { return { ...item, @@ -253,10 +238,6 @@ export const loadTxSaveFromLocalStore = async (tx: TransactionHistoryItem) => { } }; -export const isNFTTokenId = (tokenId: string) => { - return tokenId.length === 32; -}; - export const txDonePatchTokenAmountInDb = async ( tx: TransactionHistoryItem, ) => { diff --git a/apps/mobile/src/screens/Unlock/Unlock.tsx b/apps/mobile/src/screens/Unlock/Unlock.tsx index 5787508261..708dd0d605 100644 --- a/apps/mobile/src/screens/Unlock/Unlock.tsx +++ b/apps/mobile/src/screens/Unlock/Unlock.tsx @@ -1,6 +1,11 @@ import { useTheme2024 } from '@/hooks/theme'; import { createGetStyles2024 } from '@/utils/styles'; -import React, { useCallback, useLayoutEffect, useState } from 'react'; +import React, { + useCallback, + useEffect, + useLayoutEffect, + useState, +} from 'react'; import { View, TextInput, @@ -8,6 +13,7 @@ import { ActivityIndicator, Keyboard, KeyboardAvoidingView, + Text, } from 'react-native'; import * as Yup from 'yup'; @@ -56,12 +62,24 @@ const prevFailedRef = { hide: null as (() => void) | null }; const toastFailed = toastWithIcon(RcIconInfoForToast); const toastBiometricsFailed = (message?: string) => { prevFailedRef.hide?.(); - prevFailedRef.hide = toastFailed(message); + prevFailedRef.hide = toastFailed(ctx => ( + + {message || 'Biometrics authentication failed'} + + )); }; const toastLoading = toastWithIcon(() => ( )); -const toastUnlocking = () => toastLoading('Unlocking', { duration: 3000 }); +const toastUnlocking = () => + toastLoading( + ctx => ( + + {'Unlocking'} + + ), + { duration: 3000 }, + ); export function BiometricsIcon(props: { isFaceID?: boolean; size?: number }) { const { isFaceID = isIOS, size = BiometricsIconSize } = props; @@ -101,6 +119,10 @@ function useUnlockForm(navigation: ReturnType) { const { tipEnableBiometrics } = useTipedUserEnableBiometrics(); + useEffect(() => { + toastUnlocking(); + }, []); + const formik = useFormik({ initialValues: INIT_DATA, validationSchema: yupSchema, diff --git a/apps/mobile/src/setup-app.ts b/apps/mobile/src/setup-app.ts index 11190b8576..c527f08308 100644 --- a/apps/mobile/src/setup-app.ts +++ b/apps/mobile/src/setup-app.ts @@ -9,6 +9,16 @@ import './databases/orm'; import './core/services'; import './core/utils/fonts'; import './core/config/online'; +import { FlatList } from 'react-native'; + +// @ts-expect-error +FlatList.defaultProps = Object.assign({}, FlatList.defaultProps, { + /** + * @see https://github.com/software-mansion/react-native-screens/issues/2339#issuecomment-2350979876 + * @see perf issue https://github.com/software-mansion/react-native-screens/issues/2339#issuecomment-3177692971 + */ + removeClippedSubviews: false, +}); setJSExceptionHandler((error, isFatal) => { console.debug('setJSExceptionHandler:: error'); diff --git a/apps/mobile/src/utils/CustomNativeStackNavigator.tsx b/apps/mobile/src/utils/CustomNativeStackNavigator.tsx index adf35d1225..efaeaee043 100644 --- a/apps/mobile/src/utils/CustomNativeStackNavigator.tsx +++ b/apps/mobile/src/utils/CustomNativeStackNavigator.tsx @@ -5,32 +5,43 @@ import 'react-native-gesture-handler'; */ import { createNavigatorFactory, - EventArg, - ParamListBase, - StackActionHelpers, + type EventArg, + type NavigatorTypeBagBase, + type ParamListBase, + type StackActionHelpers, StackActions, - StackNavigationState, - StackRouterOptions, + type StackNavigationState, + StackRouter, + type StackRouterOptions, + type StaticConfig, + type TypedNavigator, useNavigationBuilder, } from '@react-navigation/native'; -import { NativeStackView } from '@react-navigation/native-stack'; -import type { - NativeStackNavigationEventMap, - NativeStackNavigationOptions, - NativeStackNavigatorProps, -} from '@react-navigation/native-stack/lib/typescript/src/types'; import * as React from 'react'; import { CustomStackRouter } from './CustomStackRouter'; +import { + NativeStackView, + type NativeStackNavigationEventMap, + type NativeStackNavigationOptions, + type NativeStackNavigationProp, + type NativeStackNavigatorProps, +} from '@react-navigation/native-stack'; +// import { NativeStackView } from '../views/NativeStackView'; + function NativeStackNavigator({ + id, initialRouteName, children, + layout, screenListeners, screenOptions, + screenLayout, + UNSTABLE_router, ...rest }: NativeStackNavigatorProps) { - const { state, descriptors, navigation, NavigationContent } = + const { state, describe, descriptors, navigation, NavigationContent } = useNavigationBuilder< StackNavigationState, StackRouterOptions, @@ -38,15 +49,19 @@ function NativeStackNavigator({ NativeStackNavigationOptions, NativeStackNavigationEventMap >(CustomStackRouter, { + id, initialRouteName, children, + layout, screenListeners, screenOptions, + screenLayout, + UNSTABLE_router, }); React.useEffect( () => - // @ts-expect-error + // @ts-expect-error: there may not be a tab navigator in parent navigation?.addListener?.('tabPress', (e: any) => { const isFocused = navigation.isFocused(); @@ -77,16 +92,31 @@ function NativeStackNavigator({ state={state} navigation={navigation} descriptors={descriptors} + describe={describe} /> ); } -export const createCustomNativeStackNavigator = createNavigatorFactory< - StackNavigationState, - NativeStackNavigationOptions, - NativeStackNavigationEventMap, - typeof NativeStackNavigator ->(NativeStackNavigator); - -export default createCustomNativeStackNavigator; +export function createCustomNativeStackNavigator< + const ParamList extends ParamListBase, + const NavigatorID extends string | undefined = undefined, + const TypeBag extends NavigatorTypeBagBase = { + ParamList: ParamList; + NavigatorID: NavigatorID; + State: StackNavigationState; + ScreenOptions: NativeStackNavigationOptions; + EventMap: NativeStackNavigationEventMap; + NavigationList: { + [RouteName in keyof ParamList]: NativeStackNavigationProp< + ParamList, + RouteName, + NavigatorID + >; + }; + Navigator: typeof NativeStackNavigator; + }, + const Config extends StaticConfig = StaticConfig, +>(config?: Config): TypedNavigator { + return createNavigatorFactory(NativeStackNavigator)(config); +} diff --git a/apps/mobile/src/utils/CustomStackRouter.tsx b/apps/mobile/src/utils/CustomStackRouter.tsx index 7a5c72918c..dc8e4d063b 100644 --- a/apps/mobile/src/utils/CustomStackRouter.tsx +++ b/apps/mobile/src/utils/CustomStackRouter.tsx @@ -1,4 +1,7 @@ -// https://github.com/react-navigation/react-navigation/blob/b2fa62c8ea5c5ad40a3541a7258cba62467e7a56/packages/routers/src/StackRouter.tsx +/** + * @see https://github.com/react-navigation/react-navigation/blob/%40react-navigation/routers%407.5.1/packages/routers/src/StackRouter.tsx + * @see file:///./../../node_modules/@react-navigation/routers/src/StackRouter.tsx + */ import { StackRouter, StackRouterOptions } from '@react-navigation/native'; diff --git a/apps/mobile/src/utils/account.ts b/apps/mobile/src/utils/account.ts index 1bc78c0f9f..684d318e06 100644 --- a/apps/mobile/src/utils/account.ts +++ b/apps/mobile/src/utils/account.ts @@ -7,6 +7,23 @@ import { } from '@rabby-wallet/keyring-utils/src/types'; import BigNumber from 'bignumber.js'; +export type SceneAccount = Account & { + isPinned?: boolean; +}; + +export function isSameAccount( + account: Account, + saccount?: SceneAccount | null, +) { + if (!saccount) return false; + + return ( + saccount?.address?.toLowerCase() === account.address.toLowerCase() && + saccount?.brandName === account.brandName && + saccount?.type === account.type + ); +} + export function findAccountByPriority(accounts: KeyringAccountWithAlias[]) { const priority = { [KEYRING_TYPE.HdKeyring]: 1, diff --git a/apps/mobile/src/utils/analytics.ts b/apps/mobile/src/utils/analytics.ts index 3a160378bc..5ee2feea90 100644 --- a/apps/mobile/src/utils/analytics.ts +++ b/apps/mobile/src/utils/analytics.ts @@ -1,5 +1,5 @@ import { BUILD_CHANNEL } from '@/constant/env'; -import { preferenceService } from '@/core/services'; +import { type PreferenceService } from '@/core/services/preference'; import firebaseAnalytics from '@react-native-firebase/analytics'; export const analytics = firebaseAnalytics(); @@ -10,6 +10,11 @@ import { Platform } from 'react-native'; const ANALYTICS_PATH = 'https://matomo.debank.com/matomo.php'; const genExtensionId = customAlphabet('1234567890abcdef', 16); +const preferenceServiceRef = { current: null as PreferenceService | null }; +export function setPreferenceServiceRef(service: PreferenceService) { + preferenceServiceRef.current = service; +} + async function postData(url = '', params: URLSearchParams) { const response = await fetch(`${url}?${params.toString()}`, { method: 'POST', @@ -18,10 +23,12 @@ async function postData(url = '', params: URLSearchParams) { return response; } -let extensionId = preferenceService.getPreference('extensionId') as string; +let extensionId = preferenceServiceRef.current?.getPreference( + 'extensionId', +) as string; if (!extensionId) { extensionId = genExtensionId(); - preferenceService.setPreference({ extensionId }); + preferenceServiceRef.current?.setPreference({ extensionId }); } const getParams = async () => { diff --git a/apps/mobile/src/utils/assets.ts b/apps/mobile/src/utils/assets.ts new file mode 100644 index 0000000000..f424035434 --- /dev/null +++ b/apps/mobile/src/utils/assets.ts @@ -0,0 +1,21 @@ +import { TokenItem } from '@rabby-wallet/rabby-api/dist/types'; + +export const isNFTTokenId = (tokenId: string) => { + return tokenId.length === 32; +}; + +export const fetchHistoryTokenUUId = ( + token_id: string, + chain: string, +): string => { + return `${chain}_token:${token_id}`; +}; + +export const fetchHistoryTokenItem = ( + token_id: string, + chain: string, + tokenDict: Record, +) => { + const tokenUUID = `${chain}_token:${token_id}`; + return tokenDict[tokenUUID] || tokenDict[token_id] || {}; +}; diff --git a/apps/mobile/src/utils/errorTxRetry.ts b/apps/mobile/src/utils/errorTxRetry.ts index 90c03be6a1..fdac95758a 100644 --- a/apps/mobile/src/utils/errorTxRetry.ts +++ b/apps/mobile/src/utils/errorTxRetry.ts @@ -3,9 +3,6 @@ import { Account } from '@/core/services/preference'; import { t } from 'i18next'; import { hexToNumber, isHex } from 'viem'; import { intToHex } from './number'; -import { useEffect } from 'react'; -import { isSelfhostRegPkg } from '@/constant/env'; -import { toast } from '@/components/Toast'; export type RetryUpdateType = 'nonce' | 'gasPrice' | 'origin' | false; diff --git a/package.json b/package.json index 06df88a189..10309f9581 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,6 @@ "react-native-animateable-text@0.14.2": "patch:react-native-animateable-text@npm%3A0.14.2#./.yarn/patches/react-native-animateable-text-npm-0.14.2-9dfa5fe6c7.patch", "react-native-fs@^2.20.0": "patch:react-native-fs@npm%3A2.20.0#./.yarn/patches/react-native-fs-npm-2.20.0-a38fe24051.patch", "react-native-keychain@8.0.0": "patch:react-native-keychain@npm%3A8.0.0#./.yarn/patches/react-native-keychain-npm-8.0.0-22c1f5c020.patch", - "react-native-mmkv@^2.12.2": "patch:react-native-mmkv@npm%3A2.12.2#./.yarn/patches/react-native-mmkv-npm-2.12.2-9efa7abf70.patch", "react-native-quick-crypto@0.7.13": "patch:react-native-quick-crypto@npm%3A0.7.13#./.yarn/patches/react-native-quick-crypto-npm-0.7.13-2726ada4c8.patch", "react-native-reanimated@^3.6.1": "patch:react-native-reanimated@npm%3A3.6.1#./.yarn/patches/react-native-reanimated-npm-3.6.1-68d8b4ad7e.patch", "react-native-webview@13.10.5": "patch:react-native-webview@npm%3A13.10.5#./.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch", @@ -83,7 +82,9 @@ "@scure/bip39@1.2.1": "patch:@scure/bip39@npm%3A1.3.0#./.yarn/patches/@scure-bip39-npm-1.3.0-1d74c5c469.patch", "@scure/bip39@1.3.0": "patch:@scure/bip39@npm%3A1.3.0#./.yarn/patches/@scure-bip39-npm-1.3.0-1d74c5c469.patch", "@scure/bip39@^1.4.0": "patch:@scure/bip39@npm%3A1.3.0#./.yarn/patches/@scure-bip39-npm-1.3.0-1d74c5c469.patch", - "@scure/bip39@^1.2.1": "patch:@scure/bip39@npm%3A1.3.0#./.yarn/patches/@scure-bip39-npm-1.3.0-1d74c5c469.patch" + "@scure/bip39@^1.2.1": "patch:@scure/bip39@npm%3A1.3.0#./.yarn/patches/@scure-bip39-npm-1.3.0-1d74c5c469.patch", + "react-native-reanimated@3.17.1": "patch:react-native-reanimated@npm%3A3.17.1#./.yarn/patches/react-native-reanimated-npm-3.17.1-c34570df61.patch", + "@gorhom/bottom-sheet@5.1.8": "patch:@gorhom/bottom-sheet@npm%3A5.1.8#./.yarn/patches/@gorhom-bottom-sheet-npm-5.1.8-d4532753f1.patch" }, "dependencies": { "@babel/runtime": "^7.20.0", diff --git a/yarn.lock b/yarn.lock index d88d2a155e..b5dfdbc434 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5853,6 +5853,534 @@ __metadata: languageName: node linkType: hard +"@firebase/analytics-compat@npm:0.2.14": + version: 0.2.14 + resolution: "@firebase/analytics-compat@npm:0.2.14" + dependencies: + "@firebase/analytics": 0.10.8 + "@firebase/analytics-types": 0.8.2 + "@firebase/component": 0.6.9 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 9b594ab16a9f2f6cc5130b1c5d3837f24523903f63643f604fe5897daf3d8cc8af89109d17f1354d6f02797c0781fd7141ac0aa3971a8e8b3cfb0c3d9a945daa + languageName: node + linkType: hard + +"@firebase/analytics-types@npm:0.8.2": + version: 0.8.2 + resolution: "@firebase/analytics-types@npm:0.8.2" + checksum: a8279b070b8a2496b596a18111bc51488d2e6e4b7d6cd46cbe4406a61693254c2dbd0c7d0dec77a0016a4277cde7978fd61c711bcb15ea578b33b2a5b9aba46a + languageName: node + linkType: hard + +"@firebase/analytics@npm:0.10.8": + version: 0.10.8 + resolution: "@firebase/analytics@npm:0.10.8" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/installations": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + checksum: 04170135a4457e0c5571fccf0d11be7ccdaa591840364b10d0c21edaea06e0c23b90bfbc10589a730be6511cb129c7fe79aa4ff7f44c953d7b39fd4fcf0dc7d2 + languageName: node + linkType: hard + +"@firebase/app-check-compat@npm:0.3.15": + version: 0.3.15 + resolution: "@firebase/app-check-compat@npm:0.3.15" + dependencies: + "@firebase/app-check": 0.8.8 + "@firebase/app-check-types": 0.5.2 + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: dcbe62cd516a8b70784c4e55ccb16614db0966402c20896c48f4e42ec29e91b9722bf1f6a28eac6186483ac9d65f77b5291a522932da05d2927dc7cad26a1a1a + languageName: node + linkType: hard + +"@firebase/app-check-interop-types@npm:0.3.2": + version: 0.3.2 + resolution: "@firebase/app-check-interop-types@npm:0.3.2" + checksum: 7dd452c21cb8b3682082a6f4023de208b4a4808d97ede7d72a54f2e0a51963adf1c1bcc8a8c8338bee1ba0b66516cc101a1fb51a26a80c9322c3a080aee6ec26 + languageName: node + linkType: hard + +"@firebase/app-check-types@npm:0.5.2": + version: 0.5.2 + resolution: "@firebase/app-check-types@npm:0.5.2" + checksum: d0ab668274475bdb33a5f7164a9a380e46c21b3405cb46072895386f896953461e113119bd1b2eb63abd14fc9cf249f2f80e87adbbb9bc7ef7564967955cc200 + languageName: node + linkType: hard + +"@firebase/app-check@npm:0.8.8": + version: 0.8.8 + resolution: "@firebase/app-check@npm:0.8.8" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + checksum: 6a27316f49e15ed5925dd40a8c217712119dc21c83c0032bac9f2ee3e3de713546c51451831c47eeec77734e639ec8b2fb24fd41a0efe27a5913fe2ca83503f7 + languageName: node + linkType: hard + +"@firebase/app-compat@npm:0.2.41": + version: 0.2.41 + resolution: "@firebase/app-compat@npm:0.2.41" + dependencies: + "@firebase/app": 0.10.11 + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + checksum: eef1490eda88ffbc2e5e041591f2d587e6056e64e3fe1b899be4cbf061ad98ab1c3dc09605a35cdc178ff72e4a49588b1035aca6e6035d5dbd96d0fea590ba8c + languageName: node + linkType: hard + +"@firebase/app-types@npm:0.9.2": + version: 0.9.2 + resolution: "@firebase/app-types@npm:0.9.2" + checksum: c709592d84e262b980cbeff4fd5f5d5c522a9de7fe33bcdede8e6390fc05a283c11a2bf0b012fef1329251d4599f12f4b4f0dd2228a8ec42da017ae968e740a4 + languageName: node + linkType: hard + +"@firebase/app@npm:0.10.11": + version: 0.10.11 + resolution: "@firebase/app@npm:0.10.11" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + idb: 7.1.1 + tslib: ^2.1.0 + checksum: 62f8dabbb349292165fb0847d3923e2974a803ca7756c5c22ec17ba8bb5a864d5594bd41c7733b88e38b525b7eae838d80042e9dd71200e08daada44b998714d + languageName: node + linkType: hard + +"@firebase/auth-compat@npm:0.5.14": + version: 0.5.14 + resolution: "@firebase/auth-compat@npm:0.5.14" + dependencies: + "@firebase/auth": 1.7.9 + "@firebase/auth-types": 0.12.2 + "@firebase/component": 0.6.9 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + undici: 6.19.7 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: a2adecd67abc436dea97d268f3478150612b60581b58d4d547ed8a29f760a2a60abd95da85437d3fe2a4124d6f0f9ecfbf14cd65bb6f19d63b2a99ec5e839e3e + languageName: node + linkType: hard + +"@firebase/auth-interop-types@npm:0.2.3": + version: 0.2.3 + resolution: "@firebase/auth-interop-types@npm:0.2.3" + checksum: fdadd64a067fdc1f32464890c861cdcc984a4aae307e7d46f182ba508082e55921c6f70042d1f893dfd18434484783f866adefcdc01dba8818cd7f0b0c89acf2 + languageName: node + linkType: hard + +"@firebase/auth-types@npm:0.12.2": + version: 0.12.2 + resolution: "@firebase/auth-types@npm:0.12.2" + peerDependencies: + "@firebase/app-types": 0.x + "@firebase/util": 1.x + checksum: d4bbe222b22bbd213d2e6dc8af9e196b39eb29e55c4aecf4d81d232dc105ae895c587e56e37363e5192c56b1db157c3b18c9378a907d1672e6124c4cd793a04d + languageName: node + linkType: hard + +"@firebase/auth@npm:1.7.9": + version: 1.7.9 + resolution: "@firebase/auth@npm:1.7.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + undici: 6.19.7 + peerDependencies: + "@firebase/app": 0.x + "@react-native-async-storage/async-storage": ^1.18.1 + peerDependenciesMeta: + "@react-native-async-storage/async-storage": + optional: true + checksum: f6ce5151dae619ed18dc2e205e3d6c17280a7f05fa0b6416b3dbb8d75c694c9feefaf8b30bca3d3a01ebaafd8865d6fb8b38fe46b5c23ec998278a834a1976a9 + languageName: node + linkType: hard + +"@firebase/component@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/component@npm:0.6.9" + dependencies: + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + checksum: f047109220b08eb1ff3509563c597c62bfef98c0190c4201a1c98de755931a7d3783c1de083888f600336a92865fc3f75d211467963191eaa86453d13b9ac704 + languageName: node + linkType: hard + +"@firebase/database-compat@npm:1.0.8": + version: 1.0.8 + resolution: "@firebase/database-compat@npm:1.0.8" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/database": 1.0.8 + "@firebase/database-types": 1.0.5 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + checksum: 68ea4e07a9aba636173b838fa0126310c1d4d7cee3bb64bccca5681d28515f9eb78d34ed1d8aef82de0891717b8e5e29c794d4deeed7bd7fd479eab16f00194a + languageName: node + linkType: hard + +"@firebase/database-types@npm:1.0.5": + version: 1.0.5 + resolution: "@firebase/database-types@npm:1.0.5" + dependencies: + "@firebase/app-types": 0.9.2 + "@firebase/util": 1.10.0 + checksum: 8c8c45162b6f138378f8aa16590cfad52233e0e93c35b5e6dc526ef06ee2b424e80023ab9defea4fef8f6886c9aeced8386bcf532c59008a1d2b620df90c5779 + languageName: node + linkType: hard + +"@firebase/database@npm:1.0.8": + version: 1.0.8 + resolution: "@firebase/database@npm:1.0.8" + dependencies: + "@firebase/app-check-interop-types": 0.3.2 + "@firebase/auth-interop-types": 0.2.3 + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + faye-websocket: 0.11.4 + tslib: ^2.1.0 + checksum: a12d7985ceabfe71fe4fb657c2b87904082f54cce5ce9b3c1399c1fdf0ee7ab89091a328448f99e628e636ee4f8ed30378bce864a32a8881203992a8ba023c8d + languageName: node + linkType: hard + +"@firebase/firestore-compat@npm:0.3.37": + version: 0.3.37 + resolution: "@firebase/firestore-compat@npm:0.3.37" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/firestore": 4.7.2 + "@firebase/firestore-types": 3.0.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: d23b1d67efbce88f566eef01e61583b9682e696972643a43c9359e1d29dc4713d7f9b3c9e458a15b759867df705ef86844d95abfc1d48505b36bf1124fcec1a0 + languageName: node + linkType: hard + +"@firebase/firestore-types@npm:3.0.2": + version: 3.0.2 + resolution: "@firebase/firestore-types@npm:3.0.2" + peerDependencies: + "@firebase/app-types": 0.x + "@firebase/util": 1.x + checksum: b275107a2d65aecb1fe66d44feac4d74f8bd48f309bdfe53e6c84e5ba4787fae0700d8d045b07939cbc7c3c7c19935d1ca8efab9eda4f5f8ad50e3ee330b90ca + languageName: node + linkType: hard + +"@firebase/firestore@npm:4.7.2": + version: 4.7.2 + resolution: "@firebase/firestore@npm:4.7.2" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + "@firebase/webchannel-wrapper": 1.0.1 + "@grpc/grpc-js": ~1.9.0 + "@grpc/proto-loader": ^0.7.8 + tslib: ^2.1.0 + undici: 6.19.7 + peerDependencies: + "@firebase/app": 0.x + checksum: 79973e621e70a5c4f799e9ab41618cc3309584e32a1b9fe1da14dcc80ad6b055001963382346b5994c64f700595637be11034d534de796c1b314685df1bc4adb + languageName: node + linkType: hard + +"@firebase/functions-compat@npm:0.3.14": + version: 0.3.14 + resolution: "@firebase/functions-compat@npm:0.3.14" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/functions": 0.11.8 + "@firebase/functions-types": 0.6.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 577c4c877a267587fe81628ea03ee9507c73b6b5ab7c52cfa67b6e6e7e45725aa017f16307e223a3a9f495a2df2ef1c3a76c6455f50adb6bf7e85d649ed9d4e8 + languageName: node + linkType: hard + +"@firebase/functions-types@npm:0.6.2": + version: 0.6.2 + resolution: "@firebase/functions-types@npm:0.6.2" + checksum: 7973e0de0b709295e7e885929ff10d35dec5a1d92c0f827f9580abc3860d4ccfebf7af69bbbceabc9b62eb88642028a6373a14b5f7be388fa40211e64c5147fb + languageName: node + linkType: hard + +"@firebase/functions@npm:0.11.8": + version: 0.11.8 + resolution: "@firebase/functions@npm:0.11.8" + dependencies: + "@firebase/app-check-interop-types": 0.3.2 + "@firebase/auth-interop-types": 0.2.3 + "@firebase/component": 0.6.9 + "@firebase/messaging-interop-types": 0.2.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + undici: 6.19.7 + peerDependencies: + "@firebase/app": 0.x + checksum: 69b71d68bbfb7148878bb276594553f0da8e7d60dd05353e5ee90ec06ab0524526a2d8e412f6392ae3545740a58b7d99166a63af7023fc6b0ce555ddac174050 + languageName: node + linkType: hard + +"@firebase/installations-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/installations-compat@npm:0.2.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/installations": 0.6.9 + "@firebase/installations-types": 0.5.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 2af49d1c18791b740803e3a95a4192c00067fd97e922bb0f9bf3b494df97a9d9f3c94956242942308a3fb454021ef92412dbb92023b05c21f561b1cd022aeea4 + languageName: node + linkType: hard + +"@firebase/installations-types@npm:0.5.2": + version: 0.5.2 + resolution: "@firebase/installations-types@npm:0.5.2" + peerDependencies: + "@firebase/app-types": 0.x + checksum: 19f31ab2982198ffed0cf0e57307bcf17dbc994f6ec707f508c151108b09a67472728f2ee744548bf079b458a982ac865d2fd6d6879fc7d16a7b7dbfa7263fa8 + languageName: node + linkType: hard + +"@firebase/installations@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/installations@npm:0.6.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/util": 1.10.0 + idb: 7.1.1 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + checksum: d769a96e30eb781bf826f140f859627878142a7f5a2f9c501b1fa21026b0e0c0c9037c4cc95fcfea03555cb12d62d960f7fb951175c424ce50d9fce37a26a333 + languageName: node + linkType: hard + +"@firebase/logger@npm:0.4.2": + version: 0.4.2 + resolution: "@firebase/logger@npm:0.4.2" + dependencies: + tslib: ^2.1.0 + checksum: a0d288debe32108095af691fa8797c5ee2023b0f4e0f5024992f7e49b5353d1fb0280ea950d8bfd5d93af514cf839f663fd3559303d0591fcb8b0efe3d879f0e + languageName: node + linkType: hard + +"@firebase/messaging-compat@npm:0.2.11": + version: 0.2.11 + resolution: "@firebase/messaging-compat@npm:0.2.11" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/messaging": 0.12.11 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: f7cb460e26d284df9bb9727192801d763708d70a11175228d97578898b6fe76e2da3d49db50ca4aea9bc0e5b2275a0b50c1286c4f5164785b87453b1ce4d3af6 + languageName: node + linkType: hard + +"@firebase/messaging-interop-types@npm:0.2.2": + version: 0.2.2 + resolution: "@firebase/messaging-interop-types@npm:0.2.2" + checksum: 75dc6c7d3951866145e2706562cc38d98de0d8c23a08c04b41c5641e89da424f85af4606294f1430de3c191be6c74cf7e2be55bab810720f70ba4c2f20297dbb + languageName: node + linkType: hard + +"@firebase/messaging@npm:0.12.11": + version: 0.12.11 + resolution: "@firebase/messaging@npm:0.12.11" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/installations": 0.6.9 + "@firebase/messaging-interop-types": 0.2.2 + "@firebase/util": 1.10.0 + idb: 7.1.1 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + checksum: 90230086f8ae5b953c91fbfa37ce5f750e132af0591cf7ce18bcf254c042fa004ee50302f8aa2332b05bd328dfff88f180223fc898672a80ca83ab22bba2d715 + languageName: node + linkType: hard + +"@firebase/performance-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/performance-compat@npm:0.2.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/performance": 0.6.9 + "@firebase/performance-types": 0.2.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 790e30300234ed81a018d3ef661ef571fb86287ea6587e44664059e3f3e6edf8664e542bc92c2ab2092d38547517ddcd5f4dd0e0b3c67c1f4829a0f8ddb52af5 + languageName: node + linkType: hard + +"@firebase/performance-types@npm:0.2.2": + version: 0.2.2 + resolution: "@firebase/performance-types@npm:0.2.2" + checksum: ff4c6b445629ba30a182e476d9ec0c1640a4fdf258716ebfe98573196d8ca67000d588846cf7f17d2e2144315b55146a70a6b0b184e7a05c446eb18cf0b6b8e3 + languageName: node + linkType: hard + +"@firebase/performance@npm:0.6.9": + version: 0.6.9 + resolution: "@firebase/performance@npm:0.6.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/installations": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + checksum: 4c839db0ccd7c67bbf7ade2f5df54e4922cb2907306787d17710ad49b407c4cbfac5e04ce264e66b0051f03a8139abfbdf11014402ce28c78e7facf9ac0e5820 + languageName: node + linkType: hard + +"@firebase/remote-config-compat@npm:0.2.9": + version: 0.2.9 + resolution: "@firebase/remote-config-compat@npm:0.2.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/remote-config": 0.4.9 + "@firebase/remote-config-types": 0.3.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: 32001792b53cdbe8a353deaf8dc5b7571641a46a45cb102dbf4bbfab1cdab5fc9683d63eddc40fb1a14b18619ba74efc08013799db3fe73d868e4dccd981a1c3 + languageName: node + linkType: hard + +"@firebase/remote-config-types@npm:0.3.2": + version: 0.3.2 + resolution: "@firebase/remote-config-types@npm:0.3.2" + checksum: 15dfab0febb7eb382ba1d702b677a72d11f9a98379464a9047349b844c36edb572ba7f353681ad65ece3cd9bee387a945c0939b13ae5c5f221fa264671152adc + languageName: node + linkType: hard + +"@firebase/remote-config@npm:0.4.9": + version: 0.4.9 + resolution: "@firebase/remote-config@npm:0.4.9" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/installations": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + checksum: 0113a3ed2227273684bd3b7249ba2e8707e734b02292b97044e7cf89fe36ff6c830673fd7afc315eebd9b45b731551db9f72a0a58df792bee6e902320860d0a6 + languageName: node + linkType: hard + +"@firebase/storage-compat@npm:0.3.12": + version: 0.3.12 + resolution: "@firebase/storage-compat@npm:0.3.12" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/storage": 0.13.2 + "@firebase/storage-types": 0.8.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app-compat": 0.x + checksum: daa8418fdde22e4dbe532f04a079669630650a86167cfdaa06c74b54a53c9d71b834fd5e4bc3eb735f1223d1b866d77de937d1eccb486e4c83e208fcefd3a64b + languageName: node + linkType: hard + +"@firebase/storage-types@npm:0.8.2": + version: 0.8.2 + resolution: "@firebase/storage-types@npm:0.8.2" + peerDependencies: + "@firebase/app-types": 0.x + "@firebase/util": 1.x + checksum: c992f49cc5d326a096e2ec350464c2b0934fc7259c6616e11279bc970db980545d46d150a8edcaa48d028d6fed2ee28c25ff4d5c3ade46ec48c96444d7e11198 + languageName: node + linkType: hard + +"@firebase/storage@npm:0.13.2": + version: 0.13.2 + resolution: "@firebase/storage@npm:0.13.2" + dependencies: + "@firebase/component": 0.6.9 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + undici: 6.19.7 + peerDependencies: + "@firebase/app": 0.x + checksum: d7112f3771b9145fc5e70fe8cfbe7dc9e6a1b9fb41cd6d1ce7a330a8af316f5c507cf2e707175a96b954f50e21353eb691c6bc16e3317436946353333cdd9005 + languageName: node + linkType: hard + +"@firebase/util@npm:1.10.0": + version: 1.10.0 + resolution: "@firebase/util@npm:1.10.0" + dependencies: + tslib: ^2.1.0 + checksum: 3fb8f0e58145f10bf2de0497c89293cf76bcb79d440b818466f8e1e272e4051e04926443c611f930f862af00e174bd49dc9f0b2513ba1719263a5297d4837709 + languageName: node + linkType: hard + +"@firebase/vertexai-preview@npm:0.0.4": + version: 0.0.4 + resolution: "@firebase/vertexai-preview@npm:0.0.4" + dependencies: + "@firebase/app-check-interop-types": 0.3.2 + "@firebase/component": 0.6.9 + "@firebase/logger": 0.4.2 + "@firebase/util": 1.10.0 + tslib: ^2.1.0 + peerDependencies: + "@firebase/app": 0.x + "@firebase/app-types": 0.x + checksum: bd46147ecc404d20662c0839dd2cfe855f415f9513755a795d642cbaad88ccb50f7fdbed08a879c58dae9f4df57e9dd7328141129a2e8e80c4b5a0b66723b68a + languageName: node + linkType: hard + +"@firebase/webchannel-wrapper@npm:1.0.1": + version: 1.0.1 + resolution: "@firebase/webchannel-wrapper@npm:1.0.1" + checksum: 4e12cf7866d9ceeaa7cab49b31dd5559a3ec5626137679f52598935720893022de6feac0bfd5c911886c0c0059c04dab58a000d8fd2612da266ca09a1f4412cb + languageName: node + linkType: hard + "@fivebinaries/coin-selection@npm:3.0.0": version: 3.0.0 resolution: "@fivebinaries/coin-selection@npm:3.0.0" @@ -5934,9 +6462,9 @@ __metadata: languageName: node linkType: hard -"@gorhom/bottom-sheet@npm:5.0.0-alpha.9": - version: 5.0.0-alpha.9 - resolution: "@gorhom/bottom-sheet@npm:5.0.0-alpha.9" +"@gorhom/bottom-sheet@npm:5.1.8": + version: 5.1.8 + resolution: "@gorhom/bottom-sheet@npm:5.1.8" dependencies: "@gorhom/portal": 1.0.14 invariant: ^2.2.4 @@ -5945,14 +6473,36 @@ __metadata: "@types/react-native": "*" react: "*" react-native: "*" - react-native-gesture-handler: ">=2.14.0" - react-native-reanimated: ">=3.6.0" + react-native-gesture-handler: ">=2.16.1" + react-native-reanimated: "*" peerDependenciesMeta: "@types/react": optional: true "@types/react-native": optional: true - checksum: edabc33ca86aff35c28030d639ac66f732a9300caebe522a1cb5baf8db8332814e65ffa5fc0ddefeb83d8ec8f4596f052ce53e5b6e43b1b5499f05044218a708 + checksum: de450ace52d8a4fac9faed0a900ae455f90289114e06c96c8378ba192102a8795a29f614245b450c4e2a29dbe2b93c2ccaaa39cb6a14561f200ea4dd2e372621 + languageName: node + linkType: hard + +"@gorhom/bottom-sheet@patch:@gorhom/bottom-sheet@npm%3A5.1.8#./.yarn/patches/@gorhom-bottom-sheet-npm-5.1.8-d4532753f1.patch::locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A.": + version: 5.1.8 + resolution: "@gorhom/bottom-sheet@patch:@gorhom/bottom-sheet@npm%3A5.1.8#./.yarn/patches/@gorhom-bottom-sheet-npm-5.1.8-d4532753f1.patch::version=5.1.8&hash=87b6f9&locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A." + dependencies: + "@gorhom/portal": 1.0.14 + invariant: ^2.2.4 + peerDependencies: + "@types/react": "*" + "@types/react-native": "*" + react: "*" + react-native: "*" + react-native-gesture-handler: ">=2.16.1" + react-native-reanimated: "*" + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-native": + optional: true + checksum: 12c3230cf4c9c6c11ebd7ed0edd3bbf2194f69406dd5040907b11e897b67ae36180b40a3ad82ebb1f82900f0b7591bdb56734538c4a55d9cf8fea8c2724dda46 languageName: node linkType: hard @@ -5968,6 +6518,30 @@ __metadata: languageName: node linkType: hard +"@grpc/grpc-js@npm:~1.9.0": + version: 1.9.15 + resolution: "@grpc/grpc-js@npm:1.9.15" + dependencies: + "@grpc/proto-loader": ^0.7.8 + "@types/node": ">=12.12.47" + checksum: 5b0f84052ad6610fff7919cae99c79c1182b01d2f529f6e64e1189e902a90abcb6f828a119df8e4abcdab8fa1ac5d5975fe200220293a1ced126c536f3bc1374 + languageName: node + linkType: hard + +"@grpc/proto-loader@npm:^0.7.8": + version: 0.7.15 + resolution: "@grpc/proto-loader@npm:0.7.15" + dependencies: + lodash.camelcase: ^4.3.0 + long: ^5.0.0 + protobufjs: ^7.2.5 + yargs: ^17.7.2 + bin: + proto-loader-gen-types: build/bin/proto-loader-gen-types.js + checksum: 9f19f4c611a17cd33aec0d6e3686a76696495f40593f7c284933c4b7877f58dfa5a225ddc20705860a632311f4dc0d143cb6a0da7b51b6f5ffd7de26938df308 + languageName: node + linkType: hard + "@hapi/hoek@npm:^9.0.0, @hapi/hoek@npm:^9.3.0": version: 9.3.0 resolution: "@hapi/hoek@npm:9.3.0" @@ -9719,20 +10293,20 @@ __metadata: languageName: node linkType: hard -"@react-native-firebase/analytics@npm:18.8.0": - version: 18.8.0 - resolution: "@react-native-firebase/analytics@npm:18.8.0" +"@react-native-firebase/analytics@npm:21.3.0": + version: 21.3.0 + resolution: "@react-native-firebase/analytics@npm:21.3.0" peerDependencies: - "@react-native-firebase/app": 18.8.0 - checksum: 2a01308982226e8873278e4719189083cf61563dd20d41e20b514061e96220ba7c55aa87c8fb82442b4eab8d07ba7ae7588cbbd1f942d2694a1bdc63648729ae + "@react-native-firebase/app": 21.3.0 + checksum: 5ce34d7a11019e9be615f4a4e70500ed95542f5aed2602056c627fb28bccfa8e16147ed3bc1a1faf1fdcb6b4886a18f4e493a3e4c7fb0187da8ea6eaf40edce6 languageName: node linkType: hard -"@react-native-firebase/app@npm:18.8.0": - version: 18.8.0 - resolution: "@react-native-firebase/app@npm:18.8.0" +"@react-native-firebase/app@npm:21.3.0": + version: 21.3.0 + resolution: "@react-native-firebase/app@npm:21.3.0" dependencies: - opencollective-postinstall: ^2.0.3 + firebase: 10.13.2 superstruct: ^0.6.2 peerDependencies: expo: ">=47.0.0" @@ -9741,7 +10315,7 @@ __metadata: peerDependenciesMeta: expo: optional: true - checksum: 10b4e5aec0dd18a690bc2ba07fe95f0d414f2904574dda930efd050b113629469d2c01e1d849b129ce575e84bbf89b53ffbeee55c51716c4a78e36be463c1fff + checksum: 1119aaad49780fc4171d12bbbdefb20667c698f34a56367feb37cc41d98ddb775289b37aef665cf9d46aa39bb0636c3f93ccd724eab5241776319c3a8547513b languageName: node linkType: hard @@ -10030,88 +10604,97 @@ __metadata: languageName: node linkType: hard -"@react-navigation/bottom-tabs@npm:^6.5.11": - version: 6.6.1 - resolution: "@react-navigation/bottom-tabs@npm:6.6.1" +"@react-navigation/bottom-tabs@npm:7.4.7": + version: 7.4.7 + resolution: "@react-navigation/bottom-tabs@npm:7.4.7" dependencies: - "@react-navigation/elements": ^1.3.31 + "@react-navigation/elements": ^2.6.4 color: ^4.2.3 - warn-once: ^0.1.0 peerDependencies: - "@react-navigation/native": ^6.0.0 - react: "*" + "@react-navigation/native": ^7.1.17 + react: ">= 18.2.0" react-native: "*" - react-native-safe-area-context: ">= 3.0.0" - react-native-screens: ">= 3.0.0" - checksum: 07d6da4b91d7f372b67bcb9f1ff97fba96f1fe226bd95d43d7877362ce71d99c6eebe9ca41d84ea8828f055713386262e089a8207a6c849f33bae49b4df4b196 + react-native-safe-area-context: ">= 4.0.0" + react-native-screens: ">= 4.0.0" + checksum: 9ff291b086b00d4f656d67fd29b084c7d801c68e8db41c3b18192076d9593e6d4c9d4d28d1bde12be71c0499b6af83331cbe348549c15ff5fa5f8daf42c6bae3 languageName: node linkType: hard -"@react-navigation/core@npm:^6.4.17": - version: 6.4.17 - resolution: "@react-navigation/core@npm:6.4.17" +"@react-navigation/core@npm:^7.12.4": + version: 7.12.4 + resolution: "@react-navigation/core@npm:7.12.4" dependencies: - "@react-navigation/routers": ^6.1.9 + "@react-navigation/routers": ^7.5.1 escape-string-regexp: ^4.0.0 - nanoid: ^3.1.23 + nanoid: ^3.3.11 query-string: ^7.1.3 - react-is: ^16.13.0 - use-latest-callback: ^0.2.1 + react-is: ^19.1.0 + use-latest-callback: ^0.2.4 + use-sync-external-store: ^1.5.0 peerDependencies: - react: "*" - checksum: 5e7315bb6ebff8e796eaccb0442d00696466750cc387e93f5edb5293d4ad3f409c1525ef76192894488e2d0979b762b236a1b0fbbb7500b2f065bf4745d509c0 + react: ">= 18.2.0" + checksum: 84eb6d003d09c271e9e5e8f34c4a440447a82d81df7bd2f87dc4d56f851a5c74b1ec6e488cc2702cf16fde7d33bb55a58fe1dbd14e6cbdd513583b33227c2471 languageName: node linkType: hard -"@react-navigation/elements@npm:^1.3.31": - version: 1.3.31 - resolution: "@react-navigation/elements@npm:1.3.31" +"@react-navigation/elements@npm:^2.6.4": + version: 2.6.4 + resolution: "@react-navigation/elements@npm:2.6.4" + dependencies: + color: ^4.2.3 + use-latest-callback: ^0.2.4 + use-sync-external-store: ^1.5.0 peerDependencies: - "@react-navigation/native": ^6.0.0 - react: "*" + "@react-native-masked-view/masked-view": ">= 0.2.0" + "@react-navigation/native": ^7.1.17 + react: ">= 18.2.0" react-native: "*" - react-native-safe-area-context: ">= 3.0.0" - checksum: 1e4a65ccd9fab757d01bf41f605aafd6ca8301ae25ad7d3f1769320793418cca9fe2f25ac9337578ce1e0a1560bbbc3a88f18b899867aacd4d31de7a789e417e + react-native-safe-area-context: ">= 4.0.0" + peerDependenciesMeta: + "@react-native-masked-view/masked-view": + optional: true + checksum: 5ebcf77ca85755efbc35983a32caf6f82371bd8ca7ba705deb4317c250a9a9c1898765d02fe2373adfb2aae852666ac54f07b9185bf1a91fbfe185920ac9c46d languageName: node linkType: hard -"@react-navigation/native-stack@npm:^6.9.17": - version: 6.11.0 - resolution: "@react-navigation/native-stack@npm:6.11.0" +"@react-navigation/native-stack@npm:7.3.26": + version: 7.3.26 + resolution: "@react-navigation/native-stack@npm:7.3.26" dependencies: - "@react-navigation/elements": ^1.3.31 - warn-once: ^0.1.0 + "@react-navigation/elements": ^2.6.4 + warn-once: ^0.1.1 peerDependencies: - "@react-navigation/native": ^6.0.0 - react: "*" + "@react-navigation/native": ^7.1.17 + react: ">= 18.2.0" react-native: "*" - react-native-safe-area-context: ">= 3.0.0" - react-native-screens: ">= 3.0.0" - checksum: d3dd57c216f5dbe53636bdb9aa48fe27831640f868cf5c68731943a49b68cb457d81182e7868f3e3033da0564e9f193f1b06b69085b8bc5b04ccfbe12ea2bbc0 + react-native-safe-area-context: ">= 4.0.0" + react-native-screens: ">= 4.0.0" + checksum: 81146d65c73f731bb40a5df35aa31047077869e9ace2131f6f061795e965892be16dd82bae6c8c7510eee772afe0e1c1374a526663b0e0f0c578effff0c5ef8b languageName: node linkType: hard -"@react-navigation/native@npm:^6.1.9": - version: 6.1.18 - resolution: "@react-navigation/native@npm:6.1.18" +"@react-navigation/native@npm:7.1.17": + version: 7.1.17 + resolution: "@react-navigation/native@npm:7.1.17" dependencies: - "@react-navigation/core": ^6.4.17 + "@react-navigation/core": ^7.12.4 escape-string-regexp: ^4.0.0 fast-deep-equal: ^3.1.3 - nanoid: ^3.1.23 + nanoid: ^3.3.11 + use-latest-callback: ^0.2.4 peerDependencies: - react: "*" + react: ">= 18.2.0" react-native: "*" - checksum: 82aeea67723f5dc41403e1c260f04942696f6cde95e30629c383521c3837d18d2d5c21bd78f0ade50beb81ac5edca2d7d38980dcd3a79e3acc86f45d0c09a4b8 + checksum: f0caa70f777c32861ce23a834d3afe6891c7829016649bf1491ba6b540fd4443dd6c5e6d8b44f58b92efed6074ea986e04b88ff84e9e19c09d68d9302ebd977a languageName: node linkType: hard -"@react-navigation/routers@npm:^6.1.9": - version: 6.1.9 - resolution: "@react-navigation/routers@npm:6.1.9::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2F%40react-navigation%2Frouters%2F-%2Frouters-6.1.9.tgz" +"@react-navigation/routers@npm:^7.5.1": + version: 7.5.1 + resolution: "@react-navigation/routers@npm:7.5.1" dependencies: - nanoid: ^3.1.23 - checksum: 3a3392ce095d6a2bd2aad69856f513b35774f943a3dc73d8ffb75127de6773203e3264188d87058bdea4c0c9a7d43ed28d0cbf3a1f1cdc086df3ee255d8e1e27 + nanoid: ^3.3.11 + checksum: 49f04894f7e8b8e2c16abb96bbc1a9775a02341bb00fb9c0d9ce97f8d82613c27570921f2b854f8fd1639c29309df05345aa734124d48bdbcb5a934055b8af12 languageName: node linkType: hard @@ -13051,6 +13634,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:>=12.12.47": + version: 24.6.2 + resolution: "@types/node@npm:24.6.2" + dependencies: + undici-types: ~7.13.0 + checksum: 95766998060f005403a1aea198c2c472fd1d695cb9e7cebb62adb0e3aceb871ae1201e90577df31a7c1d6a2c2fadccbd9a9868f9014cb77ebd3232104de8f4fb + languageName: node + linkType: hard + "@types/node@npm:>=13.7.0": version: 20.11.30 resolution: "@types/node@npm:20.11.30" @@ -22464,6 +23056,15 @@ __metadata: languageName: node linkType: hard +"faye-websocket@npm:0.11.4": + version: 0.11.4 + resolution: "faye-websocket@npm:0.11.4" + dependencies: + websocket-driver: ">=0.5.1" + checksum: d49a62caf027f871149fc2b3f3c7104dc6d62744277eb6f9f36e2d5714e847d846b9f7f0d0b7169b25a012e24a594cde11a93034b30732e4c683f20b8a5019fa + languageName: node + linkType: hard + "faye-websocket@npm:^0.11.3": version: 0.11.4 resolution: "faye-websocket@npm:0.11.4::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Ffaye-websocket%2F-%2Ffaye-websocket-0.11.4.tgz" @@ -22759,6 +23360,41 @@ __metadata: languageName: node linkType: hard +"firebase@npm:10.13.2": + version: 10.13.2 + resolution: "firebase@npm:10.13.2" + dependencies: + "@firebase/analytics": 0.10.8 + "@firebase/analytics-compat": 0.2.14 + "@firebase/app": 0.10.11 + "@firebase/app-check": 0.8.8 + "@firebase/app-check-compat": 0.3.15 + "@firebase/app-compat": 0.2.41 + "@firebase/app-types": 0.9.2 + "@firebase/auth": 1.7.9 + "@firebase/auth-compat": 0.5.14 + "@firebase/database": 1.0.8 + "@firebase/database-compat": 1.0.8 + "@firebase/firestore": 4.7.2 + "@firebase/firestore-compat": 0.3.37 + "@firebase/functions": 0.11.8 + "@firebase/functions-compat": 0.3.14 + "@firebase/installations": 0.6.9 + "@firebase/installations-compat": 0.2.9 + "@firebase/messaging": 0.12.11 + "@firebase/messaging-compat": 0.2.11 + "@firebase/performance": 0.6.9 + "@firebase/performance-compat": 0.2.9 + "@firebase/remote-config": 0.4.9 + "@firebase/remote-config-compat": 0.2.9 + "@firebase/storage": 0.13.2 + "@firebase/storage-compat": 0.3.12 + "@firebase/util": 1.10.0 + "@firebase/vertexai-preview": 0.0.4 + checksum: 5778ab880f845e1bfdf03282f1d5e024efa7ae18cec95cb5f416092da3eabc5b6f7b4f6377466987b842e42d434c111f7a49633b17d0db95504e6c743d4401f9 + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.2.0 resolution: "flat-cache@npm:3.2.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fflat-cache%2F-%2Fflat-cache-3.2.0.tgz" @@ -24357,6 +24993,13 @@ __metadata: languageName: node linkType: hard +"idb@npm:7.1.1": + version: 7.1.1 + resolution: "idb@npm:7.1.1" + checksum: 1973c28d53c784b177bdef9f527ec89ec239ec7cf5fcbd987dae75a16c03f5b7dfcc8c6d3285716fd0309dd57739805390bd9f98ce23b1b7d8849a3b52de8d56 + languageName: node + linkType: hard + "idb@npm:^7.0.1": version: 7.1.1 resolution: "idb@npm:7.1.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fidb%2F-%2Fidb-7.1.1.tgz" @@ -28133,6 +28776,13 @@ __metadata: languageName: node linkType: hard +"lodash.camelcase@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.camelcase@npm:4.3.0" + checksum: cb9227612f71b83e42de93eccf1232feeb25e705bdb19ba26c04f91e885bfd3dd5c517c4a97137658190581d3493ea3973072ca010aab7e301046d90740393d1 + languageName: node + linkType: hard + "lodash.clonedeep@npm:^4.5.0": version: 4.5.0 resolution: "lodash.clonedeep@npm:4.5.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Flodash.clonedeep%2F-%2Flodash.clonedeep-4.5.0.tgz" @@ -29655,7 +30305,7 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23, nanoid@npm:^3.3.1, nanoid@npm:^3.3.6, nanoid@npm:^3.3.7": +"nanoid@npm:^3.3.1, nanoid@npm:^3.3.6, nanoid@npm:^3.3.7": version: 3.3.7 resolution: "nanoid@npm:3.3.7::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fnanoid%2F-%2Fnanoid-3.3.7.tgz" bin: @@ -32529,6 +33179,26 @@ __metadata: languageName: node linkType: hard +"protobufjs@npm:^7.2.5": + version: 7.5.4 + resolution: "protobufjs@npm:7.5.4" + dependencies: + "@protobufjs/aspromise": ^1.1.2 + "@protobufjs/base64": ^1.1.2 + "@protobufjs/codegen": ^2.0.4 + "@protobufjs/eventemitter": ^1.1.0 + "@protobufjs/fetch": ^1.1.0 + "@protobufjs/float": ^1.0.2 + "@protobufjs/inquire": ^1.1.0 + "@protobufjs/path": ^1.1.2 + "@protobufjs/pool": ^1.1.0 + "@protobufjs/utf8": ^1.1.0 + "@types/node": ">=13.7.0" + long: ^5.0.0 + checksum: 53bf83b9a726b05d43da35bb990dba7536759787dccea9a67b8f31be9df470ba17f1f1b982ca19956cfc7726f3ec7e0e883ca4ad93b5ec753cc025a637fc704f + languageName: node + linkType: hard + "proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fproxy-addr%2F-%2Fproxy-addr-2.0.7.tgz" @@ -32792,7 +33462,7 @@ __metadata: "@ethereumjs/common": 4.2.0 "@ethereumjs/tx": 5.1.0 "@ethereumjs/util": ^9.0.1 - "@gorhom/bottom-sheet": 5.0.0-alpha.9 + "@gorhom/bottom-sheet": 5.1.8 "@ledgerhq/react-native-hw-transport-ble": 6.33.4 "@metamask/abi-utils": 3.0.0 "@metamask/browser-passworder": 6.0.0 @@ -32827,17 +33497,17 @@ __metadata: "@react-native-community/eslint-config": ^3.2.0 "@react-native-community/hooks": 100.1.0 "@react-native-community/netinfo": 11.4.1 - "@react-native-firebase/analytics": 18.8.0 - "@react-native-firebase/app": 18.8.0 + "@react-native-firebase/analytics": 21.3.0 + "@react-native-firebase/app": 21.3.0 "@react-native-google-signin/google-signin": 13.2.0 "@react-native-masked-view/masked-view": ^0.3.1 "@react-native-menu/menu": 1.2.3 "@react-native/babel-preset": 0.76.9 "@react-native/eslint-config": 0.76.9 "@react-native/metro-config": 0.76.9 - "@react-navigation/bottom-tabs": ^6.5.11 - "@react-navigation/native": ^6.1.9 - "@react-navigation/native-stack": ^6.9.17 + "@react-navigation/bottom-tabs": 7.4.7 + "@react-navigation/native": 7.1.17 + "@react-navigation/native-stack": 7.3.26 "@rematch/core": ^2.2.0 "@rneui/base": ^4.0.0-rc.8 "@rneui/themed": ^4.0.0-rc.8 @@ -32917,7 +33587,7 @@ __metadata: react-native-bundle-splitter: ^3.0.1 react-native-bundle-visualizer: 3.1.0 react-native-cloud-storage: ^1.4.1 - react-native-collapsible-tab-view: ^6.2.1 + react-native-collapsible-tab-view: 7.0.1 react-native-crypto-js: ^1.0.0 react-native-device-info: 14.0.4 react-native-dotenv: ^3.4.9 @@ -32937,8 +33607,8 @@ __metadata: react-native-keychain: 8.0.0 react-native-linear-gradient: ^2.8.3 react-native-localize: 3.3.0 - react-native-mmkv: ^2.12.2 - react-native-pager-view: 6.7.0 + react-native-mmkv: 3.3.1 + react-native-pager-view: 6.9.0 react-native-permissions: 5.3.0 react-native-qrcode-svg: ^6.2.0 react-native-quick-crypto: 0.7.13 @@ -32957,7 +33627,7 @@ __metadata: react-native-version: ^4.0.0 react-native-version-check: ^3.4.7 react-native-video: 6.12.0 - react-native-view-shot: 3.7.0 + react-native-view-shot: 4.0.3 react-native-vision-camera: 4.6.4 react-native-wagmi-charts: ^2.3.2 react-native-walkthrough-tooltip: ^1.5.0 @@ -33320,7 +33990,7 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^16.13.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0": +"react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Freact-is%2F-%2Freact-is-16.13.1.tgz" checksum: f7a19ac3496de32ca9ae12aa030f00f14a3d45374f1ceca0af707c831b2a6098ef0d6bdae51bd437b0a306d7f01d4677fcc8de7c0d331eb47ad0f46130e53c5f @@ -33348,6 +34018,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^19.1.0": + version: 19.2.0 + resolution: "react-is@npm:19.2.0" + checksum: 9a23e1c2d0bbc13b383bc59a05f54e6eb95dd87e01aec8aa92a88618364b7b0ee8a5b057ad813cf61e2f7ae7d24503b624706acb609d07c54754e5ad2c522568 + languageName: node + linkType: hard + "react-keyed-flatten-children@npm:^1.3.0": version: 1.3.0 resolution: "react-keyed-flatten-children@npm:1.3.0" @@ -33503,9 +34180,9 @@ __metadata: languageName: node linkType: hard -"react-native-collapsible-tab-view@npm:^6.2.1": - version: 6.2.1 - resolution: "react-native-collapsible-tab-view@npm:6.2.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Freact-native-collapsible-tab-view%2F-%2Freact-native-collapsible-tab-view-6.2.1.tgz" +"react-native-collapsible-tab-view@npm:7.0.1": + version: 7.0.1 + resolution: "react-native-collapsible-tab-view@npm:7.0.1" dependencies: use-deep-compare: ^1.1.0 peerDependencies: @@ -33513,11 +34190,11 @@ __metadata: react: "*" react-native: "*" react-native-pager-view: "*" - react-native-reanimated: ">=2.15.0" + react-native-reanimated: ">=3.8.1" peerDependenciesMeta: "@shopify/flash-list": optional: true - checksum: 759a4af59bf70c28c0a5e3a25e4eaf864a510757dd4affc0071f141e77f73cb19ea35c450a5090858e4bfa7ebcd77d5ce4982feadcd9ab75dde2e34ead23c451 + checksum: 17f7fcdd14550534a29cec6509ea5442c76db9542fb5494451f3d5d22cfbca049efc18bd75d066b3345f335afe082a81efc1aa9faafea385ca0ecf567d477854 languageName: node linkType: hard @@ -33816,33 +34493,23 @@ __metadata: languageName: node linkType: hard -"react-native-mmkv@npm:2.12.2": - version: 2.12.2 - resolution: "react-native-mmkv@npm:2.12.2" - peerDependencies: - react: "*" - react-native: ">=0.71.0" - checksum: 8c79504a89fefd7f9c290a4a6bb24f1f9ef9e2a69d20d0f7d882b89f3943556e9c919c9d46583e44ab698f25213489277fccb6d4c856cce310267c5f907388f1 - languageName: node - linkType: hard - -"react-native-mmkv@patch:react-native-mmkv@npm%3A2.12.2#./.yarn/patches/react-native-mmkv-npm-2.12.2-9efa7abf70.patch::locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A.": - version: 2.12.2 - resolution: "react-native-mmkv@patch:react-native-mmkv@npm%3A2.12.2#./.yarn/patches/react-native-mmkv-npm-2.12.2-9efa7abf70.patch::version=2.12.2&hash=ba2359&locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A." +"react-native-mmkv@npm:3.3.1": + version: 3.3.1 + resolution: "react-native-mmkv@npm:3.3.1" peerDependencies: react: "*" - react-native: ">=0.71.0" - checksum: 1710fb8e1befa9c79c53b16b7b2095322a4ac609ee7fad44877f4e4034935d3c4f3620147b0c7922af7380ffa1bd60d4ce03deb084c6663d1c6b2a16030368dd + react-native: "*" + checksum: c8d54895b1f27a2b023547858bf6e913f90399ffb6780cdd902efdcd93bbd7ddc031c9004313f7227f56837571b3c7faccc49236ea160f24e97e8434737c6d17 languageName: node linkType: hard -"react-native-pager-view@npm:6.7.0": - version: 6.7.0 - resolution: "react-native-pager-view@npm:6.7.0" +"react-native-pager-view@npm:6.9.0": + version: 6.9.0 + resolution: "react-native-pager-view@npm:6.9.0" peerDependencies: react: "*" react-native: "*" - checksum: dab79d98cd9186df8cb6ce62f00d1255490d8ba70bda68709d3adcf7fde5d72f66efcaa5c787c8d1291605e251912862e903f19d6dac2c02479a341c17625597 + checksum: ae2b170e8950d6dd8360c83f0c761a07d9981c4014e55872153a201280da0484e26d28f32185843d6398b4487e09eb202dd25769405503cd632a070662948e3b languageName: node linkType: hard @@ -33958,6 +34625,30 @@ __metadata: languageName: node linkType: hard +"react-native-reanimated@patch:react-native-reanimated@npm%3A3.17.1#./.yarn/patches/react-native-reanimated-npm-3.17.1-c34570df61.patch::locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A.": + version: 3.17.1 + resolution: "react-native-reanimated@patch:react-native-reanimated@npm%3A3.17.1#./.yarn/patches/react-native-reanimated-npm-3.17.1-c34570df61.patch::version=3.17.1&hash=de45a5&locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A." + dependencies: + "@babel/plugin-transform-arrow-functions": ^7.0.0-0 + "@babel/plugin-transform-class-properties": ^7.0.0-0 + "@babel/plugin-transform-classes": ^7.0.0-0 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.0.0-0 + "@babel/plugin-transform-optional-chaining": ^7.0.0-0 + "@babel/plugin-transform-shorthand-properties": ^7.0.0-0 + "@babel/plugin-transform-template-literals": ^7.0.0-0 + "@babel/plugin-transform-unicode-regex": ^7.0.0-0 + "@babel/preset-typescript": ^7.16.7 + convert-source-map: ^2.0.0 + invariant: ^2.2.4 + react-native-is-edge-to-edge: 1.1.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + react: "*" + react-native: "*" + checksum: e64ff07bca00e8340771bdd11ef93ea5b6ebcc34ab4a59fec430c5cc0e21463ead3c4b0676867d3fb9decb84b98a0d9489c08ec5d6e05d68bda4540a4f289740 + languageName: node + linkType: hard + "react-native-redash@npm:^16.1.1": version: 16.3.0 resolution: "react-native-redash@npm:16.3.0" @@ -34157,15 +34848,15 @@ __metadata: languageName: node linkType: hard -"react-native-view-shot@npm:3.7.0": - version: 3.7.0 - resolution: "react-native-view-shot@npm:3.7.0" +"react-native-view-shot@npm:4.0.3": + version: 4.0.3 + resolution: "react-native-view-shot@npm:4.0.3" dependencies: html2canvas: ^1.4.1 peerDependencies: react: "*" react-native: "*" - checksum: e7fd583c98f17e8911cfe8a208df4f4798bf70edf500dd71ee405552e64387fd48374abdf16a965a4a768a308f6a0e2e5b75ae710fdeaa975baef146f8cec6dc + checksum: d795849b5e2d1c75f66675aea073dae7d109b2b0a266d54f8c0ac8b30d4516dd83a5a7494fd2c44adf0e6e7286d3c29e9b025dbea3536332bf7165715f8a97de languageName: node linkType: hard @@ -34236,14 +34927,14 @@ __metadata: "react-native-webview@patch:react-native-webview@npm%3A13.10.5#./.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch::locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A.": version: 13.10.5 - resolution: "react-native-webview@patch:react-native-webview@npm%3A13.10.5#./.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch::version=13.10.5&hash=07550e&locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A." + resolution: "react-native-webview@patch:react-native-webview@npm%3A13.10.5#./.yarn/patches/react-native-webview-npm-13.10.5-714eb41569.patch::version=13.10.5&hash=207eba&locator=%40rabby-wallet%2Fmobile-monorepo%40workspace%3A." dependencies: escape-string-regexp: 2.0.0 invariant: 2.2.4 peerDependencies: react: "*" react-native: "*" - checksum: 451749d3241dd7d0f9132f2a0c610cdc19383c68c5b46c64b4fc0de33032883972457858ce31ad16b982b9e684444e454527ceb85eb0bb66023825ff1e8541e3 + checksum: c20a8bdc24dfd0295516354ed706fbc92137e7519739a58a82be05022cabe77f62caf6705ea12ebc916e29b37f9f2bc82a668c251e6576829787980221665681 languageName: node linkType: hard @@ -39193,6 +39884,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.13.0": + version: 7.13.0 + resolution: "undici-types@npm:7.13.0" + checksum: fcb3e1195a36615fce3935eb97c21ebe4dbafe968f831ed00e6f22e8e73c0655b8e3242acc6ba4ff0f3c34e3f3f860f19fbb59c00b261bd4e20b515abbc2de7c + languageName: node + linkType: hard + "undici-types@npm:~7.8.0": version: 7.8.0 resolution: "undici-types@npm:7.8.0" @@ -39200,6 +39898,13 @@ __metadata: languageName: node linkType: hard +"undici@npm:6.19.7": + version: 6.19.7 + resolution: "undici@npm:6.19.7" + checksum: ccf7f311cc2f7109e03c433190cb13d45c581905a70674992b0d8469c36ec1ae011824f41ba0c4a85b9771e4dd30a94228315c316215f76fafcb8e3b91ffbc22 + languageName: node + linkType: hard + "unicode-canonical-property-names-ecmascript@npm:^2.0.0": version: 2.0.0 resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Funicode-canonical-property-names-ecmascript%2F-%2Funicode-canonical-property-names-ecmascript-2.0.0.tgz" @@ -39569,12 +40274,12 @@ __metadata: languageName: node linkType: hard -"use-latest-callback@npm:^0.2.1": - version: 0.2.3 - resolution: "use-latest-callback@npm:0.2.3" +"use-latest-callback@npm:^0.2.4": + version: 0.2.4 + resolution: "use-latest-callback@npm:0.2.4" peerDependencies: react: ">=16.8" - checksum: 5db2dc0d414508c768ba4d1a337bd73dd0fb2a77eccc9dd7051517b28cd71c849c5e9230b5c97fc76a3811c1500f210cb4e4ebb95fe20347e5f910509a8e533c + checksum: 60c3a6b1b6567e1794f9e48cd86b8cde8a149485cc2fed60570f69ec3b157f6812e0ff0a877f0b971592fb9254b1363cc21c120fd1fc993b1dad1406c69211df languageName: node linkType: hard @@ -39603,6 +40308,15 @@ __metadata: languageName: node linkType: hard +"use-sync-external-store@npm:^1.5.0": + version: 1.6.0 + resolution: "use-sync-external-store@npm:1.6.0" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + checksum: 61a62e910713adfaf91bdb72ff2cd30e5ba83687accaf3b6e75a903b45bf635f5722e3694af30d83a03e92cb533c0a5c699298d2fef639a03ffc86b469f4eee2 + languageName: node + linkType: hard + "use@npm:^3.1.0": version: 3.1.1 resolution: "use@npm:3.1.1::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fuse%2F-%2Fuse-3.1.1.tgz" @@ -40029,7 +40743,7 @@ __metadata: languageName: node linkType: hard -"warn-once@npm:0.1.1": +"warn-once@npm:0.1.1, warn-once@npm:^0.1.1": version: 0.1.1 resolution: "warn-once@npm:0.1.1" checksum: e6a5a1f5a8dba7744399743d3cfb571db4c3947897875d4962a7c5b1bf2195ab4518c838cb4cea652e71729f21bba2e98dc75686f5fccde0fabbd894e2ed0c0d @@ -41582,6 +42296,21 @@ __metadata: languageName: node linkType: hard +"yargs@npm:^17.7.2": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: ^8.0.1 + escalade: ^3.1.1 + get-caller-file: ^2.0.5 + require-directory: ^2.1.1 + string-width: ^4.2.3 + y18n: ^5.0.5 + yargs-parser: ^21.1.1 + checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a + languageName: node + linkType: hard + "yauzl@npm:^2.10.0": version: 2.10.0 resolution: "yauzl@npm:2.10.0::__archiveUrl=https%3A%2F%2Fregistry.npmjs.org%2Fyauzl%2F-%2Fyauzl-2.10.0.tgz"