From 417fb980b1ec25072879fd04e9bd7a6d9cc585d8 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 15 Jun 2024 18:47:40 -0400 Subject: [PATCH 01/37] REF: Use menu package since showPopmenu is being removed --- blue_modules/showPopupMenu.android.ts | 32 --------- components/TooltipMenu.android.tsx | 90 +++++++++++------------- ios/BlueWallet.xcodeproj/project.pbxproj | 32 ++++----- ios/Podfile.lock | 10 ++- package-lock.json | 15 ++++ package.json | 1 + 6 files changed, 82 insertions(+), 98 deletions(-) delete mode 100644 blue_modules/showPopupMenu.android.ts diff --git a/blue_modules/showPopupMenu.android.ts b/blue_modules/showPopupMenu.android.ts deleted file mode 100644 index 3dcdfe16f1..0000000000 --- a/blue_modules/showPopupMenu.android.ts +++ /dev/null @@ -1,32 +0,0 @@ -// @ts-ignore: Ignore -import type { Element } from 'react'; -import { findNodeHandle, Text, TouchableNativeFeedback, TouchableWithoutFeedback, UIManager, View } from 'react-native'; - -type PopupMenuItem = { id?: any; label: string }; -type OnPopupMenuItemSelect = (selectedPopupMenuItem: PopupMenuItem) => void; -type PopupAnchor = Element; -type PopupMenuOptions = { onCancel?: () => void }; - -function showPopupMenu( - items: PopupMenuItem[], - onSelect: OnPopupMenuItemSelect, - anchor: PopupAnchor, - { onCancel }: PopupMenuOptions = {}, -): void { - UIManager.showPopupMenu( - // @ts-ignore: Ignore - findNodeHandle(anchor), - items.map(item => item.label), - function () { - if (onCancel) onCancel(); - }, - function (eventName: 'dismissed' | 'itemSelected', selectedIndex?: number) { - // @ts-ignore: Ignore - if (eventName === 'itemSelected') onSelect(items[selectedIndex]); - else onCancel && onCancel(); - }, - ); -} - -export type { OnPopupMenuItemSelect, PopupMenuItem, PopupMenuOptions }; -export default showPopupMenu; diff --git a/components/TooltipMenu.android.tsx b/components/TooltipMenu.android.tsx index 9689d5a7fe..bd4ecf345c 100644 --- a/components/TooltipMenu.android.tsx +++ b/components/TooltipMenu.android.tsx @@ -1,14 +1,11 @@ -import React, { forwardRef, Ref, useCallback, useEffect, useMemo, useRef } from 'react'; -import { Pressable, View } from 'react-native'; - -import showPopupMenu, { OnPopupMenuItemSelect, PopupMenuItem } from '../blue_modules/showPopupMenu.android'; +import React, { forwardRef, Ref, useCallback, useMemo } from 'react'; +import { Pressable } from 'react-native'; +import { MenuView, NativeActionEvent } from '@react-native-menu/menu'; import { ToolTipMenuProps } from './types'; -const dismissMenu = () => { - console.log('dismissMenu Not implemented'); -}; +// Define a custom type for the nativeEvent parameter + const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref<{ dismissMenu?: () => void }>) => { - const menuRef = useRef(null); const { actions, children, @@ -18,57 +15,54 @@ const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref<{ dismissMenu?: () => enableAndroidRipple = true, disabled = false, onPress, + title = 'Menu', ...restProps } = props; - const handleToolTipSelection = useCallback( - (selection: PopupMenuItem) => { - if (selection.id) { - onPressMenuItem(selection.id); - } - }, - [onPressMenuItem], - ); - - useEffect(() => { - // @ts-ignore: fix later - if (ref && ref.current) { - // @ts-ignore: fix later - ref.current.dismissMenu = dismissMenu; - } - }, [ref]); - const menuItems = useMemo(() => { - const menu: { id: string; label: string }[] = []; - actions.forEach(action => { + return actions.flatMap(action => { if (Array.isArray(action)) { - action.forEach(actionToMap => { - menu.push({ id: actionToMap.id.toString(), label: actionToMap.text }); - }); - } else { - menu.push({ id: action.id.toString(), label: action.text }); + return action.map(actionToMap => ({ + id: actionToMap.id.toString(), + title: actionToMap.text, + titleColor: actionToMap.disabled ? 'gray' : 'black', + image: actionToMap.icon.iconValue, + imageColor: actionToMap.disabled ? 'gray' : 'black', + attributes: { disabled: actionToMap.disabled }, + })); } + return { + id: action.id.toString(), + title: action.text, + titleColor: action.disabled ? 'gray' : 'black', + image: action.icon.iconValue, + imageColor: action.disabled ? 'gray' : 'black', + attributes: { disabled: action.disabled }, + }; }); - return menu; }, [actions]); - const showMenu = useCallback(() => { - if (menuRef.current) { - showPopupMenu(menuItems, handleToolTipSelection, menuRef.current); - } - }, [menuItems, handleToolTipSelection]); + const handleToolTipSelection = useCallback( + ({ nativeEvent }: NativeActionEvent) => { + if (nativeEvent) { + onPressMenuItem(nativeEvent.event); + } + }, + [onPressMenuItem], + ); return ( - - {children} - + + {} } : { onPress })} + {...restProps} + > + {children} + + ); }; diff --git a/ios/BlueWallet.xcodeproj/project.pbxproj b/ios/BlueWallet.xcodeproj/project.pbxproj index d42a8f0c98..d6483fd066 100644 --- a/ios/BlueWallet.xcodeproj/project.pbxproj +++ b/ios/BlueWallet.xcodeproj/project.pbxproj @@ -169,7 +169,7 @@ B4D0B2682C1DED67006B6B1B /* ReceiveMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D0B2672C1DED67006B6B1B /* ReceiveMethod.swift */; }; B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; }; C59F90CE0D04D3E4BB39BC5D /* libPods-BlueWalletUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */; }; - C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; + C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -491,7 +491,7 @@ files = ( 782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */, 764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */, - C978A716948AB7DEC5B6F677 /* (null) in Frameworks */, + C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */, 773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1164,9 +1164,9 @@ ); mainGroup = 83CBB9F61A601CBA00E9B192; packageReferences = ( - 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */, + 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */, B41B76832B66B2FF002C48D5 /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */, - B48A6A272C1DF01000030AB9 /* XCRemoteSwiftPackageReference "keychain-swift" */, + B48A6A272C1DF01000030AB9 /* XCRemoteSwiftPackageReference "keychain-swift.git" */, ); productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; projectDirPath = ""; @@ -1847,7 +1847,7 @@ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1901,7 +1901,7 @@ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -2158,7 +2158,7 @@ OTHER_LDFLAGS = "$(inherited)"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -2216,7 +2216,7 @@ REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -2360,7 +2360,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OBJC_BRIDGING_HEADER = "WalletInformationWidget/Widgets/Shared/BlueWalletWatch-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 7.0; }; @@ -2407,7 +2407,7 @@ SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OBJC_BRIDGING_HEADER = "WalletInformationWidget/Widgets/Shared/BlueWalletWatch-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-O"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = 4; WATCHOS_DEPLOYMENT_TARGET = 7.0; }; @@ -2555,7 +2555,7 @@ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,6"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -2603,7 +2603,7 @@ SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,6"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -2687,7 +2687,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */ = { + 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/EFPrefix/EFQRCode.git"; requirement = { @@ -2703,7 +2703,7 @@ version = 6.28.1; }; }; - B48A6A272C1DF01000030AB9 /* XCRemoteSwiftPackageReference "keychain-swift" */ = { + B48A6A272C1DF01000030AB9 /* XCRemoteSwiftPackageReference "keychain-swift.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/evgenyneu/keychain-swift.git"; requirement = { @@ -2716,7 +2716,7 @@ /* Begin XCSwiftPackageProductDependency section */ 6DFC806F24EA0B6C007B8700 /* EFQRCode */ = { isa = XCSwiftPackageProductDependency; - package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */; + package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */; productName = EFQRCode; }; B41B76842B66B2FF002C48D5 /* Bugsnag */ = { @@ -2731,7 +2731,7 @@ }; B48A6A282C1DF01000030AB9 /* KeychainSwift */ = { isa = XCSwiftPackageProductDependency; - package = B48A6A272C1DF01000030AB9 /* XCRemoteSwiftPackageReference "keychain-swift" */; + package = B48A6A272C1DF01000030AB9 /* XCRemoteSwiftPackageReference "keychain-swift.git" */; productName = KeychainSwift; }; /* End XCSwiftPackageProductDependency section */ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2c7150bdb0..e3f41c6c66 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -339,6 +339,8 @@ PODS: - React-Core - react-native-ios-context-menu (1.15.3): - React-Core + - react-native-menu (1.1.2): + - React - react-native-qrcode-local-image (1.0.4): - React - react-native-randombytes (3.6.1): @@ -462,7 +464,7 @@ PODS: - React-perflogger (= 0.72.14) - ReactNativeCameraKit (13.0.0): - React-Core - - RealmJS (12.9.0): + - RealmJS (12.10.0): - React - rn-ldk (0.8.4): - React-Core @@ -551,6 +553,7 @@ DEPENDENCIES: - react-native-idle-timer (from `../node_modules/react-native-idle-timer`) - react-native-image-picker (from `../node_modules/react-native-image-picker`) - react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`) + - "react-native-menu (from `../node_modules/@react-native-menu/menu`)" - "react-native-qrcode-local-image (from `../node_modules/@remobile/react-native-qrcode-local-image`)" - react-native-randombytes (from `../node_modules/react-native-randombytes`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) @@ -670,6 +673,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-image-picker" react-native-ios-context-menu: :path: "../node_modules/react-native-ios-context-menu" + react-native-menu: + :path: "../node_modules/@react-native-menu/menu" react-native-qrcode-local-image: :path: "../node_modules/@remobile/react-native-qrcode-local-image" react-native-randombytes: @@ -801,6 +806,7 @@ SPEC CHECKSUMS: react-native-idle-timer: ee2053f2cd458f6fef1db7bebe5098ca281cce07 react-native-image-picker: 1889c342e6a4ba089ff11ae0c3bf5cc30a3134d0 react-native-ios-context-menu: e529171ba760a1af7f2ef0729f5a7f4d226171c5 + react-native-menu: d32728a357dfb360cf01cd5979cf7713c5acbb95 react-native-qrcode-local-image: 35ccb306e4265bc5545f813e54cc830b5d75bcfc react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846 react-native-safe-area-context: 399a5859f6acbdf67f671c69b53113f535f3b5b0 @@ -824,7 +830,7 @@ SPEC CHECKSUMS: React-utils: 22a77b05da25ce49c744faa82e73856dcae1734e ReactCommon: ff94462e007c568d8cdebc32e3c97af86ec93bb5 ReactNativeCameraKit: 9d46a5d7dd544ca64aa9c03c150d2348faf437eb - RealmJS: 7aa0e7dcc8959d28cee3ab302415a8893e50ad12 + RealmJS: f86da4f2c5b089d976db335f370449903ddc8fbb rn-ldk: 0d8749d98cc5ce67302a32831818c116b67f7643 RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c RNCClipboard: 0a720adef5ec193aa0e3de24c3977222c7e52a37 diff --git a/package-lock.json b/package-lock.json index 3df0967f9a..c5ae5346ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@react-native-async-storage/async-storage": "1.23.1", "@react-native-clipboard/clipboard": "1.14.1", "@react-native-community/push-notification-ios": "1.11.0", + "@react-native-menu/menu": "^1.1.2", "@react-navigation/drawer": "6.6.15", "@react-navigation/native": "6.1.17", "@react-navigation/native-stack": "6.9.26", @@ -5402,6 +5403,15 @@ "react-native": ">=0.58.4" } }, + "node_modules/@react-native-menu/menu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@react-native-menu/menu/-/menu-1.1.2.tgz", + "integrity": "sha512-I7JWiwmIwRp+Tee2OJHPwzVKdLjzgUkdChHQ75oyEWo1YcVsXEjLVGmxWCTA6JExzS6SQW/ACmjuXLJFTvu9Pw==", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/@react-native/assets-registry": { "version": "0.72.0", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz", @@ -26619,6 +26629,11 @@ "invariant": "^2.2.4" } }, + "@react-native-menu/menu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@react-native-menu/menu/-/menu-1.1.2.tgz", + "integrity": "sha512-I7JWiwmIwRp+Tee2OJHPwzVKdLjzgUkdChHQ75oyEWo1YcVsXEjLVGmxWCTA6JExzS6SQW/ACmjuXLJFTvu9Pw==" + }, "@react-native/assets-registry": { "version": "0.72.0", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.72.0.tgz", diff --git a/package.json b/package.json index 9bb6a62041..c7be0876eb 100644 --- a/package.json +++ b/package.json @@ -104,6 +104,7 @@ "@react-native-async-storage/async-storage": "1.23.1", "@react-native-clipboard/clipboard": "1.14.1", "@react-native-community/push-notification-ios": "1.11.0", + "@react-native-menu/menu": "1.1.2", "@react-navigation/drawer": "6.6.15", "@react-navigation/native": "6.1.17", "@react-navigation/native-stack": "6.9.26", From 9f93cf8f50db9ccbf67978865fd5fd04514121e0 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 15 Jun 2024 18:58:09 -0400 Subject: [PATCH 02/37] Update TooltipMenu.android.tsx --- components/TooltipMenu.android.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/TooltipMenu.android.tsx b/components/TooltipMenu.android.tsx index bd4ecf345c..14d409db3b 100644 --- a/components/TooltipMenu.android.tsx +++ b/components/TooltipMenu.android.tsx @@ -1,11 +1,11 @@ -import React, { forwardRef, Ref, useCallback, useMemo } from 'react'; +import React, { forwardRef, useCallback, useMemo } from 'react'; import { Pressable } from 'react-native'; import { MenuView, NativeActionEvent } from '@react-native-menu/menu'; import { ToolTipMenuProps } from './types'; // Define a custom type for the nativeEvent parameter -const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref<{ dismissMenu?: () => void }>) => { +const BaseToolTipMenu = (props: ToolTipMenuProps) => { const { actions, children, From 39d43efeac099f909d97b72c1dd3aa3cb0934dc0 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 15 Jun 2024 21:12:43 -0400 Subject: [PATCH 03/37] Update TooltipMenu.android.tsx --- components/TooltipMenu.android.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/TooltipMenu.android.tsx b/components/TooltipMenu.android.tsx index 14d409db3b..874ef9c79c 100644 --- a/components/TooltipMenu.android.tsx +++ b/components/TooltipMenu.android.tsx @@ -3,9 +3,7 @@ import { Pressable } from 'react-native'; import { MenuView, NativeActionEvent } from '@react-native-menu/menu'; import { ToolTipMenuProps } from './types'; -// Define a custom type for the nativeEvent parameter - -const BaseToolTipMenu = (props: ToolTipMenuProps) => { +const BaseToolTipMenu = (props: ToolTipMenuProps, _ref: any) => { const { actions, children, From 3dc65ae074e6c059cfa6137f1e16ec050a744a54 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 15 Jun 2024 21:13:15 -0400 Subject: [PATCH 04/37] Update TooltipMenu.android.tsx --- components/TooltipMenu.android.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/TooltipMenu.android.tsx b/components/TooltipMenu.android.tsx index 874ef9c79c..e4fecd13e5 100644 --- a/components/TooltipMenu.android.tsx +++ b/components/TooltipMenu.android.tsx @@ -64,6 +64,6 @@ const BaseToolTipMenu = (props: ToolTipMenuProps, _ref: any) => { ); }; -const ToolTipMenu = forwardRef(BaseToolTipMenu); +const ToolTipMenu = BaseToolTipMenu; -export default ToolTipMenu; +export default forwardRef(ToolTipMenu); From dc3051a9aa3d3763844680f29e0254ca4814545c Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 15 Jun 2024 21:24:47 -0400 Subject: [PATCH 05/37] Update TooltipMenu.android.tsx --- components/TooltipMenu.android.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/TooltipMenu.android.tsx b/components/TooltipMenu.android.tsx index e4fecd13e5..1e4adf9425 100644 --- a/components/TooltipMenu.android.tsx +++ b/components/TooltipMenu.android.tsx @@ -3,7 +3,7 @@ import { Pressable } from 'react-native'; import { MenuView, NativeActionEvent } from '@react-native-menu/menu'; import { ToolTipMenuProps } from './types'; -const BaseToolTipMenu = (props: ToolTipMenuProps, _ref: any) => { +const BaseToolTipMenu = (props: ToolTipMenuProps, ref: any) => { const { actions, children, @@ -17,6 +17,8 @@ const BaseToolTipMenu = (props: ToolTipMenuProps, _ref: any) => { ...restProps } = props; + console.debug('ToolTipMenu.android.tsx ref:', ref); + const menuItems = useMemo(() => { return actions.flatMap(action => { if (Array.isArray(action)) { From 543acb155eaf40cb8d9b8178fb9eb5f62e535808 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 15 Jun 2024 21:26:13 -0400 Subject: [PATCH 06/37] Update metro.config.js --- metro.config.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/metro.config.js b/metro.config.js index e91aba937c..72fcb3cbf0 100644 --- a/metro.config.js +++ b/metro.config.js @@ -1,17 +1,11 @@ +const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); + /** - * Metro configuration for React Native - * https://github.com/facebook/react-native + * Metro configuration + * https://reactnative.dev/docs/metro * - * @format + * @type {import('metro-config').MetroConfig} */ +const config = {}; -module.exports = { - transformer: { - getTransformOptions: async () => ({ - transform: { - experimentalImportSupport: false, - inlineRequires: true, - }, - }), - }, -}; +module.exports = mergeConfig(getDefaultConfig(__dirname), config); From 30e6b3baa3466c174d7ecf7c5ec6926d8fce6fe4 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 16 Jun 2024 11:44:55 -0400 Subject: [PATCH 07/37] REF: Animated scroll Header --- components/Header.tsx | 37 +++++++++++++++++++---- navigation/DetailViewScreensStack.tsx | 37 ++++------------------- screen/settings/SettingsPrivacy.tsx | 2 +- screen/wallets/DrawerList.tsx | 2 +- screen/wallets/WalletsList.tsx | 42 +++++++++++++++++++++++++-- 5 files changed, 77 insertions(+), 43 deletions(-) diff --git a/components/Header.tsx b/components/Header.tsx index 1be637b977..08f627cb8c 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { StyleSheet, Text, View } from 'react-native'; - +import { StyleSheet, Text, Animated } from 'react-native'; import loc from '../loc'; import PlusIcon from './icons/PlusIcon'; import { useTheme } from './themes'; @@ -9,9 +8,11 @@ interface HeaderProps { leftText: string; isDrawerList?: boolean; onNewWalletPress?: () => void; + scrollY?: Animated.Value; + staticText?: boolean; } -export const Header: React.FC = ({ leftText, isDrawerList, onNewWalletPress }) => { +export const Header: React.FC = ({ leftText, isDrawerList, onNewWalletPress, scrollY, staticText = false }) => { const { colors } = useTheme(); const styleWithProps = StyleSheet.create({ root: { @@ -24,11 +25,31 @@ export const Header: React.FC = ({ leftText, isDrawerList, onNewWal }, }); + const HEADER_MAX_HEIGHT = 70; + const HEADER_MIN_HEIGHT = 0; + const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT; + + const headerHeightAnimated = scrollY?.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE], + outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT], + extrapolate: 'clamp', + }); + + const headerOpacity = scrollY?.interpolate({ + inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], + outputRange: [1, 0.5, 0], + extrapolate: 'clamp', + }); + return ( - - {leftText} + + {staticText ? ( + {leftText} + ) : ( + {leftText} + )} {onNewWalletPress && } - + ); }; @@ -45,4 +66,8 @@ const styles = StyleSheet.create({ fontWeight: 'bold', fontSize: 34, }, + title: { + fontSize: 34, + fontWeight: '600', + }, }); diff --git a/navigation/DetailViewScreensStack.tsx b/navigation/DetailViewScreensStack.tsx index c9aab42499..38e6a4cf3f 100644 --- a/navigation/DetailViewScreensStack.tsx +++ b/navigation/DetailViewScreensStack.tsx @@ -1,11 +1,10 @@ -import React, { useCallback, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { NativeStackNavigationOptions } from '@react-navigation/native-stack'; -import { I18nManager, View } from 'react-native'; +import { I18nManager } from 'react-native'; import { isDesktop } from '../blue_modules/environment'; import HeaderRightButton from '../components/HeaderRightButton'; import navigationStyle, { CloseButtonPosition } from '../components/navigationStyle'; import { useTheme } from '../components/themes'; -import { useExtendedNavigation } from '../hooks/useExtendedNavigation'; import loc from '../loc'; import LdkInfo from '../screen/lnd/ldkInfo'; import LNDViewAdditionalInvoiceInformation from '../screen/lnd/lndViewAdditionalInvoiceInformation'; @@ -64,41 +63,26 @@ import SignVerifyStackRoot from './SignVerifyStack'; import ViewEditMultisigCosignersStackRoot from './ViewEditMultisigCosignersStack'; import WalletExportStack from './WalletExportStack'; import WalletXpubStackRoot from './WalletXpubStack'; -import PlusIcon from '../components/icons/PlusIcon'; import SettingsButton from '../components/icons/SettingsButton'; const DetailViewStackScreensStack = () => { const theme = useTheme(); - const navigation = useExtendedNavigation(); const SaveButton = useMemo(() => , []); const DetailButton = useMemo(() => , []); - const navigateToAddWallet = useCallback(() => { - navigation.navigate('AddWalletRoot'); - }, [navigation]); - const useWalletListScreenOptions = useMemo(() => { - const RightBarButtons = ( - <> - - - - - ); - return { title: loc.wallets.wallets, navigationBarColor: theme.colors.navigationBarColor, headerShown: !isDesktop, - headerLargeTitle: true, headerStyle: { backgroundColor: theme.colors.customHeader, }, - headerRight: I18nManager.isRTL ? undefined : () => RightBarButtons, - headerLeft: I18nManager.isRTL ? () => RightBarButtons : undefined, + headerRight: I18nManager.isRTL ? undefined : () => , + headerLeft: I18nManager.isRTL ? () => : undefined, }; - }, [navigateToAddWallet, theme.colors.customHeader, theme.colors.navigationBarColor]); + }, [theme.colors.customHeader, theme.colors.navigationBarColor]); const walletListScreenOptions = useWalletListScreenOptions; return ( @@ -161,8 +145,6 @@ const DetailViewStackScreensStack = () => { backgroundColor: theme.colors.customHeader, }, headerRight: () => DetailButton, - headerBackTitleStyle: { fontSize: 0 }, - headerBackTitleVisible: true, })(theme)} /> @@ -268,9 +250,6 @@ const DetailViewStackScreensStack = () => { options={navigationStyle({ headerTransparent: true, title: loc.settings.header, - // workaround to deal with the flicker when headerBackTitleVisible is false - headerBackTitleStyle: { fontSize: 0 }, - headerBackTitleVisible: true, headerShadowVisible: false, headerLargeTitle: true, animationTypeForReplace: 'push', @@ -388,9 +367,3 @@ const DetailViewStackScreensStack = () => { }; export default DetailViewStackScreensStack; - -const styles = { - width24: { - width: 24, - }, -}; diff --git a/screen/settings/SettingsPrivacy.tsx b/screen/settings/SettingsPrivacy.tsx index b192d53175..7be6f50671 100644 --- a/screen/settings/SettingsPrivacy.tsx +++ b/screen/settings/SettingsPrivacy.tsx @@ -102,7 +102,7 @@ const SettingsPrivacy: React.FC = () => { {Platform.OS === 'android' ? ( -
+
) : null} diff --git a/screen/wallets/DrawerList.tsx b/screen/wallets/DrawerList.tsx index f16e91ac65..caa1d63824 100644 --- a/screen/wallets/DrawerList.tsx +++ b/screen/wallets/DrawerList.tsx @@ -142,7 +142,7 @@ const DrawerList: React.FC = memo(({ navigation }) => { showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} > -
+
{ } = useStorage(); const { width } = useWindowDimensions(); const { colors, scanImage } = useTheme(); - const { navigate } = useExtendedNavigation(); + const { navigate, setOptions } = useExtendedNavigation(); const isFocused = useIsFocused(); const routeName = useRoute().name; const dataSource = getTransactions(undefined, 10); const walletsCount = useRef(wallets.length); const walletActionButtonsRef = useRef(); + const scrollY = useRef(new Animated.Value(0)).current; + const stylesHook = StyleSheet.create({ walletsListWrapper: { backgroundColor: colors.brandingColor, @@ -149,6 +162,21 @@ const WalletsList: React.FC = () => { walletsCount.current = wallets.length; }, [wallets]); + const HeaderTitle = useMemo(() => { + const titleOpacity = scrollY.interpolate({ + inputRange: [0, 200], + outputRange: [0, 1], + extrapolate: 'clamp', + }); + return {loc.wallets.list_title}; + }, [scrollY]); + + useEffect(() => { + setOptions({ + headerTitle: () => HeaderTitle, + }); + }, [HeaderTitle, scrollY, setOptions]); + const verifyBalance = useCallback(() => { if (getBalance() !== 0) { A(A.ENUM.GOT_NONZERO_BALANCE); @@ -405,6 +433,7 @@ const WalletsList: React.FC = () => { return ( +
navigate('AddWalletRoot')} scrollY={scrollY} /> removeClippedSubviews @@ -421,6 +450,8 @@ const WalletsList: React.FC = () => { windowSize={21} maxToRenderPerBatch={10} updateCellsBatchingPeriod={50} + onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false })} + scrollEventThrottle={16} /> {renderScanButton()} @@ -473,4 +504,9 @@ const styles = StyleSheet.create({ transaction: { marginHorizontal: 0, }, + nativeHeaderTitle: { + fontSize: 17, + fontWeight: '600', + color: 'black', // adjust color if necessary + }, }); From 22862186f54bb3ec34d166aca3f30ac886057302 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 16 Jun 2024 13:28:40 -0400 Subject: [PATCH 08/37] Update Header.tsx --- components/Header.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/components/Header.tsx b/components/Header.tsx index 08f627cb8c..4beb47cccf 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -25,7 +25,7 @@ export const Header: React.FC = ({ leftText, isDrawerList, onNewWal }, }); - const HEADER_MAX_HEIGHT = 70; + const HEADER_MAX_HEIGHT = 55; const HEADER_MIN_HEIGHT = 0; const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT; @@ -44,9 +44,9 @@ export const Header: React.FC = ({ leftText, isDrawerList, onNewWal return ( {staticText ? ( - {leftText} + {leftText} ) : ( - {leftText} + {leftText} )} {onNewWalletPress && } @@ -66,8 +66,4 @@ const styles = StyleSheet.create({ fontWeight: 'bold', fontSize: 34, }, - title: { - fontSize: 34, - fontWeight: '600', - }, }); From 854d0261df785733e959ab5ed67db4c52f5ebd5f Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 16 Jun 2024 21:31:20 -0400 Subject: [PATCH 09/37] REF: Use MenuView on iOS --- components/AddressInput.tsx | 2 +- components/TooltipMenu.ios.tsx | 198 +++++++++++++++++---------------- components/types.ts | 3 +- package-lock.json | 2 +- screen/receive/details.js | 2 - 5 files changed, 109 insertions(+), 98 deletions(-) diff --git a/components/AddressInput.tsx b/components/AddressInput.tsx index b12f8e36fa..70b6335381 100644 --- a/components/AddressInput.tsx +++ b/components/AddressInput.tsx @@ -146,7 +146,7 @@ const AddressInput = ({ Keyboard.dismiss(); if (launchedBy) scanQrHelper(launchedBy).then(value => onBarScanned({ data: value })); }} - style={[styles.scan, stylesHook.scan]} + buttonStyle={[styles.scan, stylesHook.scan]} accessibilityLabel={loc.send.details_scan} accessibilityHint={loc.send.details_scan_hint} > diff --git a/components/TooltipMenu.ios.tsx b/components/TooltipMenu.ios.tsx index 90eb899583..d8917501aa 100644 --- a/components/TooltipMenu.ios.tsx +++ b/components/TooltipMenu.ios.tsx @@ -1,13 +1,12 @@ import React, { forwardRef, Ref, useCallback, useMemo } from 'react'; -import { TouchableOpacity } from 'react-native'; -import { ContextMenuButton, ContextMenuView, RenderItem } from 'react-native-ios-context-menu'; - -import { Action, ToolTipMenuProps } from './types'; +import { Pressable, TouchableOpacity, View } from 'react-native'; +import { ContextMenuView, RenderItem, OnPressMenuItemEventObject, MenuState, IconConfig } from 'react-native-ios-context-menu'; +import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu'; +import { ToolTipMenuProps, Action } from './types'; const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref) => { const { title = '', - isButton = false, isMenuPrimaryAction = false, renderPreview, disabled = false, @@ -16,111 +15,124 @@ const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref) => { onMenuWillHide, buttonStyle, onPressMenuItem, + children, ...restProps } = props; - const menuItemMapped = useCallback(({ action, menuOptions }: { action: Action; menuOptions?: string[] }) => { - const item: any = { + const mapMenuItemForContextMenuView = useCallback((action: Action) => { + return { actionKey: action.id.toString(), actionTitle: action.text, - icon: action.icon, - menuOptions, - menuTitle: action.menuTitle, + icon: action.icon?.iconValue ? ({ iconType: 'SYSTEM', iconValue: action.icon.iconValue } as IconConfig) : undefined, + state: action.menuStateOn ? ('on' as MenuState) : ('off' as MenuState), + attributes: action.disabled ? ['disabled'] : [], }; - item.menuState = action.menuStateOn ? 'on' : 'off'; + }, []); - if (action.disabled) { - item.menuAttributes = ['disabled']; - } - return item; + const mapMenuItemForMenuView = useCallback((action: Action): MenuAction => { + return { + id: action.id.toString(), + title: action.text, + image: action.icon?.iconValue || undefined, + state: action.menuStateOn ? ('on' as MenuState) : undefined, + attributes: { disabled: action.disabled }, + }; }, []); - const menuItems = useMemo( - () => - props.actions.map(action => { - if (Array.isArray(action)) { - const mapped = action.map(actionToMap => menuItemMapped({ action: actionToMap })); - return { - menuOptions: ['displayInline'], - menuItems: mapped, - menuTitle: '', - }; - } else { - return menuItemMapped({ action }); - } - }), - [props.actions, menuItemMapped], - ); + const contextMenuItems = useMemo(() => { + const flattenedActions = props.actions.flat(); + return flattenedActions.map(mapMenuItemForContextMenuView); + }, [props.actions, mapMenuItemForContextMenuView]); + + const menuViewItems = useMemo(() => { + return props.actions.map(actionGroup => { + if (Array.isArray(actionGroup)) { + return { + id: actionGroup[0].id.toString(), + title: '', + subactions: actionGroup.map(mapMenuItemForMenuView), + displayInline: true, + }; + } else { + return mapMenuItemForMenuView(actionGroup); + } + }); + }, [props.actions, mapMenuItemForMenuView]); - const handlePressMenuItem = useCallback( - ({ nativeEvent }: { nativeEvent: { actionKey: string } }) => { - onPressMenuItem(nativeEvent.actionKey); + const handlePressMenuItemForContextMenuView = useCallback( + (event: OnPressMenuItemEventObject) => { + onPressMenuItem(event.nativeEvent.actionKey); }, [onPressMenuItem], ); - const renderContextMenuButton = () => ( - - - {props.children} - - + const handlePressMenuItemForMenuView = useCallback( + ({ nativeEvent }: NativeActionEvent) => { + onPressMenuItem(nativeEvent.event); + }, + [onPressMenuItem], ); - const renderContextMenuView = () => ( - - {onPress ? ( - - {props.children} - - ) : ( - props.children - )} - - ); + const renderContextMenuView = () => { + console.debug('ToolTipMenu.tsx rendering: renderContextMenuView'); + return ( + + {onPress ? ( + + {children} + + ) : ( + children + )} + + ); + }; - return isMenuPrimaryAction && onPress ? ( - - {renderContextMenuButton()} - - ) : isButton ? ( - renderContextMenuButton() - ) : ( - renderContextMenuView() - ); + const renderMenuView = () => { + console.debug('ToolTipMenu.tsx rendering: renderMenuView'); + return ( + + + {isMenuPrimaryAction ? ( + + {children} + + ) : ( + children + )} + + + ); + }; + + return renderPreview ? renderContextMenuView() : renderMenuView(); }; const ToolTipMenu = forwardRef(BaseToolTipMenu); diff --git a/components/types.ts b/components/types.ts index 57a57f67a9..ef9d3c2c9e 100644 --- a/components/types.ts +++ b/components/types.ts @@ -10,6 +10,7 @@ export interface Action { menuTitle?: string; menuStateOn?: boolean; disabled?: boolean; + displayInline?: boolean; } export interface ToolTipMenuProps { @@ -30,7 +31,7 @@ export interface ToolTipMenuProps { style?: ViewStyle | ViewStyle[]; accessibilityLabel?: string; accessibilityHint?: string; - buttonStyle?: ViewStyle; + buttonStyle?: ViewStyle | ViewStyle[]; onMenuWillShow?: () => void; onMenuWillHide?: () => void; } diff --git a/package-lock.json b/package-lock.json index c5ae5346ca..d06e997bbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@react-native-async-storage/async-storage": "1.23.1", "@react-native-clipboard/clipboard": "1.14.1", "@react-native-community/push-notification-ios": "1.11.0", - "@react-native-menu/menu": "^1.1.2", + "@react-native-menu/menu": "1.1.2", "@react-navigation/drawer": "6.6.15", "@react-navigation/native": "6.1.17", "@react-navigation/native-stack": "6.9.26", diff --git a/screen/receive/details.js b/screen/receive/details.js index fed468ba83..9381b9ae7b 100644 --- a/screen/receive/details.js +++ b/screen/receive/details.js @@ -271,8 +271,6 @@ const ReceiveDetails = () => { const obtainWalletAddress = useCallback(async () => { console.log('receive/details - componentDidMount'); - wallet.setUserHasSavedExport(true); - await saveToDisk(); let newAddress; if (address) { setAddressBIP21Encoded(address); From 1bd239bf782d3b5a69665423e2058898c1266f6b Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 16 Jun 2024 22:26:43 -0400 Subject: [PATCH 10/37] REF: Send options to use Tooltip --- components/TooltipMenu.android.tsx | 71 ----- components/TooltipMenu.ios.tsx | 140 ---------- components/TooltipMenu.tsx | 145 ++++++++++- components/types.ts | 2 +- loc/en.json | 1 - screen/send/SendDetails.tsx | 399 +++++++++++++++-------------- 6 files changed, 342 insertions(+), 416 deletions(-) delete mode 100644 components/TooltipMenu.android.tsx delete mode 100644 components/TooltipMenu.ios.tsx diff --git a/components/TooltipMenu.android.tsx b/components/TooltipMenu.android.tsx deleted file mode 100644 index 1e4adf9425..0000000000 --- a/components/TooltipMenu.android.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { forwardRef, useCallback, useMemo } from 'react'; -import { Pressable } from 'react-native'; -import { MenuView, NativeActionEvent } from '@react-native-menu/menu'; -import { ToolTipMenuProps } from './types'; - -const BaseToolTipMenu = (props: ToolTipMenuProps, ref: any) => { - const { - actions, - children, - onPressMenuItem, - isMenuPrimaryAction = false, - buttonStyle = {}, - enableAndroidRipple = true, - disabled = false, - onPress, - title = 'Menu', - ...restProps - } = props; - - console.debug('ToolTipMenu.android.tsx ref:', ref); - - const menuItems = useMemo(() => { - return actions.flatMap(action => { - if (Array.isArray(action)) { - return action.map(actionToMap => ({ - id: actionToMap.id.toString(), - title: actionToMap.text, - titleColor: actionToMap.disabled ? 'gray' : 'black', - image: actionToMap.icon.iconValue, - imageColor: actionToMap.disabled ? 'gray' : 'black', - attributes: { disabled: actionToMap.disabled }, - })); - } - return { - id: action.id.toString(), - title: action.text, - titleColor: action.disabled ? 'gray' : 'black', - image: action.icon.iconValue, - imageColor: action.disabled ? 'gray' : 'black', - attributes: { disabled: action.disabled }, - }; - }); - }, [actions]); - - const handleToolTipSelection = useCallback( - ({ nativeEvent }: NativeActionEvent) => { - if (nativeEvent) { - onPressMenuItem(nativeEvent.event); - } - }, - [onPressMenuItem], - ); - - return ( - - {} } : { onPress })} - {...restProps} - > - {children} - - - ); -}; - -const ToolTipMenu = BaseToolTipMenu; - -export default forwardRef(ToolTipMenu); diff --git a/components/TooltipMenu.ios.tsx b/components/TooltipMenu.ios.tsx deleted file mode 100644 index d8917501aa..0000000000 --- a/components/TooltipMenu.ios.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import React, { forwardRef, Ref, useCallback, useMemo } from 'react'; -import { Pressable, TouchableOpacity, View } from 'react-native'; -import { ContextMenuView, RenderItem, OnPressMenuItemEventObject, MenuState, IconConfig } from 'react-native-ios-context-menu'; -import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu'; -import { ToolTipMenuProps, Action } from './types'; - -const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref) => { - const { - title = '', - isMenuPrimaryAction = false, - renderPreview, - disabled = false, - onPress, - onMenuWillShow, - onMenuWillHide, - buttonStyle, - onPressMenuItem, - children, - ...restProps - } = props; - - const mapMenuItemForContextMenuView = useCallback((action: Action) => { - return { - actionKey: action.id.toString(), - actionTitle: action.text, - icon: action.icon?.iconValue ? ({ iconType: 'SYSTEM', iconValue: action.icon.iconValue } as IconConfig) : undefined, - state: action.menuStateOn ? ('on' as MenuState) : ('off' as MenuState), - attributes: action.disabled ? ['disabled'] : [], - }; - }, []); - - const mapMenuItemForMenuView = useCallback((action: Action): MenuAction => { - return { - id: action.id.toString(), - title: action.text, - image: action.icon?.iconValue || undefined, - state: action.menuStateOn ? ('on' as MenuState) : undefined, - attributes: { disabled: action.disabled }, - }; - }, []); - - const contextMenuItems = useMemo(() => { - const flattenedActions = props.actions.flat(); - return flattenedActions.map(mapMenuItemForContextMenuView); - }, [props.actions, mapMenuItemForContextMenuView]); - - const menuViewItems = useMemo(() => { - return props.actions.map(actionGroup => { - if (Array.isArray(actionGroup)) { - return { - id: actionGroup[0].id.toString(), - title: '', - subactions: actionGroup.map(mapMenuItemForMenuView), - displayInline: true, - }; - } else { - return mapMenuItemForMenuView(actionGroup); - } - }); - }, [props.actions, mapMenuItemForMenuView]); - - const handlePressMenuItemForContextMenuView = useCallback( - (event: OnPressMenuItemEventObject) => { - onPressMenuItem(event.nativeEvent.actionKey); - }, - [onPressMenuItem], - ); - - const handlePressMenuItemForMenuView = useCallback( - ({ nativeEvent }: NativeActionEvent) => { - onPressMenuItem(nativeEvent.event); - }, - [onPressMenuItem], - ); - - const renderContextMenuView = () => { - console.debug('ToolTipMenu.tsx rendering: renderContextMenuView'); - return ( - - {onPress ? ( - - {children} - - ) : ( - children - )} - - ); - }; - - const renderMenuView = () => { - console.debug('ToolTipMenu.tsx rendering: renderMenuView'); - return ( - - - {isMenuPrimaryAction ? ( - - {children} - - ) : ( - children - )} - - - ); - }; - - return renderPreview ? renderContextMenuView() : renderMenuView(); -}; - -const ToolTipMenu = forwardRef(BaseToolTipMenu); - -export default ToolTipMenu; diff --git a/components/TooltipMenu.tsx b/components/TooltipMenu.tsx index 629dc02c4e..4d309afe77 100644 --- a/components/TooltipMenu.tsx +++ b/components/TooltipMenu.tsx @@ -1,10 +1,145 @@ -import { forwardRef, Ref } from 'react'; - -import { ToolTipMenuProps } from './types'; +import React, { forwardRef, Ref, useCallback, useMemo } from 'react'; +import { Platform, Pressable, TouchableOpacity, View } from 'react-native'; +import { ContextMenuView, RenderItem, OnPressMenuItemEventObject, MenuState, IconConfig } from 'react-native-ios-context-menu'; +import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu'; +import { ToolTipMenuProps, Action } from './types'; const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref) => { - console.debug('ToolTipMenu.tsx ref:', ref); - return props.children; + const { + title = '', + isMenuPrimaryAction = false, + renderPreview, + disabled = false, + onPress, + onMenuWillShow, + onMenuWillHide, + buttonStyle, + onPressMenuItem, + children, + isButton = false, + ...restProps + } = props; + + const mapMenuItemForContextMenuView = useCallback((action: Action) => { + return { + actionKey: action.id.toString(), + actionTitle: action.text, + icon: action.icon?.iconValue ? ({ iconType: 'SYSTEM', iconValue: action.icon.iconValue } as IconConfig) : undefined, + state: action.menuStateOn ? ('on' as MenuState) : ('off' as MenuState), + attributes: action.disabled ? ['disabled'] : [], + }; + }, []); + + const mapMenuItemForMenuView = useCallback((action: Action): MenuAction => { + return { + id: action.id.toString(), + title: action.text, + image: action.menuStateOn && Platform.OS === 'android' ? 'checkbox_on_background' : action.icon?.iconValue || undefined, + state: action.menuStateOn ? ('on' as MenuState) : undefined, + attributes: { disabled: action.disabled }, + }; + }, []); + + const contextMenuItems = useMemo(() => { + const flattenedActions = props.actions.flat(); + return flattenedActions.map(mapMenuItemForContextMenuView); + }, [props.actions, mapMenuItemForContextMenuView]); + + const menuViewItemsIOS = useMemo(() => { + return props.actions.map(actionGroup => { + if (Array.isArray(actionGroup)) { + return { + id: actionGroup[0].id.toString(), + title: '', + subactions: actionGroup.map(mapMenuItemForMenuView), + displayInline: true, + }; + } else { + return mapMenuItemForMenuView(actionGroup); + } + }); + }, [props.actions, mapMenuItemForMenuView]); + + const menuViewItemsAndroid = useMemo(() => { + const mergedActions = props.actions.flat(); + return mergedActions.map(mapMenuItemForMenuView); + }, [props.actions, mapMenuItemForMenuView]); + + const handlePressMenuItemForContextMenuView = useCallback( + (event: OnPressMenuItemEventObject) => { + onPressMenuItem(event.nativeEvent.actionKey); + }, + [onPressMenuItem], + ); + + const handlePressMenuItemForMenuView = useCallback( + ({ nativeEvent }: NativeActionEvent) => { + onPressMenuItem(nativeEvent.event); + }, + [onPressMenuItem], + ); + + const renderContextMenuView = () => { + console.debug('ToolTipMenu.tsx rendering: renderContextMenuView'); + return ( + + {onPress ? ( + + {children} + + ) : ( + children + )} + + ); + }; + + const renderMenuView = () => { + console.debug('ToolTipMenu.tsx rendering: renderMenuView'); + return ( + + + {isMenuPrimaryAction || isButton ? ( + + {children} + + ) : ( + children + )} + + + ); + }; + + return Platform.OS === 'ios' && renderPreview ? renderContextMenuView() : renderMenuView(); }; const ToolTipMenu = forwardRef(BaseToolTipMenu); diff --git a/components/types.ts b/components/types.ts index ef9d3c2c9e..8b4f1def98 100644 --- a/components/types.ts +++ b/components/types.ts @@ -3,7 +3,7 @@ import { AccessibilityRole, ViewStyle } from 'react-native'; export interface Action { id: string | number; text: string; - icon: { + icon?: { iconType: string; iconValue: string; }; diff --git a/loc/en.json b/loc/en.json index c9ca242bde..ef523da2ef 100644 --- a/loc/en.json +++ b/loc/en.json @@ -21,7 +21,6 @@ "close": "Close", "change_input_currency": "Change input currency", "refresh": "Refresh", - "more": "More", "pick_image": "Choose image from library", "pick_file": "Choose a file", "enter_amount": "Enter amount", diff --git a/screen/send/SendDetails.tsx b/screen/send/SendDetails.tsx index cde41a14a5..9bcb5e9598 100644 --- a/screen/send/SendDetails.tsx +++ b/screen/send/SendDetails.tsx @@ -57,6 +57,7 @@ import { isTablet } from '../../blue_modules/environment'; import { useExtendedNavigation } from '../../hooks/useExtendedNavigation'; import { ContactList } from '../../class/contact-list'; import { useStorage } from '../../hooks/context/useStorage'; +import { Action } from '../../components/types'; interface IPaymentDestinations { address: string; // btc address or payment code @@ -686,12 +687,40 @@ const SendDetails = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [routeParams.walletID]); + const importQrTransactionOnBarScanned = useCallback( + (ret: any) => { + navigation.getParent()?.getParent()?.dispatch(popAction); + if (!wallet) return; + if (!ret.data) ret = { data: ret }; + if (ret.data.toUpperCase().startsWith('UR')) { + presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); + } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { + // this looks like NOT base64, so maybe its transaction's hex + // we dont support it in this flow + } else { + // psbt base64? + + // we construct PSBT object and pass to next screen + // so user can do smth with it: + const psbt = bitcoin.Psbt.fromBase64(ret.data); + navigation.navigate('PsbtWithHardwareWallet', { + memo: transactionMemo, + fromWallet: wallet, + psbt, + }); + setIsLoading(false); + setOptionsVisible(false); + } + }, + [navigation, popAction, wallet, transactionMemo], + ); + /** * same as `importTransaction`, but opens camera instead. * * @returns {Promise} */ - const importQrTransaction = () => { + const importQrTransaction = useCallback(() => { if (wallet?.type !== WatchOnlyWallet.type) { return presentAlert({ title: loc.errors.error, message: 'Importing transaction in non-watchonly wallet (this should never happen)' }); } @@ -706,32 +735,7 @@ const SendDetails = () => { }, }); }); - }; - - const importQrTransactionOnBarScanned = (ret: any) => { - navigation.getParent()?.getParent()?.dispatch(popAction); - if (!wallet) return; - if (!ret.data) ret = { data: ret }; - if (ret.data.toUpperCase().startsWith('UR')) { - presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); - } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { - // this looks like NOT base64, so maybe its transaction's hex - // we dont support it in this flow - } else { - // psbt base64? - - // we construct PSBT object and pass to next screen - // so user can do smth with it: - const psbt = bitcoin.Psbt.fromBase64(ret.data); - navigation.navigate('PsbtWithHardwareWallet', { - memo: transactionMemo, - fromWallet: wallet, - psbt, - }); - setIsLoading(false); - setOptionsVisible(false); - } - }; + }, [wallet?.type, navigation, importQrTransactionOnBarScanned]); /** * watch-only wallets with enabled HW wallet support have different flow. we have to show PSBT to user as QR code @@ -741,7 +745,7 @@ const SendDetails = () => { * * @returns {Promise} */ - const importTransaction = async () => { + const importTransaction = useCallback(async () => { if (wallet?.type !== WatchOnlyWallet.type) { return presentAlert({ title: loc.errors.error, message: 'Importing transaction in non-watchonly wallet (this should never happen)' }); } @@ -792,7 +796,7 @@ const SendDetails = () => { presentAlert({ title: loc.errors.error, message: loc.send.details_no_signed_tx }); } } - }; + }, [wallet, navigation, transactionMemo]); const askCosignThisTransaction = async () => { return new Promise(resolve => { @@ -815,54 +819,65 @@ const SendDetails = () => { }); }; - const _importTransactionMultisig = async (base64arg: string | false) => { - try { - const base64 = base64arg || (await fs.openSignedTransaction()); - if (!base64) return; - const psbt = bitcoin.Psbt.fromBase64(base64); // if it doesnt throw - all good, its valid - - if ((wallet as MultisigHDWallet)?.howManySignaturesCanWeMake() > 0 && (await askCosignThisTransaction())) { - hideOptions(); - setIsLoading(true); - await sleep(100); - (wallet as MultisigHDWallet).cosignPsbt(psbt); - setIsLoading(false); - await sleep(100); - } + const hideOptions = useCallback(() => { + Keyboard.dismiss(); + setOptionsVisible(false); + }, []); - if (wallet) { - navigation.navigate('PsbtMultisig', { - memo: transactionMemo, - psbtBase64: psbt.toBase64(), - walletID: wallet.getID(), - }); + const _importTransactionMultisig = useCallback( + async (base64arg: string | false) => { + try { + const base64 = base64arg || (await fs.openSignedTransaction()); + if (!base64) return; + const psbt = bitcoin.Psbt.fromBase64(base64); // if it doesnt throw - all good, its valid + + if ((wallet as MultisigHDWallet)?.howManySignaturesCanWeMake() > 0 && (await askCosignThisTransaction())) { + hideOptions(); + setIsLoading(true); + await sleep(100); + (wallet as MultisigHDWallet).cosignPsbt(psbt); + setIsLoading(false); + await sleep(100); + } + + if (wallet) { + navigation.navigate('PsbtMultisig', { + memo: transactionMemo, + psbtBase64: psbt.toBase64(), + walletID: wallet.getID(), + }); + } + } catch (error: any) { + presentAlert({ title: loc.send.problem_with_psbt, message: error.message }); } - } catch (error: any) { - presentAlert({ title: loc.send.problem_with_psbt, message: error.message }); - } - setIsLoading(false); - setOptionsVisible(false); - }; + setIsLoading(false); + setOptionsVisible(false); + }, + [wallet, hideOptions, sleep, navigation, transactionMemo], + ); - const importTransactionMultisig = () => { + const importTransactionMultisig = useCallback(() => { return _importTransactionMultisig(false); - }; - - const onBarScanned = (ret: any) => { - navigation.getParent()?.dispatch(popAction); - if (!ret.data) ret = { data: ret }; - if (ret.data.toUpperCase().startsWith('UR')) { - presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); - } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { - // this looks like NOT base64, so maybe its transaction's hex - // we dont support it in this flow - } else { - // psbt base64? - return _importTransactionMultisig(ret.data); - } - }; + }, [_importTransactionMultisig]); + + const onBarScanned = useCallback( + (ret: any) => { + navigation.getParent()?.dispatch(popAction); + if (!ret.data) ret = { data: ret }; + if (ret.data.toUpperCase().startsWith('UR')) { + presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); + } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { + // this looks like NOT base64, so maybe its transaction's hex + // we dont support it in this flow + } else { + // psbt base64? + return _importTransactionMultisig(ret.data); + } + }, + [navigation, popAction, _importTransactionMultisig], + ); - const importTransactionMultisigScanQr = () => { + const importTransactionMultisigScanQr = useCallback(() => { setOptionsVisible(false); requestCameraAuthorization().then(() => { navigation.navigate('ScanQRCodeRoot', { @@ -873,9 +888,9 @@ const SendDetails = () => { }, }); }); - }; + }, [navigation, onBarScanned]); - const handleAddRecipient = async () => { + const handleAddRecipient = useCallback(async () => { console.log('handleAddRecipient'); setAddresses(addrs => [...addrs, { address: '', key: String(Math.random()) } as IPaymentDestinations]); setOptionsVisible(false); @@ -883,9 +898,9 @@ const SendDetails = () => { scrollView.current?.scrollToEnd(); if (addresses.length === 0) return; scrollView.current?.flashScrollIndicators(); - }; + }, [addresses.length, sleep]); - const handleRemoveRecipient = async () => { + const handleRemoveRecipient = useCallback(async () => { const last = scrollIndex.current === addresses.length - 1; LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); setAddresses(addrs => { @@ -897,24 +912,24 @@ const SendDetails = () => { await sleep(200); // wait for animation scrollView.current?.flashScrollIndicators(); if (last && Platform.OS === 'android') scrollView.current?.scrollToEnd(); // fix white screen on android - }; + }, [addresses.length, sleep]); - const handleCoinControl = () => { + const handleCoinControl = useCallback(() => { if (!wallet) return; setOptionsVisible(false); navigation.navigate('CoinControl', { walletID: wallet?.getID(), onUTXOChoose: (u: CreateTransactionUtxo[]) => setUtxo(u), }); - }; + }, [wallet, setOptionsVisible, navigation]); - const handleInsertContact = () => { + const handleInsertContact = useCallback(() => { if (!wallet) return; setOptionsVisible(false); navigation.navigate('PaymentCodeList', { walletID: wallet.getID() }); - }; + }, [wallet, navigation, setOptionsVisible]); - const handlePsbtSign = async () => { + const handlePsbtSign = useCallback(async () => { setIsLoading(true); setOptionsVisible(false); await new Promise(resolve => setTimeout(resolve, 100)); // sleep for animations @@ -954,142 +969,161 @@ const SendDetails = () => { showAnimatedQr: true, psbt, }); - }; + }, [name, navigation, wallet]); - const hideOptions = () => { - Keyboard.dismiss(); - setOptionsVisible(false); - }; + const onUseAllPressed = useCallback(() => { + triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning); + const message = frozenBalance > 0 ? loc.send.details_adv_full_sure_frozen : loc.send.details_adv_full_sure; + Alert.alert( + loc.send.details_adv_full, + message, + [ + { + text: loc._.ok, + onPress: () => { + Keyboard.dismiss(); + setAddresses(addrs => { + addrs[scrollIndex.current].amount = BitcoinUnit.MAX; + addrs[scrollIndex.current].amountSats = BitcoinUnit.MAX; + return [...addrs]; + }); + setUnits(u => { + u[scrollIndex.current] = BitcoinUnit.BTC; + return [...u]; + }); + LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); + setOptionsVisible(false); + }, + style: 'default', + }, + { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, + ], + { cancelable: false }, + ); + }, [frozenBalance]); // Header Right Button - const headerRightOnPress = (id: string) => { - if (id === SendDetails.actionKeys.AddRecipient) { - handleAddRecipient(); - } else if (id === SendDetails.actionKeys.RemoveRecipient) { - handleRemoveRecipient(); - } else if (id === SendDetails.actionKeys.SignPSBT) { - handlePsbtSign(); - } else if (id === SendDetails.actionKeys.SendMax) { - onUseAllPressed(); - } else if (id === SendDetails.actionKeys.AllowRBF) { - onReplaceableFeeSwitchValueChanged(!isTransactionReplaceable); - } else if (id === SendDetails.actionKeys.ImportTransaction) { - importTransaction(); - } else if (id === SendDetails.actionKeys.ImportTransactionQR) { - importQrTransaction(); - } else if (id === SendDetails.actionKeys.ImportTransactionMultsig) { - importTransactionMultisig(); - } else if (id === SendDetails.actionKeys.CoSignTransaction) { - importTransactionMultisigScanQr(); - } else if (id === SendDetails.actionKeys.CoinControl) { - handleCoinControl(); - } else if (id === SendDetails.actionKeys.InsertContact) { - handleInsertContact(); - } - }; + const headerRightOnPress = useCallback( + (id: string) => { + if (id === actionKeys.AddRecipient) { + handleAddRecipient(); + } else if (id === actionKeys.RemoveRecipient) { + handleRemoveRecipient(); + } else if (id === actionKeys.SignPSBT) { + handlePsbtSign(); + } else if (id === actionKeys.SendMax) { + onUseAllPressed(); + } else if (id === actionKeys.AllowRBF) { + onReplaceableFeeSwitchValueChanged(!isTransactionReplaceable); + } else if (id === actionKeys.ImportTransaction) { + importTransaction(); + } else if (id === actionKeys.ImportTransactionQR) { + importQrTransaction(); + } else if (id === actionKeys.ImportTransactionMultsig) { + importTransactionMultisig(); + } else if (id === actionKeys.CoSignTransaction) { + importTransactionMultisigScanQr(); + } else if (id === actionKeys.CoinControl) { + handleCoinControl(); + } else if (id === actionKeys.InsertContact) { + handleInsertContact(); + } + }, + [ + handleAddRecipient, + handleCoinControl, + handleInsertContact, + handlePsbtSign, + handleRemoveRecipient, + importQrTransaction, + importTransaction, + importTransactionMultisig, + importTransactionMultisigScanQr, + isTransactionReplaceable, + onUseAllPressed, + ], + ); - const headerRightActions = () => { - const actions = []; + const headerRightActions = useCallback(() => { + const actions: Action[] & Action[][] = []; if (isEditable) { if (wallet?.allowBIP47() && wallet?.isBIP47Enabled()) { - actions.push([ - { id: SendDetails.actionKeys.InsertContact, text: loc.send.details_insert_contact, icon: SendDetails.actionIcons.InsertContact }, - ]); + actions.push([{ id: actionKeys.InsertContact, text: loc.send.details_insert_contact, icon: actionIcons.InsertContact }]); } if (Number(wallet?.getBalance()) > 0) { const isSendMaxUsed = addresses.some(element => element.amount === BitcoinUnit.MAX); - actions.push([{ id: SendDetails.actionKeys.SendMax, text: loc.send.details_adv_full, disabled: balance === 0 || isSendMaxUsed }]); + actions.push([{ id: actionKeys.SendMax, text: loc.send.details_adv_full, disabled: balance === 0 || isSendMaxUsed }]); } if (wallet?.type === HDSegwitBech32Wallet.type) { - actions.push([{ id: SendDetails.actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuStateOn: isTransactionReplaceable }]); + actions.push([{ id: actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuStateOn: isTransactionReplaceable }]); } const transactionActions = []; if (wallet?.type === WatchOnlyWallet.type && wallet.isHd()) { transactionActions.push( { - id: SendDetails.actionKeys.ImportTransaction, + id: actionKeys.ImportTransaction, text: loc.send.details_adv_import, - icon: SendDetails.actionIcons.ImportTransaction, + icon: actionIcons.ImportTransaction, }, { - id: SendDetails.actionKeys.ImportTransactionQR, + id: actionKeys.ImportTransactionQR, text: loc.send.details_adv_import_qr, - icon: SendDetails.actionIcons.ImportTransactionQR, + icon: actionIcons.ImportTransactionQR, }, ); } if (wallet?.type === MultisigHDWallet.type) { transactionActions.push({ - id: SendDetails.actionKeys.ImportTransactionMultsig, + id: actionKeys.ImportTransactionMultsig, text: loc.send.details_adv_import, - icon: SendDetails.actionIcons.ImportTransactionMultsig, + icon: actionIcons.ImportTransactionMultsig, }); } if (wallet?.type === MultisigHDWallet.type && wallet.howManySignaturesCanWeMake() > 0) { transactionActions.push({ - id: SendDetails.actionKeys.CoSignTransaction, + id: actionKeys.CoSignTransaction, text: loc.multisig.co_sign_transaction, - icon: SendDetails.actionIcons.SignPSBT, + icon: actionIcons.SignPSBT, }); } if ((wallet as MultisigHDWallet)?.allowCosignPsbt()) { - transactionActions.push({ id: SendDetails.actionKeys.SignPSBT, text: loc.send.psbt_sign, icon: SendDetails.actionIcons.SignPSBT }); + transactionActions.push({ id: actionKeys.SignPSBT, text: loc.send.psbt_sign, icon: actionIcons.SignPSBT }); } actions.push(transactionActions, [ { - id: SendDetails.actionKeys.AddRecipient, + id: actionKeys.AddRecipient, text: loc.send.details_add_rec_add, - icon: SendDetails.actionIcons.AddRecipient, + icon: actionIcons.AddRecipient, }, { - id: SendDetails.actionKeys.RemoveRecipient, + id: actionKeys.RemoveRecipient, text: loc.send.details_add_rec_rem, disabled: addresses.length < 2, - icon: SendDetails.actionIcons.RemoveRecipient, + icon: actionIcons.RemoveRecipient, }, ]); } - actions.push({ id: SendDetails.actionKeys.CoinControl, text: loc.cc.header, icon: SendDetails.actionIcons.CoinControl }); + actions.push({ id: actionKeys.CoinControl, text: loc.cc.header, icon: actionIcons.CoinControl }); return actions; - }; + }, [isEditable, wallet, addresses, balance, isTransactionReplaceable]); + + const HeaderRight = useMemo( + () => ( + + + + ), + [isLoading, headerRightOnPress, headerRightActions, colors.foregroundColor], + ); + const setHeaderRightOptions = () => { navigation.setOptions({ - headerRight: Platform.select({ - // eslint-disable-next-line react/no-unstable-nested-components - ios: () => ( - - - - ), - // eslint-disable-next-line react/no-unstable-nested-components - default: () => ( - { - Keyboard.dismiss(); - setOptionsVisible(true); - }} - testID="advancedOptionsMenuButton" - > - - - ), - }), + headerRight: () => HeaderRight, }); }; @@ -1117,37 +1151,6 @@ const SendDetails = () => { scrollIndex.current = index; }; - const onUseAllPressed = () => { - triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning); - const message = frozenBalance > 0 ? loc.send.details_adv_full_sure_frozen : loc.send.details_adv_full_sure; - Alert.alert( - loc.send.details_adv_full, - message, - [ - { - text: loc._.ok, - onPress: () => { - Keyboard.dismiss(); - setAddresses(addrs => { - addrs[scrollIndex.current].amount = BitcoinUnit.MAX; - addrs[scrollIndex.current].amountSats = BitcoinUnit.MAX; - return [...addrs]; - }); - setUnits(u => { - u[scrollIndex.current] = BitcoinUnit.BTC; - return [...u]; - }); - LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); - setOptionsVisible(false); - }, - style: 'default', - }, - { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, - ], - { cancelable: false }, - ); - }; - const formatFee = (fee: number) => formatBalance(fee, feeUnit!, true); const stylesHook = StyleSheet.create({ @@ -1605,7 +1608,7 @@ const SendDetails = () => { export default SendDetails; -SendDetails.actionKeys = { +const actionKeys = { InsertContact: 'InsertContact', SignPSBT: 'SignPSBT', SendMax: 'SendMax', @@ -1619,7 +1622,7 @@ SendDetails.actionKeys = { CoSignTransaction: 'CoSignTransaction', }; -SendDetails.actionIcons = { +const actionIcons = { InsertContact: { iconType: 'SYSTEM', iconValue: 'at.badge.plus' }, SignPSBT: { iconType: 'SYSTEM', iconValue: 'signature' }, SendMax: 'SendMax', From 5e78d8f2b33349bd24614d958778e53684dcc9f9 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 16 Jun 2024 22:33:10 -0400 Subject: [PATCH 11/37] Update setup.js --- tests/setup.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/setup.js b/tests/setup.js index 9dcf23b512..1b5f603abe 100644 --- a/tests/setup.js +++ b/tests/setup.js @@ -200,6 +200,4 @@ jest.mock('react-native-keychain', () => mockKeychain); jest.mock('react-native-tcp-socket', () => mockKeychain); -jest.mock('../components/TooltipMenu.ios.tsx', () => require('../components/TooltipMenu.tsx')); - global.alert = () => {}; From 7d611f7189bbaaee7602c7da75dd5d934d2437ec Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sun, 16 Jun 2024 22:41:13 -0400 Subject: [PATCH 12/37] Update TransactionListItem.tsx --- components/TransactionListItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/TransactionListItem.tsx b/components/TransactionListItem.tsx index e2fc0fce36..be54d54516 100644 --- a/components/TransactionListItem.tsx +++ b/components/TransactionListItem.tsx @@ -16,12 +16,12 @@ import { BitcoinUnit } from '../models/bitcoinUnits'; import { useSettings } from '../hooks/context/useSettings'; import ListItem from './ListItem'; import { useTheme } from './themes'; -import ToolTipMenu from './TooltipMenu'; import { Action, ToolTipMenuProps } from './types'; import { useExtendedNavigation } from '../hooks/useExtendedNavigation'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { DetailViewStackParamList } from '../navigation/DetailViewStackParamList'; import { useStorage } from '../hooks/context/useStorage'; +import ToolTipMenu from './TooltipMenu'; interface TransactionListItemProps { itemPriceUnit: BitcoinUnit; @@ -339,7 +339,7 @@ export const TransactionListItem: React.FC = React.mem // eslint-disable-next-line react-hooks/exhaustive-deps }, [item.hash, subtitle, rowTitle, subtitleNumberOfLines, txMetadata]); return ( - + Date: Mon, 17 Jun 2024 10:56:06 -0400 Subject: [PATCH 13/37] FIX: Test --- components/TooltipMenu.tsx | 9 +++----- components/TransactionsNavigationHeader.tsx | 6 ++--- components/addresses/AddressItem.tsx | 21 +++++------------ loc/en.json | 1 + screen/send/SendDetails.tsx | 25 ++++++++++++++++----- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/components/TooltipMenu.tsx b/components/TooltipMenu.tsx index 4d309afe77..93240927c6 100644 --- a/components/TooltipMenu.tsx +++ b/components/TooltipMenu.tsx @@ -1,10 +1,10 @@ -import React, { forwardRef, Ref, useCallback, useMemo } from 'react'; +import React, { Ref, useCallback, useMemo } from 'react'; import { Platform, Pressable, TouchableOpacity, View } from 'react-native'; import { ContextMenuView, RenderItem, OnPressMenuItemEventObject, MenuState, IconConfig } from 'react-native-ios-context-menu'; import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu'; import { ToolTipMenuProps, Action } from './types'; -const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref) => { +const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref) => { const { title = '', isMenuPrimaryAction = false, @@ -83,7 +83,6 @@ const BaseToolTipMenu = (props: ToolTipMenuProps, ref: Ref) => { console.debug('ToolTipMenu.tsx rendering: renderContextMenuView'); return ( ) => { }; return Platform.OS === 'ios' && renderPreview ? renderContextMenuView() : renderMenuView(); -}; - -const ToolTipMenu = forwardRef(BaseToolTipMenu); +}); export default ToolTipMenu; diff --git a/components/TransactionsNavigationHeader.tsx b/components/TransactionsNavigationHeader.tsx index 386a5b138b..54f4dcb13f 100644 --- a/components/TransactionsNavigationHeader.tsx +++ b/components/TransactionsNavigationHeader.tsx @@ -1,8 +1,7 @@ -import Clipboard from '@react-native-clipboard/clipboard'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import Clipboard from '@react-native-clipboard/clipboard'; import { I18nManager, Image, LayoutAnimation, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; - import { LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet } from '../class'; import WalletGradient from '../class/wallet-gradient'; import { TWallet } from '../class/wallets/types'; @@ -11,8 +10,8 @@ import { BitcoinUnit } from '../models/bitcoinUnits'; import { FiatUnit } from '../models/fiatUnit'; import { BlurredBalanceView } from './BlurredBalanceView'; import { useSettings } from '../hooks/context/useSettings'; -import ToolTipMenu from './TooltipMenu'; import { ToolTipMenuProps } from './types'; +import ToolTipMenu from './TooltipMenu'; interface TransactionsNavigationHeaderProps { wallet: TWallet; @@ -155,7 +154,6 @@ const TransactionsNavigationHeader: React.FC isMenuPrimaryAction isButton enableAndroidRipple={false} - ref={menuRef} buttonStyle={styles.walletBalance} onPressMenuItem={onPressMenuItem} actions={ diff --git a/components/addresses/AddressItem.tsx b/components/addresses/AddressItem.tsx index 20821906ab..eb06663994 100644 --- a/components/addresses/AddressItem.tsx +++ b/components/addresses/AddressItem.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useRef } from 'react'; +import React, { useMemo } from 'react'; import Clipboard from '@react-native-clipboard/clipboard'; import { useNavigation } from '@react-navigation/native'; import { StyleSheet, Text, View } from 'react-native'; @@ -12,12 +12,12 @@ import { BitcoinUnit } from '../../models/bitcoinUnits'; import presentAlert from '../Alert'; import QRCodeComponent from '../QRCodeComponent'; import { useTheme } from '../themes'; -import TooltipMenu from '../TooltipMenu'; -import { Action, ToolTipMenuProps } from '../types'; +import { Action } from '../types'; import { AddressTypeBadge } from './AddressTypeBadge'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList'; import { useStorage } from '../../hooks/context/useStorage'; +import ToolTipMenu from '../TooltipMenu'; interface AddressItemProps { // todo: fix `any` after addresses.js is converted to the church of holy typescript @@ -57,16 +57,7 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad const { navigate } = useNavigation(); - const menuRef = useRef(); - - const dismissMenu = () => { - if (menuRef.current?.dismissMenu) { - menuRef.current.dismissMenu(); - } - }; - const navigateToReceive = () => { - dismissMenu(); navigate('ReceiveDetailsRoot', { screen: 'ReceiveDetails', params: { @@ -77,7 +68,6 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad }; const navigateToSignVerify = () => { - dismissMenu(); navigate('SignVerifyRoot', { screen: 'SignVerify', params: { @@ -145,9 +135,8 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad const render = () => { return ( - - + ); }; diff --git a/loc/en.json b/loc/en.json index ef523da2ef..c9ca242bde 100644 --- a/loc/en.json +++ b/loc/en.json @@ -21,6 +21,7 @@ "close": "Close", "change_input_currency": "Change input currency", "refresh": "Refresh", + "more": "More", "pick_image": "Choose image from library", "pick_file": "Choose a file", "enter_amount": "Enter amount", diff --git a/screen/send/SendDetails.tsx b/screen/send/SendDetails.tsx index 9bcb5e9598..1c63e96732 100644 --- a/screen/send/SendDetails.tsx +++ b/screen/send/SendDetails.tsx @@ -1113,11 +1113,26 @@ const SendDetails = () => { }, [isEditable, wallet, addresses, balance, isTransactionReplaceable]); const HeaderRight = useMemo( - () => ( - - - - ), + () => + Platform.OS === 'ios' ? ( + + + + ) : ( + { + Keyboard.dismiss(); + setOptionsVisible(true); + }} + testID="advancedOptionsMenuButton" + > + + + ), [isLoading, headerRightOnPress, headerRightActions, colors.foregroundColor], ); From 58d728a1076f4a1996ffda32c9aa7b81e9659009 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 14:27:45 -0400 Subject: [PATCH 14/37] Update SendDetails.tsx --- screen/send/SendDetails.tsx | 411 +++++++++++++++++------------------- 1 file changed, 197 insertions(+), 214 deletions(-) diff --git a/screen/send/SendDetails.tsx b/screen/send/SendDetails.tsx index 1c63e96732..663c6174e2 100644 --- a/screen/send/SendDetails.tsx +++ b/screen/send/SendDetails.tsx @@ -687,40 +687,12 @@ const SendDetails = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [routeParams.walletID]); - const importQrTransactionOnBarScanned = useCallback( - (ret: any) => { - navigation.getParent()?.getParent()?.dispatch(popAction); - if (!wallet) return; - if (!ret.data) ret = { data: ret }; - if (ret.data.toUpperCase().startsWith('UR')) { - presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); - } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { - // this looks like NOT base64, so maybe its transaction's hex - // we dont support it in this flow - } else { - // psbt base64? - - // we construct PSBT object and pass to next screen - // so user can do smth with it: - const psbt = bitcoin.Psbt.fromBase64(ret.data); - navigation.navigate('PsbtWithHardwareWallet', { - memo: transactionMemo, - fromWallet: wallet, - psbt, - }); - setIsLoading(false); - setOptionsVisible(false); - } - }, - [navigation, popAction, wallet, transactionMemo], - ); - /** * same as `importTransaction`, but opens camera instead. * * @returns {Promise} */ - const importQrTransaction = useCallback(() => { + const importQrTransaction = () => { if (wallet?.type !== WatchOnlyWallet.type) { return presentAlert({ title: loc.errors.error, message: 'Importing transaction in non-watchonly wallet (this should never happen)' }); } @@ -735,7 +707,32 @@ const SendDetails = () => { }, }); }); - }, [wallet?.type, navigation, importQrTransactionOnBarScanned]); + }; + + const importQrTransactionOnBarScanned = (ret: any) => { + navigation.getParent()?.getParent()?.dispatch(popAction); + if (!wallet) return; + if (!ret.data) ret = { data: ret }; + if (ret.data.toUpperCase().startsWith('UR')) { + presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); + } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { + // this looks like NOT base64, so maybe its transaction's hex + // we dont support it in this flow + } else { + // psbt base64? + + // we construct PSBT object and pass to next screen + // so user can do smth with it: + const psbt = bitcoin.Psbt.fromBase64(ret.data); + navigation.navigate('PsbtWithHardwareWallet', { + memo: transactionMemo, + fromWallet: wallet, + psbt, + }); + setIsLoading(false); + setOptionsVisible(false); + } + }; /** * watch-only wallets with enabled HW wallet support have different flow. we have to show PSBT to user as QR code @@ -745,7 +742,7 @@ const SendDetails = () => { * * @returns {Promise} */ - const importTransaction = useCallback(async () => { + const importTransaction = async () => { if (wallet?.type !== WatchOnlyWallet.type) { return presentAlert({ title: loc.errors.error, message: 'Importing transaction in non-watchonly wallet (this should never happen)' }); } @@ -796,7 +793,7 @@ const SendDetails = () => { presentAlert({ title: loc.errors.error, message: loc.send.details_no_signed_tx }); } } - }, [wallet, navigation, transactionMemo]); + }; const askCosignThisTransaction = async () => { return new Promise(resolve => { @@ -819,65 +816,54 @@ const SendDetails = () => { }); }; - const hideOptions = useCallback(() => { - Keyboard.dismiss(); - setOptionsVisible(false); - }, []); - - const _importTransactionMultisig = useCallback( - async (base64arg: string | false) => { - try { - const base64 = base64arg || (await fs.openSignedTransaction()); - if (!base64) return; - const psbt = bitcoin.Psbt.fromBase64(base64); // if it doesnt throw - all good, its valid - - if ((wallet as MultisigHDWallet)?.howManySignaturesCanWeMake() > 0 && (await askCosignThisTransaction())) { - hideOptions(); - setIsLoading(true); - await sleep(100); - (wallet as MultisigHDWallet).cosignPsbt(psbt); - setIsLoading(false); - await sleep(100); - } + const _importTransactionMultisig = async (base64arg: string | false) => { + try { + const base64 = base64arg || (await fs.openSignedTransaction()); + if (!base64) return; + const psbt = bitcoin.Psbt.fromBase64(base64); // if it doesnt throw - all good, its valid + + if ((wallet as MultisigHDWallet)?.howManySignaturesCanWeMake() > 0 && (await askCosignThisTransaction())) { + hideOptions(); + setIsLoading(true); + await sleep(100); + (wallet as MultisigHDWallet).cosignPsbt(psbt); + setIsLoading(false); + await sleep(100); + } - if (wallet) { - navigation.navigate('PsbtMultisig', { - memo: transactionMemo, - psbtBase64: psbt.toBase64(), - walletID: wallet.getID(), - }); - } - } catch (error: any) { - presentAlert({ title: loc.send.problem_with_psbt, message: error.message }); + if (wallet) { + navigation.navigate('PsbtMultisig', { + memo: transactionMemo, + psbtBase64: psbt.toBase64(), + walletID: wallet.getID(), + }); } - setIsLoading(false); - setOptionsVisible(false); - }, - [wallet, hideOptions, sleep, navigation, transactionMemo], - ); + } catch (error: any) { + presentAlert({ title: loc.send.problem_with_psbt, message: error.message }); + } + setIsLoading(false); + setOptionsVisible(false); + }; - const importTransactionMultisig = useCallback(() => { + const importTransactionMultisig = () => { return _importTransactionMultisig(false); - }, [_importTransactionMultisig]); - - const onBarScanned = useCallback( - (ret: any) => { - navigation.getParent()?.dispatch(popAction); - if (!ret.data) ret = { data: ret }; - if (ret.data.toUpperCase().startsWith('UR')) { - presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); - } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { - // this looks like NOT base64, so maybe its transaction's hex - // we dont support it in this flow - } else { - // psbt base64? - return _importTransactionMultisig(ret.data); - } - }, - [navigation, popAction, _importTransactionMultisig], - ); + }; - const importTransactionMultisigScanQr = useCallback(() => { + const onBarScanned = (ret: any) => { + navigation.getParent()?.dispatch(popAction); + if (!ret.data) ret = { data: ret }; + if (ret.data.toUpperCase().startsWith('UR')) { + presentAlert({ title: loc.errors.error, message: 'BC-UR not decoded. This should never happen' }); + } else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) { + // this looks like NOT base64, so maybe its transaction's hex + // we dont support it in this flow + } else { + // psbt base64? + return _importTransactionMultisig(ret.data); + } + }; + + const importTransactionMultisigScanQr = () => { setOptionsVisible(false); requestCameraAuthorization().then(() => { navigation.navigate('ScanQRCodeRoot', { @@ -888,9 +874,9 @@ const SendDetails = () => { }, }); }); - }, [navigation, onBarScanned]); + }; - const handleAddRecipient = useCallback(async () => { + const handleAddRecipient = async () => { console.log('handleAddRecipient'); setAddresses(addrs => [...addrs, { address: '', key: String(Math.random()) } as IPaymentDestinations]); setOptionsVisible(false); @@ -898,9 +884,9 @@ const SendDetails = () => { scrollView.current?.scrollToEnd(); if (addresses.length === 0) return; scrollView.current?.flashScrollIndicators(); - }, [addresses.length, sleep]); + }; - const handleRemoveRecipient = useCallback(async () => { + const handleRemoveRecipient = async () => { const last = scrollIndex.current === addresses.length - 1; LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); setAddresses(addrs => { @@ -912,24 +898,24 @@ const SendDetails = () => { await sleep(200); // wait for animation scrollView.current?.flashScrollIndicators(); if (last && Platform.OS === 'android') scrollView.current?.scrollToEnd(); // fix white screen on android - }, [addresses.length, sleep]); + }; - const handleCoinControl = useCallback(() => { + const handleCoinControl = () => { if (!wallet) return; setOptionsVisible(false); navigation.navigate('CoinControl', { walletID: wallet?.getID(), onUTXOChoose: (u: CreateTransactionUtxo[]) => setUtxo(u), }); - }, [wallet, setOptionsVisible, navigation]); + }; - const handleInsertContact = useCallback(() => { + const handleInsertContact = () => { if (!wallet) return; setOptionsVisible(false); navigation.navigate('PaymentCodeList', { walletID: wallet.getID() }); - }, [wallet, navigation, setOptionsVisible]); + }; - const handlePsbtSign = useCallback(async () => { + const handlePsbtSign = async () => { setIsLoading(true); setOptionsVisible(false); await new Promise(resolve => setTimeout(resolve, 100)); // sleep for animations @@ -969,176 +955,142 @@ const SendDetails = () => { showAnimatedQr: true, psbt, }); - }, [name, navigation, wallet]); + }; - const onUseAllPressed = useCallback(() => { - triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning); - const message = frozenBalance > 0 ? loc.send.details_adv_full_sure_frozen : loc.send.details_adv_full_sure; - Alert.alert( - loc.send.details_adv_full, - message, - [ - { - text: loc._.ok, - onPress: () => { - Keyboard.dismiss(); - setAddresses(addrs => { - addrs[scrollIndex.current].amount = BitcoinUnit.MAX; - addrs[scrollIndex.current].amountSats = BitcoinUnit.MAX; - return [...addrs]; - }); - setUnits(u => { - u[scrollIndex.current] = BitcoinUnit.BTC; - return [...u]; - }); - LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); - setOptionsVisible(false); - }, - style: 'default', - }, - { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, - ], - { cancelable: false }, - ); - }, [frozenBalance]); + const hideOptions = () => { + Keyboard.dismiss(); + setOptionsVisible(false); + }; // Header Right Button - const headerRightOnPress = useCallback( - (id: string) => { - if (id === actionKeys.AddRecipient) { - handleAddRecipient(); - } else if (id === actionKeys.RemoveRecipient) { - handleRemoveRecipient(); - } else if (id === actionKeys.SignPSBT) { - handlePsbtSign(); - } else if (id === actionKeys.SendMax) { - onUseAllPressed(); - } else if (id === actionKeys.AllowRBF) { - onReplaceableFeeSwitchValueChanged(!isTransactionReplaceable); - } else if (id === actionKeys.ImportTransaction) { - importTransaction(); - } else if (id === actionKeys.ImportTransactionQR) { - importQrTransaction(); - } else if (id === actionKeys.ImportTransactionMultsig) { - importTransactionMultisig(); - } else if (id === actionKeys.CoSignTransaction) { - importTransactionMultisigScanQr(); - } else if (id === actionKeys.CoinControl) { - handleCoinControl(); - } else if (id === actionKeys.InsertContact) { - handleInsertContact(); - } - }, - [ - handleAddRecipient, - handleCoinControl, - handleInsertContact, - handlePsbtSign, - handleRemoveRecipient, - importQrTransaction, - importTransaction, - importTransactionMultisig, - importTransactionMultisigScanQr, - isTransactionReplaceable, - onUseAllPressed, - ], - ); + const headerRightOnPress = (id: string) => { + if (id === SendDetails.actionKeys.AddRecipient) { + handleAddRecipient(); + } else if (id === SendDetails.actionKeys.RemoveRecipient) { + handleRemoveRecipient(); + } else if (id === SendDetails.actionKeys.SignPSBT) { + handlePsbtSign(); + } else if (id === SendDetails.actionKeys.SendMax) { + onUseAllPressed(); + } else if (id === SendDetails.actionKeys.AllowRBF) { + onReplaceableFeeSwitchValueChanged(!isTransactionReplaceable); + } else if (id === SendDetails.actionKeys.ImportTransaction) { + importTransaction(); + } else if (id === SendDetails.actionKeys.ImportTransactionQR) { + importQrTransaction(); + } else if (id === SendDetails.actionKeys.ImportTransactionMultsig) { + importTransactionMultisig(); + } else if (id === SendDetails.actionKeys.CoSignTransaction) { + importTransactionMultisigScanQr(); + } else if (id === SendDetails.actionKeys.CoinControl) { + handleCoinControl(); + } else if (id === SendDetails.actionKeys.InsertContact) { + handleInsertContact(); + } + }; - const headerRightActions = useCallback(() => { + const headerRightActions = () => { const actions: Action[] & Action[][] = []; if (isEditable) { if (wallet?.allowBIP47() && wallet?.isBIP47Enabled()) { - actions.push([{ id: actionKeys.InsertContact, text: loc.send.details_insert_contact, icon: actionIcons.InsertContact }]); + actions.push([ + { id: SendDetails.actionKeys.InsertContact, text: loc.send.details_insert_contact, icon: SendDetails.actionIcons.InsertContact }, + ]); } if (Number(wallet?.getBalance()) > 0) { const isSendMaxUsed = addresses.some(element => element.amount === BitcoinUnit.MAX); - actions.push([{ id: actionKeys.SendMax, text: loc.send.details_adv_full, disabled: balance === 0 || isSendMaxUsed }]); + actions.push([{ id: SendDetails.actionKeys.SendMax, text: loc.send.details_adv_full, disabled: balance === 0 || isSendMaxUsed }]); } if (wallet?.type === HDSegwitBech32Wallet.type) { - actions.push([{ id: actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuStateOn: isTransactionReplaceable }]); + actions.push([{ id: SendDetails.actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuStateOn: isTransactionReplaceable }]); } const transactionActions = []; if (wallet?.type === WatchOnlyWallet.type && wallet.isHd()) { transactionActions.push( { - id: actionKeys.ImportTransaction, + id: SendDetails.actionKeys.ImportTransaction, text: loc.send.details_adv_import, - icon: actionIcons.ImportTransaction, + icon: SendDetails.actionIcons.ImportTransaction, }, { - id: actionKeys.ImportTransactionQR, + id: SendDetails.actionKeys.ImportTransactionQR, text: loc.send.details_adv_import_qr, - icon: actionIcons.ImportTransactionQR, + icon: SendDetails.actionIcons.ImportTransactionQR, }, ); } if (wallet?.type === MultisigHDWallet.type) { transactionActions.push({ - id: actionKeys.ImportTransactionMultsig, + id: SendDetails.actionKeys.ImportTransactionMultsig, text: loc.send.details_adv_import, - icon: actionIcons.ImportTransactionMultsig, + icon: SendDetails.actionIcons.ImportTransactionMultsig, }); } if (wallet?.type === MultisigHDWallet.type && wallet.howManySignaturesCanWeMake() > 0) { transactionActions.push({ - id: actionKeys.CoSignTransaction, + id: SendDetails.actionKeys.CoSignTransaction, text: loc.multisig.co_sign_transaction, - icon: actionIcons.SignPSBT, + icon: SendDetails.actionIcons.SignPSBT, }); } if ((wallet as MultisigHDWallet)?.allowCosignPsbt()) { - transactionActions.push({ id: actionKeys.SignPSBT, text: loc.send.psbt_sign, icon: actionIcons.SignPSBT }); + transactionActions.push({ id: SendDetails.actionKeys.SignPSBT, text: loc.send.psbt_sign, icon: SendDetails.actionIcons.SignPSBT }); } actions.push(transactionActions, [ { - id: actionKeys.AddRecipient, + id: SendDetails.actionKeys.AddRecipient, text: loc.send.details_add_rec_add, - icon: actionIcons.AddRecipient, + icon: SendDetails.actionIcons.AddRecipient, }, { - id: actionKeys.RemoveRecipient, + id: SendDetails.actionKeys.RemoveRecipient, text: loc.send.details_add_rec_rem, disabled: addresses.length < 2, - icon: actionIcons.RemoveRecipient, + icon: SendDetails.actionIcons.RemoveRecipient, }, ]); } - actions.push({ id: actionKeys.CoinControl, text: loc.cc.header, icon: actionIcons.CoinControl }); + actions.push({ id: SendDetails.actionKeys.CoinControl, text: loc.cc.header, icon: SendDetails.actionIcons.CoinControl }); return actions; - }, [isEditable, wallet, addresses, balance, isTransactionReplaceable]); - - const HeaderRight = useMemo( - () => - Platform.OS === 'ios' ? ( - - - - ) : ( - { - Keyboard.dismiss(); - setOptionsVisible(true); - }} - testID="advancedOptionsMenuButton" - > - - - ), - [isLoading, headerRightOnPress, headerRightActions, colors.foregroundColor], - ); - + }; const setHeaderRightOptions = () => { navigation.setOptions({ - headerRight: () => HeaderRight, + headerRight: Platform.select({ + // eslint-disable-next-line react/no-unstable-nested-components + ios: () => ( + + + + ), + // eslint-disable-next-line react/no-unstable-nested-components + default: () => ( + { + Keyboard.dismiss(); + setOptionsVisible(true); + }} + testID="advancedOptionsMenuButton" + > + + + ), + }), }); }; @@ -1166,6 +1118,37 @@ const SendDetails = () => { scrollIndex.current = index; }; + const onUseAllPressed = () => { + triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning); + const message = frozenBalance > 0 ? loc.send.details_adv_full_sure_frozen : loc.send.details_adv_full_sure; + Alert.alert( + loc.send.details_adv_full, + message, + [ + { + text: loc._.ok, + onPress: () => { + Keyboard.dismiss(); + setAddresses(addrs => { + addrs[scrollIndex.current].amount = BitcoinUnit.MAX; + addrs[scrollIndex.current].amountSats = BitcoinUnit.MAX; + return [...addrs]; + }); + setUnits(u => { + u[scrollIndex.current] = BitcoinUnit.BTC; + return [...u]; + }); + LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); + setOptionsVisible(false); + }, + style: 'default', + }, + { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, + ], + { cancelable: false }, + ); + }; + const formatFee = (fee: number) => formatBalance(fee, feeUnit!, true); const stylesHook = StyleSheet.create({ @@ -1623,7 +1606,7 @@ const SendDetails = () => { export default SendDetails; -const actionKeys = { +SendDetails.actionKeys = { InsertContact: 'InsertContact', SignPSBT: 'SignPSBT', SendMax: 'SendMax', @@ -1637,7 +1620,7 @@ const actionKeys = { CoSignTransaction: 'CoSignTransaction', }; -const actionIcons = { +SendDetails.actionIcons = { InsertContact: { iconType: 'SYSTEM', iconValue: 'at.badge.plus' }, SignPSBT: { iconType: 'SYSTEM', iconValue: 'signature' }, SendMax: 'SendMax', From 3bb42f689378352be553050b09008902dd4bd5ce Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 15:29:54 -0400 Subject: [PATCH 15/37] FIX: Deepscan --- components/AddressInput.tsx | 93 +++++++++++---------- components/TransactionsNavigationHeader.tsx | 25 +++--- 2 files changed, 62 insertions(+), 56 deletions(-) diff --git a/components/AddressInput.tsx b/components/AddressInput.tsx index 70b6335381..0370517965 100644 --- a/components/AddressInput.tsx +++ b/components/AddressInput.tsx @@ -1,13 +1,13 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { Image, Keyboard, StyleSheet, Text, TextInput, View } from 'react-native'; import { scanQrHelper } from '../helpers/scan-qr'; import loc from '../loc'; import { useTheme } from './themes'; -import ToolTipMenu from './TooltipMenu'; import { showFilePickerAndReadFile, showImagePickerAndReadImage } from '../blue_modules/fs'; import Clipboard from '@react-native-clipboard/clipboard'; import presentAlert from './Alert'; +import ToolTipMenu from './TooltipMenu'; interface AddressInputProps { isLoading?: boolean; @@ -69,52 +69,55 @@ const AddressInput = ({ Keyboard.dismiss(); }; - const onMenuItemPressed = (action: string) => { - if (onBarScanned === undefined) throw new Error('onBarScanned is required'); - switch (action) { - case actionKeys.ScanQR: - scanButtonTapped(); - if (launchedBy) { - scanQrHelper(launchedBy) - .then(value => onBarScanned({ data: value })) + const onMenuItemPressed = useCallback( + (action: string) => { + if (onBarScanned === undefined) throw new Error('onBarScanned is required'); + switch (action) { + case actionKeys.ScanQR: + scanButtonTapped(); + if (launchedBy) { + scanQrHelper(launchedBy) + .then(value => onBarScanned({ data: value })) + .catch(error => { + presentAlert({ message: error.message }); + }); + } + + break; + case actionKeys.CopyFromClipboard: + Clipboard.getString() + .then(onChangeText) .catch(error => { presentAlert({ message: error.message }); }); - } - - break; - case actionKeys.CopyFromClipboard: - Clipboard.getString() - .then(onChangeText) - .catch(error => { - presentAlert({ message: error.message }); - }); - break; - case actionKeys.ChoosePhoto: - showImagePickerAndReadImage() - .then(value => { - if (value) { - onChangeText(value); - } - }) - .catch(error => { - presentAlert({ message: error.message }); - }); - break; - case actionKeys.ImportFile: - showFilePickerAndReadFile() - .then(value => { - if (value.data) { - onChangeText(value.data); - } - }) - .catch(error => { - presentAlert({ message: error.message }); - }); - break; - } - Keyboard.dismiss(); - }; + break; + case actionKeys.ChoosePhoto: + showImagePickerAndReadImage() + .then(value => { + if (value) { + onChangeText(value); + } + }) + .catch(error => { + presentAlert({ message: error.message }); + }); + break; + case actionKeys.ImportFile: + showFilePickerAndReadFile() + .then(value => { + if (value.data) { + onChangeText(value.data); + } + }) + .catch(error => { + presentAlert({ message: error.message }); + }); + break; + } + Keyboard.dismiss(); + }, + [launchedBy, onBarScanned, onChangeText, scanButtonTapped], + ); return ( diff --git a/components/TransactionsNavigationHeader.tsx b/components/TransactionsNavigationHeader.tsx index 54f4dcb13f..d3d48033ac 100644 --- a/components/TransactionsNavigationHeader.tsx +++ b/components/TransactionsNavigationHeader.tsx @@ -63,16 +63,16 @@ const TransactionsNavigationHeader: React.FC verifyIfWalletAllowsOnchainAddress(); }, [wallet, verifyIfWalletAllowsOnchainAddress]); - const handleCopyPress = () => { + const handleCopyPress = useCallback(() => { const value = formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit()); if (value) { Clipboard.setString(value); } - }; + }, [wallet]); - const handleBalanceVisibility = () => { + const handleBalanceVisibility = useCallback(() => { onWalletBalanceVisibilityChange?.(!wallet.hideBalance); - }; + }, [onWalletBalanceVisibilityChange, wallet.hideBalance]); const updateWalletWithNewUnit = (w: TWallet, newPreferredUnit: BitcoinUnit) => { w.preferredBalanceUnit = newPreferredUnit; @@ -106,13 +106,16 @@ const TransactionsNavigationHeader: React.FC } }; - const onPressMenuItem = (id: string) => { - if (id === 'walletBalanceVisibility') { - handleBalanceVisibility(); - } else if (id === 'copyToClipboard') { - handleCopyPress(); - } - }; + const onPressMenuItem = useCallback( + (id: string) => { + if (id === 'walletBalanceVisibility') { + handleBalanceVisibility(); + } else if (id === 'copyToClipboard') { + handleCopyPress(); + } + }, + [handleBalanceVisibility, handleCopyPress], + ); const balance = useMemo(() => { const hideBalance = wallet.hideBalance; From 2a9f9b0def7be8308c6147c38dbb301414f3ab53 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 15:32:56 -0400 Subject: [PATCH 16/37] Update TransactionsNavigationHeader.tsx --- components/TransactionsNavigationHeader.tsx | 28 ++++++++++++--------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/components/TransactionsNavigationHeader.tsx b/components/TransactionsNavigationHeader.tsx index d3d48033ac..8ee0569697 100644 --- a/components/TransactionsNavigationHeader.tsx +++ b/components/TransactionsNavigationHeader.tsx @@ -117,6 +117,21 @@ const TransactionsNavigationHeader: React.FC [handleBalanceVisibility, handleCopyPress], ); + const toolTipActions = useMemo(() => { + return [ + { + id: actionKeys.Refill, + text: loc.lnd.refill, + icon: actionIcons.Refill, + }, + { + id: actionKeys.RefillWithExternalWallet, + text: loc.lnd.refill_external, + icon: actionIcons.RefillWithExternalWallet, + }, + ]; + }, []); + const balance = useMemo(() => { const hideBalance = wallet.hideBalance; const balanceUnit = wallet.getPreferredBalanceUnit(); @@ -224,18 +239,7 @@ const TransactionsNavigationHeader: React.FC isMenuPrimaryAction isButton onPressMenuItem={handleManageFundsPressed} - actions={[ - { - id: actionKeys.Refill, - text: loc.lnd.refill, - icon: actionIcons.Refill, - }, - { - id: actionKeys.RefillWithExternalWallet, - text: loc.lnd.refill_external, - icon: actionIcons.RefillWithExternalWallet, - }, - ]} + actions={toolTipActions} buttonStyle={styles.manageFundsButton} > {loc.lnd.title} From 0f7f24cd131a7a5f4a23f5daaa61c37494562365 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 15:38:01 -0400 Subject: [PATCH 17/37] FIX: DS --- components/AddressInput.tsx | 18 ++++++----- components/QRCodeComponent.tsx | 6 ++-- components/SaveFileButton.tsx | 35 +++++++++++---------- components/TransactionsNavigationHeader.tsx | 13 +++++--- 4 files changed, 41 insertions(+), 31 deletions(-) diff --git a/components/AddressInput.tsx b/components/AddressInput.tsx index 0370517965..e4a81ba097 100644 --- a/components/AddressInput.tsx +++ b/components/AddressInput.tsx @@ -1,4 +1,4 @@ -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { Image, Keyboard, StyleSheet, Text, TextInput, View } from 'react-native'; import { scanQrHelper } from '../helpers/scan-qr'; @@ -69,6 +69,12 @@ const AddressInput = ({ Keyboard.dismiss(); }; + const toolTipOnPress = useCallback(async () => { + await scanButtonTapped(); + Keyboard.dismiss(); + if (launchedBy) scanQrHelper(launchedBy).then(value => onBarScanned({ data: value })); + }, [launchedBy, onBarScanned, scanButtonTapped]); + const onMenuItemPressed = useCallback( (action: string) => { if (onBarScanned === undefined) throw new Error('onBarScanned is required'); @@ -119,6 +125,8 @@ const AddressInput = ({ [launchedBy, onBarScanned, onChangeText, scanButtonTapped], ); + const buttonStyle = useMemo(() => [styles.scan, stylesHook.scan], [stylesHook.scan]); + return ( { - await scanButtonTapped(); - Keyboard.dismiss(); - if (launchedBy) scanQrHelper(launchedBy).then(value => onBarScanned({ data: value })); - }} - buttonStyle={[styles.scan, stylesHook.scan]} + onPress={toolTipOnPress} + buttonStyle={buttonStyle} accessibilityLabel={loc.send.details_scan} accessibilityHint={loc.send.details_scan_hint} > diff --git a/components/QRCodeComponent.tsx b/components/QRCodeComponent.tsx index 72f0a65b13..be9857a64b 100644 --- a/components/QRCodeComponent.tsx +++ b/components/QRCodeComponent.tsx @@ -1,5 +1,5 @@ import Clipboard from '@react-native-clipboard/clipboard'; -import React, { useRef } from 'react'; +import React, { useCallback, useRef } from 'react'; import { Platform, StyleSheet, View } from 'react-native'; import QRCode from 'react-native-qrcode-svg'; import Share from 'react-native-share'; @@ -76,13 +76,13 @@ const QRCodeComponent: React.FC = ({ }); }; - const onPressMenuItem = (id: string) => { + const onPressMenuItem = useCallback((id: string) => { if (id === actionKeys.Share) { handleShareQRCode(); } else if (id === actionKeys.Copy) { qrCode.current.toDataURL(Clipboard.setImage); } - }; + }, []); const renderQRCode = ( = ({ onMenuWillHide, onMenuWillShow, }) => { - const handlePressMenuItem = async (actionId: string) => { - if (beforeOnPress) { - await beforeOnPress(); - } - const action = actions.find(a => a.id === actionId); + const handlePressMenuItem = useCallback( + async (actionId: string) => { + if (beforeOnPress) { + await beforeOnPress(); + } + const action = actions.find(a => a.id === actionId); - if (action?.id === 'save') { - await fs.writeFileAndExport(fileName, fileContent, false).finally(() => { - afterOnPress?.(); - }); - } else if (action?.id === 'share') { - await fs.writeFileAndExport(fileName, fileContent, true).finally(() => { - afterOnPress?.(); - }); - } - }; + if (action?.id === 'save') { + await fs.writeFileAndExport(fileName, fileContent, false).finally(() => { + afterOnPress?.(); + }); + } else if (action?.id === 'share') { + await fs.writeFileAndExport(fileName, fileContent, true).finally(() => { + afterOnPress?.(); + }); + } + }, + [afterOnPress, beforeOnPress, fileContent, fileName], + ); return ( onWalletUnitChange?.(updatedWallet); }; - const handleManageFundsPressed = (actionKeyID?: string) => { - if (onManageFundsPressed) { - onManageFundsPressed(actionKeyID); - } - }; + const handleManageFundsPressed = useCallback( + (actionKeyID?: string) => { + if (onManageFundsPressed) { + onManageFundsPressed(actionKeyID); + } + }, + [onManageFundsPressed], + ); const onPressMenuItem = useCallback( (id: string) => { From 7c48223af931097dd030f2c2104a1c6541e75d7f Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 15:40:33 -0400 Subject: [PATCH 18/37] Update TransactionsNavigationHeader.tsx --- components/TransactionsNavigationHeader.tsx | 64 +++++++++++---------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/components/TransactionsNavigationHeader.tsx b/components/TransactionsNavigationHeader.tsx index b7a17114d9..d455919009 100644 --- a/components/TransactionsNavigationHeader.tsx +++ b/components/TransactionsNavigationHeader.tsx @@ -146,6 +146,38 @@ const TransactionsNavigationHeader: React.FC // eslint-disable-next-line react-hooks/exhaustive-deps }, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]); + const toolTipWalletBalanceActions = useMemo(() => { + return wallet.hideBalance + ? [ + { + id: 'walletBalanceVisibility', + text: loc.transactions.details_balance_show, + icon: { + iconType: 'SYSTEM', + iconValue: 'eye', + }, + }, + ] + : [ + { + id: 'walletBalanceVisibility', + text: loc.transactions.details_balance_hide, + icon: { + iconType: 'SYSTEM', + iconValue: 'eye.slash', + }, + }, + { + id: 'copyToClipboard', + text: loc.transactions.details_copy, + icon: { + iconType: 'SYSTEM', + iconValue: 'doc.on.doc', + }, + }, + ]; + }, [wallet.hideBalance]); + return ( enableAndroidRipple={false} buttonStyle={styles.walletBalance} onPressMenuItem={onPressMenuItem} - actions={ - wallet.hideBalance - ? [ - { - id: 'walletBalanceVisibility', - text: loc.transactions.details_balance_show, - icon: { - iconType: 'SYSTEM', - iconValue: 'eye', - }, - }, - ] - : [ - { - id: 'walletBalanceVisibility', - text: loc.transactions.details_balance_hide, - icon: { - iconType: 'SYSTEM', - iconValue: 'eye.slash', - }, - }, - { - id: 'copyToClipboard', - text: loc.transactions.details_copy, - icon: { - iconType: 'SYSTEM', - iconValue: 'doc.on.doc', - }, - }, - ] - } + actions={toolTipWalletBalanceActions} > {wallet.hideBalance ? ( From 8ded51a55148f4668b7a42e780c9ab61d36f3d9e Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 15:50:20 -0400 Subject: [PATCH 19/37] Update AddressInput.tsx --- components/AddressInput.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/AddressInput.tsx b/components/AddressInput.tsx index e4a81ba097..57402e7aab 100644 --- a/components/AddressInput.tsx +++ b/components/AddressInput.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useMemo } from 'react'; -import { Image, Keyboard, StyleSheet, Text, TextInput, View } from 'react-native'; +import { Image, Keyboard, Platform, StyleSheet, Text, TextInput, View } from 'react-native'; import { scanQrHelper } from '../helpers/scan-qr'; import loc from '../loc'; @@ -210,7 +210,7 @@ const actionKeys = { const actionIcons = { ScanQR: { iconType: 'SYSTEM', - iconValue: 'qrcode', + iconValue: Platform.OS === 'ios' ? 'qrcode' : 'ic_menu_camera', }, ImportFile: { iconType: 'SYSTEM', @@ -218,7 +218,7 @@ const actionIcons = { }, ChoosePhoto: { iconType: 'SYSTEM', - iconValue: 'photo', + iconValue: Platform.OS === 'ios' ? 'photo' : 'ic_menu_gallery', }, Clipboard: { iconType: 'SYSTEM', From eee51285ede5e4c5c8363556088405de292f8e6a Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 15:57:13 -0400 Subject: [PATCH 20/37] DEL: DRY --- components/AddressInput.tsx | 6 +----- components/QRCodeComponent.tsx | 2 -- components/SaveFileButton.tsx | 2 -- components/TransactionListItem.tsx | 5 ----- components/TransactionsNavigationHeader.tsx | 8 -------- components/addresses/AddressItem.tsx | 4 ---- components/types.ts | 1 - screen/send/SendDetails.tsx | 16 ++++++++-------- screen/transactions/TransactionDetails.tsx | 2 -- screen/wallets/PaymentCodesList.tsx | 4 ---- typings/ActionIcons.ts | 1 - 11 files changed, 9 insertions(+), 42 deletions(-) diff --git a/components/AddressInput.tsx b/components/AddressInput.tsx index 57402e7aab..fbff8e926f 100644 --- a/components/AddressInput.tsx +++ b/components/AddressInput.tsx @@ -209,20 +209,16 @@ const actionKeys = { const actionIcons = { ScanQR: { - iconType: 'SYSTEM', iconValue: Platform.OS === 'ios' ? 'qrcode' : 'ic_menu_camera', }, ImportFile: { - iconType: 'SYSTEM', iconValue: 'doc', }, ChoosePhoto: { - iconType: 'SYSTEM', iconValue: Platform.OS === 'ios' ? 'photo' : 'ic_menu_gallery', }, Clipboard: { - iconType: 'SYSTEM', - iconValue: 'doc.on.doc', + iconValue: Platform.OS === 'ios' ? 'doc' : 'ic_menu_file', }, }; diff --git a/components/QRCodeComponent.tsx b/components/QRCodeComponent.tsx index be9857a64b..24949702c4 100644 --- a/components/QRCodeComponent.tsx +++ b/components/QRCodeComponent.tsx @@ -22,11 +22,9 @@ interface QRCodeComponentProps { const actionIcons: { [key: string]: ActionIcons } = { Share: { - iconType: 'SYSTEM', iconValue: 'square.and.arrow.up', }, Copy: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, }; diff --git a/components/SaveFileButton.tsx b/components/SaveFileButton.tsx index 315462e169..ca2b26052e 100644 --- a/components/SaveFileButton.tsx +++ b/components/SaveFileButton.tsx @@ -67,11 +67,9 @@ export default SaveFileButton; const actionIcons: { [key: string]: ActionIcons } = { Share: { - iconType: 'SYSTEM', iconValue: 'square.and.arrow.up', }, Save: { - iconType: 'SYSTEM', iconValue: 'square.and.arrow.down', }, }; diff --git a/components/TransactionListItem.tsx b/components/TransactionListItem.tsx index be54d54516..0276d8c238 100644 --- a/components/TransactionListItem.tsx +++ b/components/TransactionListItem.tsx @@ -367,23 +367,18 @@ const actionKeys = { const actionIcons = { Eye: { - iconType: 'SYSTEM', iconValue: 'eye', }, EyeSlash: { - iconType: 'SYSTEM', iconValue: 'eye.slash', }, Clipboard: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, Link: { - iconType: 'SYSTEM', iconValue: 'link', }, Note: { - iconType: 'SYSTEM', iconValue: 'note.text', }, }; diff --git a/components/TransactionsNavigationHeader.tsx b/components/TransactionsNavigationHeader.tsx index d455919009..6491f85965 100644 --- a/components/TransactionsNavigationHeader.tsx +++ b/components/TransactionsNavigationHeader.tsx @@ -153,7 +153,6 @@ const TransactionsNavigationHeader: React.FC id: 'walletBalanceVisibility', text: loc.transactions.details_balance_show, icon: { - iconType: 'SYSTEM', iconValue: 'eye', }, }, @@ -163,7 +162,6 @@ const TransactionsNavigationHeader: React.FC id: 'walletBalanceVisibility', text: loc.transactions.details_balance_hide, icon: { - iconType: 'SYSTEM', iconValue: 'eye.slash', }, }, @@ -171,7 +169,6 @@ const TransactionsNavigationHeader: React.FC id: 'copyToClipboard', text: loc.transactions.details_copy, icon: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, }, @@ -343,23 +340,18 @@ export const actionKeys = { export const actionIcons = { Eye: { - iconType: 'SYSTEM', iconValue: 'eye', }, EyeSlash: { - iconType: 'SYSTEM', iconValue: 'eye.slash', }, Clipboard: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, Refill: { - iconType: 'SYSTEM', iconValue: 'goforward.plus', }, RefillWithExternalWallet: { - iconType: 'SYSTEM', iconValue: 'qrcode', }, }; diff --git a/components/addresses/AddressItem.tsx b/components/addresses/AddressItem.tsx index eb06663994..5a3743bfc0 100644 --- a/components/addresses/AddressItem.tsx +++ b/components/addresses/AddressItem.tsx @@ -175,19 +175,15 @@ const actionKeys = { const actionIcons = { Signature: { - iconType: 'SYSTEM', iconValue: 'signature', }, Share: { - iconType: 'SYSTEM', iconValue: 'square.and.arrow.up', }, Clipboard: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, ExportPrivateKey: { - iconType: 'SYSTEM', iconValue: 'key', }, }; diff --git a/components/types.ts b/components/types.ts index 8b4f1def98..f5c369a420 100644 --- a/components/types.ts +++ b/components/types.ts @@ -4,7 +4,6 @@ export interface Action { id: string | number; text: string; icon?: { - iconType: string; iconValue: string; }; menuTitle?: string; diff --git a/screen/send/SendDetails.tsx b/screen/send/SendDetails.tsx index 663c6174e2..74e1041cf5 100644 --- a/screen/send/SendDetails.tsx +++ b/screen/send/SendDetails.tsx @@ -1621,16 +1621,16 @@ SendDetails.actionKeys = { }; SendDetails.actionIcons = { - InsertContact: { iconType: 'SYSTEM', iconValue: 'at.badge.plus' }, - SignPSBT: { iconType: 'SYSTEM', iconValue: 'signature' }, + InsertContact: { iconValue: 'at.badge.plus' }, + SignPSBT: { iconValue: 'signature' }, SendMax: 'SendMax', - AddRecipient: { iconType: 'SYSTEM', iconValue: 'person.badge.plus' }, - RemoveRecipient: { iconType: 'SYSTEM', iconValue: 'person.badge.minus' }, + AddRecipient: { iconValue: 'person.badge.plus' }, + RemoveRecipient: { iconValue: 'person.badge.minus' }, AllowRBF: 'AllowRBF', - ImportTransaction: { iconType: 'SYSTEM', iconValue: 'square.and.arrow.down' }, - ImportTransactionMultsig: { iconType: 'SYSTEM', iconValue: 'square.and.arrow.down.on.square' }, - ImportTransactionQR: { iconType: 'SYSTEM', iconValue: 'qrcode.viewfinder' }, - CoinControl: { iconType: 'SYSTEM', iconValue: 'switch.2' }, + ImportTransaction: { iconValue: 'square.and.arrow.down' }, + ImportTransactionMultsig: { iconValue: 'square.and.arrow.down.on.square' }, + ImportTransactionQR: { iconValue: 'qrcode.viewfinder' }, + CoinControl: { iconValue: 'switch.2' }, }; const styles = StyleSheet.create({ diff --git a/screen/transactions/TransactionDetails.tsx b/screen/transactions/TransactionDetails.tsx index 6a8527f9e8..d5c16d4712 100644 --- a/screen/transactions/TransactionDetails.tsx +++ b/screen/transactions/TransactionDetails.tsx @@ -32,11 +32,9 @@ const actionKeys = { const actionIcons = { Clipboard: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, GoToWallet: { - iconType: 'SYSTEM', iconValue: 'wallet.pass', }, }; diff --git a/screen/wallets/PaymentCodesList.tsx b/screen/wallets/PaymentCodesList.tsx index 979bd7e9ff..c9eb0f757a 100644 --- a/screen/wallets/PaymentCodesList.tsx +++ b/screen/wallets/PaymentCodesList.tsx @@ -42,7 +42,6 @@ const actionKeys: Action[] = [ id: Actions.pay, text: loc.bip47.pay_this_contact, icon: { - iconType: 'SYSTEM', iconValue: 'paperplane', }, }, @@ -50,7 +49,6 @@ const actionKeys: Action[] = [ id: Actions.rename, text: loc.bip47.rename_contact, icon: { - iconType: 'SYSTEM', iconValue: 'pencil', }, }, @@ -58,7 +56,6 @@ const actionKeys: Action[] = [ id: Actions.copyToClipboard, text: loc.bip47.copy_payment_code, icon: { - iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, }, @@ -66,7 +63,6 @@ const actionKeys: Action[] = [ id: Actions.hide, text: loc.bip47.hide_contact, icon: { - iconType: 'SYSTEM', iconValue: 'eye.slash', }, }, diff --git a/typings/ActionIcons.ts b/typings/ActionIcons.ts index c3b7af6ac0..a455d1ebaf 100644 --- a/typings/ActionIcons.ts +++ b/typings/ActionIcons.ts @@ -1,4 +1,3 @@ export interface ActionIcons { - iconType: 'SYSTEM'; iconValue: string; } From b704ea9db5e047797689d8a1596f48a27ad605ef Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Mon, 17 Jun 2024 16:12:43 -0400 Subject: [PATCH 21/37] Update AddressItem.tsx --- components/addresses/AddressItem.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/addresses/AddressItem.tsx b/components/addresses/AddressItem.tsx index 5a3743bfc0..dd93d5dd52 100644 --- a/components/addresses/AddressItem.tsx +++ b/components/addresses/AddressItem.tsx @@ -141,6 +141,7 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad onPressMenuItem={onToolTipPress} renderPreview={renderPreview} onPress={navigateToReceive} + isButton > From 347081125bacaeebc2870eaac4a20ec3f89c6698 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:33:32 +0000 Subject: [PATCH 22/37] Update dependency react-native-screens to v3.32.0 --- package-lock.json | 15 ++++++++------- package.json | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index cbce568a13..19261ec970 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,7 +90,7 @@ "react-native-rate": "1.2.12", "react-native-reanimated": "3.11.0", "react-native-safe-area-context": "4.10.5", - "react-native-screens": "3.31.1", + "react-native-screens": "3.32.0", "react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48", "react-native-share": "10.2.1", "react-native-svg": "13.14.1", @@ -19918,9 +19918,10 @@ } }, "node_modules/react-native-screens": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.31.1.tgz", - "integrity": "sha512-8fRW362pfZ9y4rS8KY5P3DFScrmwo/vu1RrRMMx0PNHbeC9TLq0Kw1ubD83591yz64gLNHFLTVkTJmWeWCXKtQ==", + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.32.0.tgz", + "integrity": "sha512-wybqZAHX7v8ipOXhh90CqGLkBHw5JYqKNRBX7R/b0c2WQisTOgu0M0yGwBMM6LyXRBT+4k3NTGHdDbpJVpq0yQ==", + "license": "MIT", "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" @@ -37618,9 +37619,9 @@ "integrity": "sha512-Wyb0Nqw2XJ6oZxW/cK8k5q7/UAhg/wbEG6UVf89rQqecDZTDA5ic//P9J6VvJRVZerzGmxWQpVuM7f+PRYUM4g==" }, "react-native-screens": { - "version": "3.31.1", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.31.1.tgz", - "integrity": "sha512-8fRW362pfZ9y4rS8KY5P3DFScrmwo/vu1RrRMMx0PNHbeC9TLq0Kw1ubD83591yz64gLNHFLTVkTJmWeWCXKtQ==", + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.32.0.tgz", + "integrity": "sha512-wybqZAHX7v8ipOXhh90CqGLkBHw5JYqKNRBX7R/b0c2WQisTOgu0M0yGwBMM6LyXRBT+4k3NTGHdDbpJVpq0yQ==", "requires": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" diff --git a/package.json b/package.json index 0fd8e78e5d..691705640e 100644 --- a/package.json +++ b/package.json @@ -175,7 +175,7 @@ "react-native-rate": "1.2.12", "react-native-reanimated": "3.11.0", "react-native-safe-area-context": "4.10.5", - "react-native-screens": "3.31.1", + "react-native-screens": "3.32.0", "react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48", "react-native-share": "10.2.1", "react-native-svg": "13.14.1", From 1101e6b0818cc1557fd2c7f0f636c608355b6e49 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:34:06 +0000 Subject: [PATCH 23/37] Update dependency realm to v12.11.0 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index cbce568a13..11d637a660 100644 --- a/package-lock.json +++ b/package-lock.json @@ -98,7 +98,7 @@ "react-native-vector-icons": "10.1.0", "react-native-watch-connectivity": "1.1.0", "readable-stream": "3.6.2", - "realm": "12.10.0", + "realm": "12.11.0", "rn-ldk": "github:BlueWallet/rn-ldk#v0.8.4", "rn-nodeify": "10.3.0", "scryptsy": "2.1.0", @@ -20292,9 +20292,9 @@ "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, "node_modules/realm": { - "version": "12.10.0", - "resolved": "https://registry.npmjs.org/realm/-/realm-12.10.0.tgz", - "integrity": "sha512-F3TpZ6upARxo+ZO6m/qbqaBc8AtPawxayckYGmEDfZ2TX3fqfq9v9NdtUDpjYoDXAyGiPxuSTu+DrrGzHCeYTw==", + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/realm/-/realm-12.11.0.tgz", + "integrity": "sha512-7KR3BSCurJcQR8IJJiWoLb6VkN3q34HObgtTlleKjXAAqr/7xEUu/kkVWyH78LCdU92qq16lBKS/59Ol2lJnlA==", "hasInstallScript": true, "license": "apache-2.0", "dependencies": { @@ -37805,9 +37805,9 @@ "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, "realm": { - "version": "12.10.0", - "resolved": "https://registry.npmjs.org/realm/-/realm-12.10.0.tgz", - "integrity": "sha512-F3TpZ6upARxo+ZO6m/qbqaBc8AtPawxayckYGmEDfZ2TX3fqfq9v9NdtUDpjYoDXAyGiPxuSTu+DrrGzHCeYTw==", + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/realm/-/realm-12.11.0.tgz", + "integrity": "sha512-7KR3BSCurJcQR8IJJiWoLb6VkN3q34HObgtTlleKjXAAqr/7xEUu/kkVWyH78LCdU92qq16lBKS/59Ol2lJnlA==", "requires": { "@realm/fetch": "^0.1.1", "bson": "^4.7.2", diff --git a/package.json b/package.json index 0fd8e78e5d..d3ce9da803 100644 --- a/package.json +++ b/package.json @@ -183,7 +183,7 @@ "react-native-vector-icons": "10.1.0", "react-native-watch-connectivity": "1.1.0", "readable-stream": "3.6.2", - "realm": "12.10.0", + "realm": "12.11.0", "rn-ldk": "github:BlueWallet/rn-ldk#v0.8.4", "rn-nodeify": "10.3.0", "scryptsy": "2.1.0", From 12883f92bf21590acf4e0894cdefd90a9192d66a Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Tue, 18 Jun 2024 13:34:36 -0400 Subject: [PATCH 24/37] OPS: Pods --- Gemfile | 2 +- Gemfile.lock | 8 ++++---- ios/BlueWallet.xcodeproj/project.pbxproj | 6 +++--- ios/Podfile.lock | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 7e60e03851..b9037bf89d 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version ruby "3.1.6" -gem "cocoapods", ">= 1.13", "< 1.15" +gem "cocoapods", "1.15" gem "activesupport", ">= 6.1.7.3", "< 7.1.0" gem "fastlane" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 60e4918247..2c483096b4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -36,10 +36,10 @@ GEM babosa (1.0.4) base64 (0.2.0) claide (1.1.0) - cocoapods (1.14.3) + cocoapods (1.15.0) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) + cocoapods-core (= 1.15.0) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -54,7 +54,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) + cocoapods-core (1.15.0) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -277,7 +277,7 @@ PLATFORMS DEPENDENCIES activesupport (>= 6.1.7.3, < 7.1.0) - cocoapods (>= 1.13, < 1.15) + cocoapods (= 1.15) fastlane RUBY VERSION diff --git a/ios/BlueWallet.xcodeproj/project.pbxproj b/ios/BlueWallet.xcodeproj/project.pbxproj index f53ee2bfbf..cd570783e0 100644 --- a/ios/BlueWallet.xcodeproj/project.pbxproj +++ b/ios/BlueWallet.xcodeproj/project.pbxproj @@ -169,7 +169,7 @@ B4D0B2682C1DED67006B6B1B /* ReceiveMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D0B2672C1DED67006B6B1B /* ReceiveMethod.swift */; }; B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; }; C59F90CE0D04D3E4BB39BC5D /* libPods-BlueWalletUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */; }; - C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; + C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -491,7 +491,7 @@ files = ( 782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */, 764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */, - C978A716948AB7DEC5B6F677 /* (null) in Frameworks */, + C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */, 773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2737,4 +2737,4 @@ /* End XCSwiftPackageProductDependency section */ }; rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} \ No newline at end of file +} diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c7e850de05..4e86a4ab70 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -462,7 +462,7 @@ PODS: - React-perflogger (= 0.72.14) - ReactNativeCameraKit (13.0.0): - React-Core - - RealmJS (12.10.0): + - RealmJS (12.11.0): - React - rn-ldk (0.8.4): - React-Core @@ -501,7 +501,7 @@ PODS: - RCT-Folly (= 2021.07.22.00) - React-Core - ReactCommon/turbomodule/core - - RNScreens (3.31.1): + - RNScreens (3.32.0): - RCT-Folly (= 2021.07.22.00) - React-Core - React-RCTImage @@ -824,7 +824,7 @@ SPEC CHECKSUMS: React-utils: 22a77b05da25ce49c744faa82e73856dcae1734e ReactCommon: ff94462e007c568d8cdebc32e3c97af86ec93bb5 ReactNativeCameraKit: 9d46a5d7dd544ca64aa9c03c150d2348faf437eb - RealmJS: f86da4f2c5b089d976db335f370449903ddc8fbb + RealmJS: 5f96d3e02420b5f579296c465a437f6e20026da9 rn-ldk: 0d8749d98cc5ce67302a32831818c116b67f7643 RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c RNCClipboard: 0a720adef5ec193aa0e3de24c3977222c7e52a37 @@ -842,7 +842,7 @@ SPEC CHECKSUMS: RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 RNReanimated: d4f25b2a931c4f0b2bb12173a3096f02ea4cfb05 - RNScreens: b8d370282cdeae9df85dd5eab20c88eb5181243b + RNScreens: ad1c105ac9107cf1a613bf80889485458eb20bd7 RNShare: 0fad69ae2d71de9d1f7b9a43acf876886a6cb99c RNSVG: af3907ac5d4fa26a862b75a16d8f15bc74f2ceda RNVectorIcons: 32462e7c7e58fe457474fc79c4d7de3f0ef08d70 @@ -852,4 +852,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: f19eea438501edfe85fb2fa51d40ba1b57540758 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.0 From b15ce8635569d8ebc8c92c6148f613c3451ce7da Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Tue, 18 Jun 2024 18:58:58 -0400 Subject: [PATCH 25/37] OPS: Node version --- .github/workflows/build-ios-release-pullrequest.yml | 2 +- .github/workflows/build-release-apk.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-ios-release-pullrequest.yml b/.github/workflows/build-ios-release-pullrequest.yml index 5d6ef2b4ec..4667b6f564 100644 --- a/.github/workflows/build-ios-release-pullrequest.yml +++ b/.github/workflows/build-ios-release-pullrequest.yml @@ -28,7 +28,7 @@ jobs: - name: Specify node version uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: 15.4 diff --git a/.github/workflows/build-release-apk.yml b/.github/workflows/build-release-apk.yml index c76870bfc8..7a076d3e36 100644 --- a/.github/workflows/build-release-apk.yml +++ b/.github/workflows/build-release-apk.yml @@ -20,7 +20,7 @@ jobs: - name: Specify node version uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Use npm caches uses: actions/cache@v2 From f5b73cd5580892d3c6ccb37a013fd93f34090c3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 08:54:50 +0000 Subject: [PATCH 26/37] Update dependency detox to v20.23.0 --- package-lock.json | 15 ++++++++------- package.json | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a18ad7007..bae1232f5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "coinselect": "3.1.13", "crypto-js": "4.2.0", "dayjs": "1.11.11", - "detox": "20.22.2", + "detox": "20.23.0", "ecpair": "2.0.1", "ecurve": "1.0.6", "electrum-client": "github:BlueWallet/rn-electrum-client#1bfe3cc", @@ -9617,9 +9617,9 @@ } }, "node_modules/detox": { - "version": "20.22.2", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.22.2.tgz", - "integrity": "sha512-NTgLI4PQ7mgTTy+/w+jrD/8FhVdfQDwjUsYXEEreWS+tEG+borNNskTRnEO2JMvmBC3eM5lcnbfhCUbzClfURQ==", + "version": "20.23.0", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.23.0.tgz", + "integrity": "sha512-jIZzO/gWEWDgq+lKcbwSiBJG2C9m6I8eDsuIxeyUbK4Di9UXZRhBCnVnp8hke6mUXkAe5TjzwnTCx7hD55f9pQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -9743,6 +9743,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -29902,9 +29903,9 @@ "dev": true }, "detox": { - "version": "20.22.2", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.22.2.tgz", - "integrity": "sha512-NTgLI4PQ7mgTTy+/w+jrD/8FhVdfQDwjUsYXEEreWS+tEG+borNNskTRnEO2JMvmBC3eM5lcnbfhCUbzClfURQ==", + "version": "20.23.0", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.23.0.tgz", + "integrity": "sha512-jIZzO/gWEWDgq+lKcbwSiBJG2C9m6I8eDsuIxeyUbK4Di9UXZRhBCnVnp8hke6mUXkAe5TjzwnTCx7hD55f9pQ==", "requires": { "ajv": "^8.6.3", "bunyan": "^1.8.12", diff --git a/package.json b/package.json index 996890a600..0149753f06 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "coinselect": "3.1.13", "crypto-js": "4.2.0", "dayjs": "1.11.11", - "detox": "20.22.2", + "detox": "20.23.0", "ecpair": "2.0.1", "ecurve": "1.0.6", "electrum-client": "github:BlueWallet/rn-electrum-client#1bfe3cc", From 7c4b279e22778ccbeae9e26337366e62ef3f9657 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 13:13:29 +0000 Subject: [PATCH 27/37] Update dependency react-native-gesture-handler to v2.17.0 --- package-lock.json | 17 ++++++++--------- package.json | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a18ad7007..9e41ddeb29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "react-native-document-picker": "https://github.com/BlueWallet/react-native-document-picker#6033c4e1b0dd0a6760b5f5a5a2c3b2e5d07f2ae4", "react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#ebfddc4", "react-native-fs": "2.20.0", - "react-native-gesture-handler": "2.16.2", + "react-native-gesture-handler": "2.17.0", "react-native-handoff": "https://github.com/BlueWallet/react-native-handoff#31d005f93d31099d0e564590a3bbd052b8a02b39", "react-native-haptic-feedback": "2.2.0", "react-native-idle-timer": "https://github.com/BlueWallet/react-native-idle-timer#7300b637c465c86e8db874c442e687950111da40", @@ -19686,14 +19686,14 @@ } }, "node_modules/react-native-gesture-handler": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.16.2.tgz", - "integrity": "sha512-vGFlrDKlmyI+BT+FemqVxmvO7nqxU33cgXVsn6IKAFishvlG3oV2Ds67D5nPkHMea8T+s1IcuMm0bF8ntZtAyg==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.17.0.tgz", + "integrity": "sha512-FzEOlLTo83OEBnCKwgwQTnsnlVHMVHu6xRNrxHpPRllfSBlpfyHCn2ezzDA6/k7ec2ooltU+3IIQSRiamHwHNA==", + "license": "MIT", "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4", - "lodash": "^4.17.21", "prop-types": "^15.7.2" }, "peerDependencies": { @@ -37466,14 +37466,13 @@ } }, "react-native-gesture-handler": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.16.2.tgz", - "integrity": "sha512-vGFlrDKlmyI+BT+FemqVxmvO7nqxU33cgXVsn6IKAFishvlG3oV2Ds67D5nPkHMea8T+s1IcuMm0bF8ntZtAyg==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.17.0.tgz", + "integrity": "sha512-FzEOlLTo83OEBnCKwgwQTnsnlVHMVHu6xRNrxHpPRllfSBlpfyHCn2ezzDA6/k7ec2ooltU+3IIQSRiamHwHNA==", "requires": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4", - "lodash": "^4.17.21", "prop-types": "^15.7.2" } }, diff --git a/package.json b/package.json index 996890a600..fd159500c2 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,7 @@ "react-native-document-picker": "https://github.com/BlueWallet/react-native-document-picker#6033c4e1b0dd0a6760b5f5a5a2c3b2e5d07f2ae4", "react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#ebfddc4", "react-native-fs": "2.20.0", - "react-native-gesture-handler": "2.16.2", + "react-native-gesture-handler": "2.17.0", "react-native-handoff": "https://github.com/BlueWallet/react-native-handoff#31d005f93d31099d0e564590a3bbd052b8a02b39", "react-native-haptic-feedback": "2.2.0", "react-native-idle-timer": "https://github.com/BlueWallet/react-native-idle-timer#7300b637c465c86e8db874c442e687950111da40", From 7eef06fea8b98cec024a511193b362afc935b7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Rodriguez=20V=C3=A9lez?= Date: Wed, 19 Jun 2024 13:18:08 -0400 Subject: [PATCH 28/37] Ruby (#6727) --- .../build-ios-release-pullrequest.yml | 26 +++++++++---------- .github/workflows/build-release-apk.yml | 2 +- Gemfile | 3 ++- Gemfile.lock | 17 ++++++------ ios/Podfile.lock | 6 ++--- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-ios-release-pullrequest.yml b/.github/workflows/build-ios-release-pullrequest.yml index 5d6ef2b4ec..074c951532 100644 --- a/.github/workflows/build-ios-release-pullrequest.yml +++ b/.github/workflows/build-ios-release-pullrequest.yml @@ -19,16 +19,16 @@ jobs: project_version: ${{ steps.determine_marketing_version.outputs.project_version }} latest_commit_message: ${{ steps.get_latest_commit_message.outputs.commit_message }} env: - APPLE_ID: ${{ secrets.APPLE_ID }} # Setting the environment variable + APPLE_ID: ${{ secrets.APPLE_ID }} steps: - name: Checkout project - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # Fetches all history - name: Specify node version uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - uses: maxim-lobanov/setup-xcode@v1 with: xcode-version: 15.4 @@ -38,17 +38,12 @@ jobs: ruby-version: 3.1.6 bundler-cache: true - name: Install dependencies with Bundler - run: bundle install --quiet - - name: Install Fastlane - run: gem install fastlane - - name: Clear Derived Data - run: bundle exec fastlane ios clear_derived_data_lane - working-directory: ./ios + run: bundle install - name: Install node_modules run: npm install - name: Install CocoaPods Dependencies run: | - sudo gem install cocoapods # Ensure CocoaPods is installed + gem install cocoapods bundle exec pod install working-directory: ./ios - name: Cache CocoaPods Pods @@ -110,7 +105,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa - path: ./ios/build/BlueWallet.${{env.PROJECT_VERSION}}(${{ env.NEW_BUILD_NUMBER }}).ipa + path: ./ios/build/BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa testflight-upload: needs: build @@ -123,7 +118,12 @@ jobs: LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }} steps: - name: Checkout project - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.1.6 + bundler-cache: true - name: Cache Ruby Gems uses: actions/cache@v2 with: @@ -138,7 +138,7 @@ jobs: - name: Download IPA from Artifact uses: actions/download-artifact@v2 with: - name: BlueWallet.${{needs.build.outputs.project_version}}(${{needs.build.outputs.new_build_number}}).ipa + name: BlueWallet.${{ needs.build.outputs.project_version }}(${{ needs.build.outputs.new_build_number }}).ipa path: ./ios/build - name: Create App Store Connect API Key JSON run: echo '${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}' > ./ios/appstore_api_key.json diff --git a/.github/workflows/build-release-apk.yml b/.github/workflows/build-release-apk.yml index c76870bfc8..7a076d3e36 100644 --- a/.github/workflows/build-release-apk.yml +++ b/.github/workflows/build-release-apk.yml @@ -20,7 +20,7 @@ jobs: - name: Specify node version uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Use npm caches uses: actions/cache@v2 diff --git a/Gemfile b/Gemfile index b9037bf89d..7e4d042ad6 100644 --- a/Gemfile +++ b/Gemfile @@ -2,6 +2,7 @@ source "https://rubygems.org" # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version ruby "3.1.6" -gem "cocoapods", "1.15" +gem 'rubyzip', '2.3.0' +gem "cocoapods", "1.15.2" gem "activesupport", ">= 6.1.7.3", "< 7.1.0" gem "fastlane" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 2c483096b4..2436e3220b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -24,7 +24,7 @@ GEM aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.84.0) + aws-sdk-kms (1.85.0) aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) aws-sdk-s3 (1.152.3) @@ -36,10 +36,10 @@ GEM babosa (1.0.4) base64 (0.2.0) claide (1.1.0) - cocoapods (1.15.0) + cocoapods (1.15.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.15.0) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -54,7 +54,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.15.0) + cocoapods-core (1.15.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -117,7 +117,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.3.1) - fastlane (2.220.0) + fastlane (2.221.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -206,7 +206,7 @@ GEM concurrent-ruby (~> 1.0) jmespath (1.6.2) json (2.7.2) - jwt (2.8.1) + jwt (2.8.2) base64 mini_magick (4.13.1) mini_mime (1.1.5) @@ -234,7 +234,7 @@ GEM rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) - rubyzip (2.3.2) + rubyzip (2.3.0) security (0.1.5) signet (0.19.0) addressable (~> 2.8) @@ -277,8 +277,9 @@ PLATFORMS DEPENDENCIES activesupport (>= 6.1.7.3, < 7.1.0) - cocoapods (= 1.15) + cocoapods (= 1.15.2) fastlane + rubyzip (= 2.3.0) RUBY VERSION ruby 3.1.6p260 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4e86a4ab70..476e2ac124 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -491,7 +491,7 @@ PODS: - React-Core - RNPrivacySnapshot (1.0.0): - React - - RNQuickAction (0.3.13): + - RNQuickAction (0.3.14): - React - RNRate (1.2.12): - React-Core @@ -838,7 +838,7 @@ SPEC CHECKSUMS: RNLocalize: b77875884750cb6a58cd6865863fe2ba2729b72b RNPermissions: 9fa74223844f437bc309e112994859dc47194829 RNPrivacySnapshot: 71919dde3c6a29dd332115409c2aec564afee8f4 - RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93 + RNQuickAction: c056e83ff3f649e7a723c60659037a4fdad2d929 RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 RNReanimated: d4f25b2a931c4f0b2bb12173a3096f02ea4cfb05 @@ -852,4 +852,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: f19eea438501edfe85fb2fa51d40ba1b57540758 -COCOAPODS: 1.15.0 +COCOAPODS: 1.15.2 From f26ca2fe487fff1cf60f1c8a88c393871d89613a Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Wed, 19 Jun 2024 13:38:01 -0400 Subject: [PATCH 29/37] Update project.pbxproj --- ios/BlueWallet.xcodeproj/project.pbxproj | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/ios/BlueWallet.xcodeproj/project.pbxproj b/ios/BlueWallet.xcodeproj/project.pbxproj index cd570783e0..4e3eb5def8 100644 --- a/ios/BlueWallet.xcodeproj/project.pbxproj +++ b/ios/BlueWallet.xcodeproj/project.pbxproj @@ -169,7 +169,7 @@ B4D0B2682C1DED67006B6B1B /* ReceiveMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D0B2672C1DED67006B6B1B /* ReceiveMethod.swift */; }; B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; }; C59F90CE0D04D3E4BB39BC5D /* libPods-BlueWalletUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */; }; - C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -491,7 +491,7 @@ files = ( 782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */, 764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */, - C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */, + C978A716948AB7DEC5B6F677 /* (null) in Frameworks */, 773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -571,7 +571,6 @@ 13B07FAE1A68108700A75B9A /* BlueWallet */ = { isa = PBXGroup; children = ( - B4AB21052B61D8890080440C /* SplashScreen */, B461B850299599F800E431AA /* AppDelegate.h */, B461B851299599F800E431AA /* AppDelegate.mm */, 32C7944323B8879D00BE2AFA /* BlueWalletRelease.entitlements */, @@ -911,13 +910,6 @@ path = BlueWalletUITests; sourceTree = ""; }; - B4AB21052B61D8890080440C /* SplashScreen */ = { - isa = PBXGroup; - children = ( - ); - name = SplashScreen; - sourceTree = ""; - }; FAA856B639C61E61D2CF90A8 /* Pods */ = { isa = PBXGroup; children = ( From 5aed9471b6fa1f7b3b61aaba0f95463869be17f6 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Wed, 19 Jun 2024 13:44:55 -0400 Subject: [PATCH 30/37] Update Podfile.lock --- ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 476e2ac124..12bb815b60 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -491,7 +491,7 @@ PODS: - React-Core - RNPrivacySnapshot (1.0.0): - React - - RNQuickAction (0.3.14): + - RNQuickAction (0.3.13): - React - RNRate (1.2.12): - React-Core @@ -838,7 +838,7 @@ SPEC CHECKSUMS: RNLocalize: b77875884750cb6a58cd6865863fe2ba2729b72b RNPermissions: 9fa74223844f437bc309e112994859dc47194829 RNPrivacySnapshot: 71919dde3c6a29dd332115409c2aec564afee8f4 - RNQuickAction: c056e83ff3f649e7a723c60659037a4fdad2d929 + RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93 RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 RNReanimated: d4f25b2a931c4f0b2bb12173a3096f02ea4cfb05 From 11d740804988ae554b03af133d29dab2bfd89729 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Wed, 19 Jun 2024 13:46:43 -0400 Subject: [PATCH 31/37] Update Podfile.lock --- ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 12bb815b60..7d7f8a7afd 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -478,7 +478,7 @@ PODS: - React-Core - RNFS (2.20.0): - React-Core - - RNGestureHandler (2.16.2): + - RNGestureHandler (2.17.0): - RCT-Folly (= 2021.07.22.00) - React-Core - RNHandoff (0.0.3): @@ -832,7 +832,7 @@ SPEC CHECKSUMS: RNDefaultPreference: 08bdb06cfa9188d5da97d4642dac745218d7fb31 RNDeviceInfo: b899ce37a403a4dea52b7cb85e16e49c04a5b88e RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 - RNGestureHandler: 982741f345785f2927e7b28f67dc83679cf3bfc8 + RNGestureHandler: 2d351f93c68bf410fc0fe8d9ace7bdddb0c2e566 RNHandoff: d3b0754cca3a6bcd9b25f544f733f7f033ccf5fa RNKeychain: bfe3d12bf4620fe488771c414530bf16e88f3678 RNLocalize: b77875884750cb6a58cd6865863fe2ba2729b72b From 763676633769e7423797378bc5b452ec9d7cc0d9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Jun 2024 11:23:24 +0000 Subject: [PATCH 32/37] Update dependency react-native-tcp-socket to v6.1.0 --- package-lock.json | 16 +++++++++------- package.json | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index c44e2b33c5..d5013da932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,7 +95,7 @@ "react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48", "react-native-share": "10.2.1", "react-native-svg": "13.14.1", - "react-native-tcp-socket": "6.0.6", + "react-native-tcp-socket": "6.1.0", "react-native-vector-icons": "10.1.0", "react-native-watch-connectivity": "1.1.0", "readable-stream": "3.6.2", @@ -19971,9 +19971,10 @@ } }, "node_modules/react-native-tcp-socket": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/react-native-tcp-socket/-/react-native-tcp-socket-6.0.6.tgz", - "integrity": "sha512-FIFSP+3S5OnJRjl7ddD7G9NfVbVEiQ4WROEmOBei1cKE0pDz2R/Kcm4XkFlnMd5sdoG6Wbv830Yd/ZsmOjkEKw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-native-tcp-socket/-/react-native-tcp-socket-6.1.0.tgz", + "integrity": "sha512-dgJAi6u0Bes9XC9awgbyeQchog15ZRqOWjk7ZKW9DzwyPGXJnMAOhQCYyER9+AcQ4s93A/x/xgGBIXIeBLJQyg==", + "license": "MIT", "dependencies": { "buffer": "^5.4.3", "eventemitter3": "^4.0.7" @@ -20004,6 +20005,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -37661,9 +37663,9 @@ } }, "react-native-tcp-socket": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/react-native-tcp-socket/-/react-native-tcp-socket-6.0.6.tgz", - "integrity": "sha512-FIFSP+3S5OnJRjl7ddD7G9NfVbVEiQ4WROEmOBei1cKE0pDz2R/Kcm4XkFlnMd5sdoG6Wbv830Yd/ZsmOjkEKw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-native-tcp-socket/-/react-native-tcp-socket-6.1.0.tgz", + "integrity": "sha512-dgJAi6u0Bes9XC9awgbyeQchog15ZRqOWjk7ZKW9DzwyPGXJnMAOhQCYyER9+AcQ4s93A/x/xgGBIXIeBLJQyg==", "requires": { "buffer": "^5.4.3", "eventemitter3": "^4.0.7" diff --git a/package.json b/package.json index 91a63721f0..c8c2528fa1 100644 --- a/package.json +++ b/package.json @@ -180,7 +180,7 @@ "react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48", "react-native-share": "10.2.1", "react-native-svg": "13.14.1", - "react-native-tcp-socket": "6.0.6", + "react-native-tcp-socket": "6.1.0", "react-native-vector-icons": "10.1.0", "react-native-watch-connectivity": "1.1.0", "readable-stream": "3.6.2", From 0d271b15ebc2cbc06609b51d552dd7323cbf9cf6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 13:41:52 +0000 Subject: [PATCH 33/37] Update dependency react-native-gesture-handler to v2.17.1 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index d5013da932..ed9d6f8a9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,7 @@ "react-native-document-picker": "https://github.com/BlueWallet/react-native-document-picker#6033c4e1b0dd0a6760b5f5a5a2c3b2e5d07f2ae4", "react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#ebfddc4", "react-native-fs": "2.20.0", - "react-native-gesture-handler": "2.17.0", + "react-native-gesture-handler": "2.17.1", "react-native-handoff": "https://github.com/BlueWallet/react-native-handoff#31d005f93d31099d0e564590a3bbd052b8a02b39", "react-native-haptic-feedback": "2.2.0", "react-native-idle-timer": "https://github.com/BlueWallet/react-native-idle-timer#7300b637c465c86e8db874c442e687950111da40", @@ -19697,9 +19697,9 @@ } }, "node_modules/react-native-gesture-handler": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.17.0.tgz", - "integrity": "sha512-FzEOlLTo83OEBnCKwgwQTnsnlVHMVHu6xRNrxHpPRllfSBlpfyHCn2ezzDA6/k7ec2ooltU+3IIQSRiamHwHNA==", + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.17.1.tgz", + "integrity": "sha512-pWfniN6NuVKUq40KACuD3NCMe+bWNQCpD3cmxL6aLSCTwPKYmf7l4Lp0/E/almpjvxhybJZtFLU0w4tmxnIKaA==", "license": "MIT", "dependencies": { "@egjs/hammerjs": "^2.0.17", @@ -37484,9 +37484,9 @@ } }, "react-native-gesture-handler": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.17.0.tgz", - "integrity": "sha512-FzEOlLTo83OEBnCKwgwQTnsnlVHMVHu6xRNrxHpPRllfSBlpfyHCn2ezzDA6/k7ec2ooltU+3IIQSRiamHwHNA==", + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.17.1.tgz", + "integrity": "sha512-pWfniN6NuVKUq40KACuD3NCMe+bWNQCpD3cmxL6aLSCTwPKYmf7l4Lp0/E/almpjvxhybJZtFLU0w4tmxnIKaA==", "requires": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", diff --git a/package.json b/package.json index c8c2528fa1..edeb624f67 100644 --- a/package.json +++ b/package.json @@ -155,7 +155,7 @@ "react-native-document-picker": "https://github.com/BlueWallet/react-native-document-picker#6033c4e1b0dd0a6760b5f5a5a2c3b2e5d07f2ae4", "react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#ebfddc4", "react-native-fs": "2.20.0", - "react-native-gesture-handler": "2.17.0", + "react-native-gesture-handler": "2.17.1", "react-native-handoff": "https://github.com/BlueWallet/react-native-handoff#31d005f93d31099d0e564590a3bbd052b8a02b39", "react-native-haptic-feedback": "2.2.0", "react-native-idle-timer": "https://github.com/BlueWallet/react-native-idle-timer#7300b637c465c86e8db874c442e687950111da40", From 9f890100d0f3a640c603cc355213287021012c5e Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 18:06:18 +0000 Subject: [PATCH 34/37] Translate loc/en.json in es_419 100% reviewed source file: 'loc/en.json' on 'es_419'. --- loc/es_419.json | 1 + 1 file changed, 1 insertion(+) diff --git a/loc/es_419.json b/loc/es_419.json index 0fa4f5bdd5..1a246700f1 100644 --- a/loc/es_419.json +++ b/loc/es_419.json @@ -428,6 +428,7 @@ "details_show_xpub": "Mostrar el XPUB de la Billetera", "details_show_addresses": "Mostrar direcciones", "details_title": "Billetera", + "wallets": "Billeteras", "details_type": "Tipo", "details_use_with_hardware_wallet": "Usar con Billetera de Hardware", "details_wallet_updated": "Billetera actualizada", From e3417b1c85c160fedf5e1326c29cc3687c2dcfc8 Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 22 Jun 2024 12:08:57 -0400 Subject: [PATCH 35/37] Update SettingsButton.tsx --- components/icons/SettingsButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/icons/SettingsButton.tsx b/components/icons/SettingsButton.tsx index 1cb2fdea99..77d5ae0331 100644 --- a/components/icons/SettingsButton.tsx +++ b/components/icons/SettingsButton.tsx @@ -17,7 +17,7 @@ const SettingsButton = () => { accessibilityRole="button" accessibilityLabel={loc.settings.default_title} testID="SettingsButton" - style={[style.buttonStyle, { backgroundColor: colors.darkGray }]} + style={[style.buttonStyle, { backgroundColor: colors.lightButton }]} onPress={onPress} > From 86032b80f55c994675883499634da3c140a1b64f Mon Sep 17 00:00:00 2001 From: Marcos Rodriguez Velez Date: Sat, 22 Jun 2024 14:30:29 -0400 Subject: [PATCH 36/37] ADD: Watch only wallets warning --- class/wallets/watch-only-wallet.ts | 1 + components/WatchOnlyWarning.tsx | 61 ++++++++++++++++++++++++++++++ loc/en.json | 4 +- screen/wallets/transactions.js | 12 +++++- 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 components/WatchOnlyWarning.tsx diff --git a/class/wallets/watch-only-wallet.ts b/class/wallets/watch-only-wallet.ts index c27c161b3f..ca889ed3bb 100644 --- a/class/wallets/watch-only-wallet.ts +++ b/class/wallets/watch-only-wallet.ts @@ -18,6 +18,7 @@ export class WatchOnlyWallet extends LegacyWallet { public readonly type = WatchOnlyWallet.type; // @ts-ignore: override public readonly typeReadable = WatchOnlyWallet.typeReadable; + public isWatchOnlyWarningVisible = true; public _hdWalletInstance?: THDWalletForWatchOnly; use_with_hardware_wallet = false; diff --git a/components/WatchOnlyWarning.tsx b/components/WatchOnlyWarning.tsx new file mode 100644 index 0000000000..047ea39287 --- /dev/null +++ b/components/WatchOnlyWarning.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; +import { Icon } from '@rneui/themed'; +import loc from '../loc'; + +interface Props { + handleDismiss: () => void; + isLoading?: boolean; +} + +const WatchOnlyWarning: React.FC = ({ handleDismiss, isLoading }) => { + return ( + + + + + + + {loc.transactions.watchOnlyWarningTitle} + {loc.transactions.watchOnlyWarningDescription} + + + ); +}; + +const styles = StyleSheet.create({ + container: { + backgroundColor: '#ff4c4c', + padding: 16, + margin: 16, + borderRadius: 8, + position: 'relative', + }, + dismissButton: { + position: 'absolute', + top: 8, + right: 8, + backgroundColor: 'black', + borderRadius: 15, + width: 30, + height: 30, + justifyContent: 'center', + alignItems: 'center', + zIndex: 1, + }, + content: { + alignItems: 'center', + }, + title: { + color: 'white', + fontWeight: 'bold', + marginBottom: 8, + marginTop: 8, + }, + description: { + color: 'white', + textAlign: 'center', + }, +}); + +export default WatchOnlyWarning; diff --git a/loc/en.json b/loc/en.json index c9ca242bde..976559dcb0 100644 --- a/loc/en.json +++ b/loc/en.json @@ -382,7 +382,9 @@ "txid": "Transaction ID", "from": "From: {counterparty}", "to": "To: {counterparty}", - "updating": "Updating..." + "updating": "Updating...", + "watchOnlyWarningTitle": "Scam Alert", + "watchOnlyWarningDescription": "Be aware that scammers usually use this type of wallet 'watch-only' to try to steal from users. This wallet you cannot control or send from it, only allows to watch the balance." }, "wallets": { "add_bitcoin": "Bitcoin", diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index 2ca35df945..066fb65a09 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -42,6 +42,7 @@ import { Chain } from '../../models/bitcoinUnits'; import ActionSheet from '../ActionSheet'; import { useStorage } from '../../hooks/context/useStorage'; import { WalletTransactionsStatus } from '../../components/Context/StorageProvider'; +import WatchOnlyWarning from '../../components/WatchOnlyWarning'; const buttonFontSize = PixelRatio.roundToNearestPixel(Dimensions.get('window').width / 26) > 22 @@ -286,7 +287,6 @@ const WalletTransactions = ({ navigation }) => { ); }; - const onWalletSelect = async selectedWallet => { if (selectedWallet) { navigate('WalletTransactions', { @@ -530,6 +530,16 @@ const WalletTransactions = ({ navigation }) => { }} /> + {wallet.type === WatchOnlyWallet.type && wallet.isWatchOnlyWarningVisible && ( + { + wallet.isWatchOnlyWarningVisible = false; + LayoutAnimation.configureNext(LayoutAnimation.Presets.linear); + saveToDisk(); + }} + /> + )} Date: Sat, 22 Jun 2024 16:43:48 -0400 Subject: [PATCH 37/37] Revert "Merge pull request #6718 from BlueWallet/h" (#6739) --- components/Header.tsx | 33 ++++----------------- navigation/DetailViewScreensStack.tsx | 37 +++++++++++++++++++---- screen/settings/SettingsPrivacy.tsx | 2 +- screen/wallets/DrawerList.tsx | 2 +- screen/wallets/WalletsList.tsx | 42 ++------------------------- 5 files changed, 43 insertions(+), 73 deletions(-) diff --git a/components/Header.tsx b/components/Header.tsx index 4beb47cccf..1be637b977 100644 --- a/components/Header.tsx +++ b/components/Header.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { StyleSheet, Text, Animated } from 'react-native'; +import { StyleSheet, Text, View } from 'react-native'; + import loc from '../loc'; import PlusIcon from './icons/PlusIcon'; import { useTheme } from './themes'; @@ -8,11 +9,9 @@ interface HeaderProps { leftText: string; isDrawerList?: boolean; onNewWalletPress?: () => void; - scrollY?: Animated.Value; - staticText?: boolean; } -export const Header: React.FC = ({ leftText, isDrawerList, onNewWalletPress, scrollY, staticText = false }) => { +export const Header: React.FC = ({ leftText, isDrawerList, onNewWalletPress }) => { const { colors } = useTheme(); const styleWithProps = StyleSheet.create({ root: { @@ -25,31 +24,11 @@ export const Header: React.FC = ({ leftText, isDrawerList, onNewWal }, }); - const HEADER_MAX_HEIGHT = 55; - const HEADER_MIN_HEIGHT = 0; - const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT; - - const headerHeightAnimated = scrollY?.interpolate({ - inputRange: [0, HEADER_SCROLL_DISTANCE], - outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT], - extrapolate: 'clamp', - }); - - const headerOpacity = scrollY?.interpolate({ - inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE], - outputRange: [1, 0.5, 0], - extrapolate: 'clamp', - }); - return ( - - {staticText ? ( - {leftText} - ) : ( - {leftText} - )} + + {leftText} {onNewWalletPress && } - + ); }; diff --git a/navigation/DetailViewScreensStack.tsx b/navigation/DetailViewScreensStack.tsx index 38e6a4cf3f..c9aab42499 100644 --- a/navigation/DetailViewScreensStack.tsx +++ b/navigation/DetailViewScreensStack.tsx @@ -1,10 +1,11 @@ -import React, { useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { NativeStackNavigationOptions } from '@react-navigation/native-stack'; -import { I18nManager } from 'react-native'; +import { I18nManager, View } from 'react-native'; import { isDesktop } from '../blue_modules/environment'; import HeaderRightButton from '../components/HeaderRightButton'; import navigationStyle, { CloseButtonPosition } from '../components/navigationStyle'; import { useTheme } from '../components/themes'; +import { useExtendedNavigation } from '../hooks/useExtendedNavigation'; import loc from '../loc'; import LdkInfo from '../screen/lnd/ldkInfo'; import LNDViewAdditionalInvoiceInformation from '../screen/lnd/lndViewAdditionalInvoiceInformation'; @@ -63,26 +64,41 @@ import SignVerifyStackRoot from './SignVerifyStack'; import ViewEditMultisigCosignersStackRoot from './ViewEditMultisigCosignersStack'; import WalletExportStack from './WalletExportStack'; import WalletXpubStackRoot from './WalletXpubStack'; +import PlusIcon from '../components/icons/PlusIcon'; import SettingsButton from '../components/icons/SettingsButton'; const DetailViewStackScreensStack = () => { const theme = useTheme(); + const navigation = useExtendedNavigation(); const SaveButton = useMemo(() => , []); const DetailButton = useMemo(() => , []); + const navigateToAddWallet = useCallback(() => { + navigation.navigate('AddWalletRoot'); + }, [navigation]); + const useWalletListScreenOptions = useMemo(() => { + const RightBarButtons = ( + <> + + + + + ); + return { title: loc.wallets.wallets, navigationBarColor: theme.colors.navigationBarColor, headerShown: !isDesktop, + headerLargeTitle: true, headerStyle: { backgroundColor: theme.colors.customHeader, }, - headerRight: I18nManager.isRTL ? undefined : () => , - headerLeft: I18nManager.isRTL ? () => : undefined, + headerRight: I18nManager.isRTL ? undefined : () => RightBarButtons, + headerLeft: I18nManager.isRTL ? () => RightBarButtons : undefined, }; - }, [theme.colors.customHeader, theme.colors.navigationBarColor]); + }, [navigateToAddWallet, theme.colors.customHeader, theme.colors.navigationBarColor]); const walletListScreenOptions = useWalletListScreenOptions; return ( @@ -145,6 +161,8 @@ const DetailViewStackScreensStack = () => { backgroundColor: theme.colors.customHeader, }, headerRight: () => DetailButton, + headerBackTitleStyle: { fontSize: 0 }, + headerBackTitleVisible: true, })(theme)} /> @@ -250,6 +268,9 @@ const DetailViewStackScreensStack = () => { options={navigationStyle({ headerTransparent: true, title: loc.settings.header, + // workaround to deal with the flicker when headerBackTitleVisible is false + headerBackTitleStyle: { fontSize: 0 }, + headerBackTitleVisible: true, headerShadowVisible: false, headerLargeTitle: true, animationTypeForReplace: 'push', @@ -367,3 +388,9 @@ const DetailViewStackScreensStack = () => { }; export default DetailViewStackScreensStack; + +const styles = { + width24: { + width: 24, + }, +}; diff --git a/screen/settings/SettingsPrivacy.tsx b/screen/settings/SettingsPrivacy.tsx index 7be6f50671..b192d53175 100644 --- a/screen/settings/SettingsPrivacy.tsx +++ b/screen/settings/SettingsPrivacy.tsx @@ -102,7 +102,7 @@ const SettingsPrivacy: React.FC = () => { {Platform.OS === 'android' ? ( -
+
) : null} diff --git a/screen/wallets/DrawerList.tsx b/screen/wallets/DrawerList.tsx index caa1d63824..f16e91ac65 100644 --- a/screen/wallets/DrawerList.tsx +++ b/screen/wallets/DrawerList.tsx @@ -142,7 +142,7 @@ const DrawerList: React.FC = memo(({ navigation }) => { showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} > -
+
{ } = useStorage(); const { width } = useWindowDimensions(); const { colors, scanImage } = useTheme(); - const { navigate, setOptions } = useExtendedNavigation(); + const { navigate } = useExtendedNavigation(); const isFocused = useIsFocused(); const routeName = useRoute().name; const dataSource = getTransactions(undefined, 10); const walletsCount = useRef(wallets.length); const walletActionButtonsRef = useRef(); - const scrollY = useRef(new Animated.Value(0)).current; - const stylesHook = StyleSheet.create({ walletsListWrapper: { backgroundColor: colors.brandingColor, @@ -162,21 +149,6 @@ const WalletsList: React.FC = () => { walletsCount.current = wallets.length; }, [wallets]); - const HeaderTitle = useMemo(() => { - const titleOpacity = scrollY.interpolate({ - inputRange: [0, 200], - outputRange: [0, 1], - extrapolate: 'clamp', - }); - return {loc.wallets.list_title}; - }, [scrollY]); - - useEffect(() => { - setOptions({ - headerTitle: () => HeaderTitle, - }); - }, [HeaderTitle, scrollY, setOptions]); - const verifyBalance = useCallback(() => { if (getBalance() !== 0) { A(A.ENUM.GOT_NONZERO_BALANCE); @@ -433,7 +405,6 @@ const WalletsList: React.FC = () => { return ( -
navigate('AddWalletRoot')} scrollY={scrollY} /> removeClippedSubviews @@ -450,8 +421,6 @@ const WalletsList: React.FC = () => { windowSize={21} maxToRenderPerBatch={10} updateCellsBatchingPeriod={50} - onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: false })} - scrollEventThrottle={16} /> {renderScanButton()} @@ -504,9 +473,4 @@ const styles = StyleSheet.create({ transaction: { marginHorizontal: 0, }, - nativeHeaderTitle: { - fontSize: 17, - fontWeight: '600', - color: 'black', // adjust color if necessary - }, });