mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-13 11:09:20 +01:00
Merge branch 'master' into virw
This commit is contained in:
commit
d7743a740f
30 changed files with 556 additions and 392 deletions
110
.github/workflows/build-ios-release-pullrequest.yml
vendored
110
.github/workflows/build-ios-release-pullrequest.yml
vendored
|
@ -22,12 +22,26 @@ jobs:
|
|||
branch_name: ${{ steps.get_latest_commit_details.outputs.branch_name }}
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
MATCH_READONLY: "true"
|
||||
|
||||
steps:
|
||||
- name: Checkout Project
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Ensures the full Git history is available
|
||||
|
||||
- name: Setup Caching
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/Library/Caches/CocoaPods
|
||||
ios/Pods
|
||||
~/.npm
|
||||
node_modules
|
||||
vendor/bundle
|
||||
key: ${{ runner.os }}-ios-${{ hashFiles('**/package-lock.json', '**/Podfile.lock', '**/Gemfile.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ios-
|
||||
|
||||
- name: Clear All Caches
|
||||
if: github.ref == 'refs/heads/master'
|
||||
|
@ -81,15 +95,32 @@ jobs:
|
|||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: 16.2.0
|
||||
xcode-version: latest
|
||||
|
||||
- name: Install iOS Simulator Runtime
|
||||
run: |
|
||||
echo "Available iOS simulator runtimes:"
|
||||
xcrun simctl list runtimes
|
||||
|
||||
# Try to download the latest iOS 16.x simulator if not present
|
||||
if (! xcrun simctl list runtimes | grep -q "iOS 16"); then
|
||||
echo "Installing iOS 16.4 simulator..."
|
||||
sudo xcode-select -s /Applications/Xcode.app
|
||||
xcodebuild -downloadPlatform iOS
|
||||
fi
|
||||
|
||||
echo "Available iOS simulator runtimes after install:"
|
||||
xcrun simctl list runtimes
|
||||
|
||||
- name: Set Up Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.1.6
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install Dependencies with Bundler
|
||||
run: |
|
||||
|
@ -102,6 +133,7 @@ jobs:
|
|||
- name: Install CocoaPods Dependencies
|
||||
run: |
|
||||
bundle exec fastlane ios install_pods
|
||||
echo "CocoaPods dependencies installed successfully"
|
||||
|
||||
- name: Generate Build Number Based on Timestamp
|
||||
id: generate_build_number
|
||||
|
@ -147,8 +179,26 @@ jobs:
|
|||
- name: Build App
|
||||
id: build_app
|
||||
run: |
|
||||
bundle exec fastlane ios build_app_lane --verbose
|
||||
echo "ipa_output_path=$IPA_OUTPUT_PATH" >> $GITHUB_OUTPUT # Set the IPA output path for future jobs
|
||||
bundle exec fastlane ios build_app_lane
|
||||
|
||||
# Ensure IPA path is set for subsequent steps
|
||||
if [ -f "./ios/build/ipa_path.txt" ]; then
|
||||
IPA_PATH=$(cat ./ios/build/ipa_path.txt)
|
||||
echo "IPA_OUTPUT_PATH=$IPA_PATH" >> $GITHUB_ENV
|
||||
echo "ipa_output_path=$IPA_PATH" >> $GITHUB_OUTPUT
|
||||
echo "Found IPA at: $IPA_PATH"
|
||||
else
|
||||
echo "Warning: ipa_path.txt not found, trying to locate IPA file manually..."
|
||||
IPA_PATH=$(find ./ios -name "*.ipa" | head -n 1)
|
||||
if [ -n "$IPA_PATH" ]; then
|
||||
echo "IPA_OUTPUT_PATH=$IPA_PATH" >> $GITHUB_ENV
|
||||
echo "ipa_output_path=$IPA_PATH" >> $GITHUB_OUTPUT
|
||||
echo "Found IPA at: $IPA_PATH"
|
||||
else
|
||||
echo "Error: No IPA file found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Upload Bugsnag Sourcemaps
|
||||
if: success()
|
||||
|
@ -156,8 +206,8 @@ jobs:
|
|||
env:
|
||||
BUGSNAG_API_KEY: ${{ secrets.BUGSNAG_API_KEY }}
|
||||
BUGSNAG_RELEASE_STAGE: production
|
||||
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
|
||||
NEW_BUILD_NUMBER: ${{ needs.build.outputs.new_build_number }}
|
||||
PROJECT_VERSION: ${{ env.PROJECT_VERSION }}
|
||||
NEW_BUILD_NUMBER: ${{ env.NEW_BUILD_NUMBER }}
|
||||
|
||||
- name: Upload Build Logs
|
||||
if: always()
|
||||
|
@ -165,13 +215,32 @@ jobs:
|
|||
with:
|
||||
name: build_logs
|
||||
path: ./ios/build_logs/
|
||||
retention-days: 7
|
||||
|
||||
- name: Verify IPA File Before Upload
|
||||
run: |
|
||||
echo "Checking IPA file at: $IPA_OUTPUT_PATH"
|
||||
if [ -f "$IPA_OUTPUT_PATH" ]; then
|
||||
echo "✅ IPA file exists"
|
||||
ls -la "$IPA_OUTPUT_PATH"
|
||||
else
|
||||
echo "❌ IPA file not found at: $IPA_OUTPUT_PATH"
|
||||
echo "Current directory contents:"
|
||||
find ./ios -name "*.ipa"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload IPA as Artifact
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: BlueWallet_${{env.PROJECT_VERSION}}_${{env.NEW_BUILD_NUMBER}}.ipa
|
||||
path: ${{ env.IPA_OUTPUT_PATH }} # Directly from Fastfile `IPA_OUTPUT_PATH`
|
||||
name: BlueWallet_IPA
|
||||
path: ${{ env.IPA_OUTPUT_PATH }}
|
||||
retention-days: 7
|
||||
|
||||
- name: Delete Temporary Keychain
|
||||
if: always()
|
||||
run: bundle exec fastlane ios delete_temp_keychain
|
||||
|
||||
testflight-upload:
|
||||
needs: build
|
||||
|
@ -191,6 +260,7 @@ jobs:
|
|||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.1.6
|
||||
bundler-cache: true
|
||||
|
||||
- name: Install Dependencies with Bundler
|
||||
run: |
|
||||
|
@ -200,18 +270,11 @@ jobs:
|
|||
- name: Download IPA from Artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: BlueWallet_${{ needs.build.outputs.project_version }}_${{ needs.build.outputs.new_build_number }}.ipa
|
||||
name: BlueWallet_IPA
|
||||
path: ./
|
||||
|
||||
- name: Create App Store Connect API Key JSON
|
||||
run: echo '${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}' > ./appstore_api_key.json
|
||||
|
||||
- name: Verify IPA File Download
|
||||
run: |
|
||||
echo "Current directory:"
|
||||
pwd
|
||||
echo "Files in current directory:"
|
||||
ls -la ./
|
||||
|
||||
- name: Set IPA Path Environment Variable
|
||||
run: echo "IPA_OUTPUT_PATH=$(pwd)/BlueWallet_${{ needs.build.outputs.project_version }}_${{ needs.build.outputs.new_build_number }}.ipa" >> $GITHUB_ENV
|
||||
|
@ -219,19 +282,23 @@ jobs:
|
|||
- name: Verify IPA Path Before Upload
|
||||
run: |
|
||||
if [ ! -f "$IPA_OUTPUT_PATH" ]; then
|
||||
echo "IPA file not found at path: $IPA_OUTPUT_PATH"
|
||||
echo "❌ IPA file not found at path: $IPA_OUTPUT_PATH"
|
||||
ls -la $(pwd)
|
||||
exit 1
|
||||
else
|
||||
echo "✅ Found IPA at: $IPA_OUTPUT_PATH"
|
||||
fi
|
||||
|
||||
- name: Print Environment Variables for Debugging
|
||||
run: |
|
||||
echo "LATEST_COMMIT_MESSAGE: $LATEST_COMMIT_MESSAGE"
|
||||
echo "BRANCH_NAME: $BRANCH_NAME"
|
||||
echo "PROJECT_VERSION: $PROJECT_VERSION"
|
||||
echo "NEW_BUILD_NUMBER: $NEW_BUILD_NUMBER"
|
||||
echo "IPA_OUTPUT_PATH: $IPA_OUTPUT_PATH"
|
||||
|
||||
- name: Upload to TestFlight
|
||||
run: |
|
||||
ls -la $IPA_OUTPUT_PATH
|
||||
bundle exec fastlane ios upload_to_testflight_lane
|
||||
run: bundle exec fastlane ios upload_to_testflight_lane
|
||||
env:
|
||||
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/appstore_api_key.p8
|
||||
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
|
||||
|
@ -242,18 +309,19 @@ jobs:
|
|||
APP_STORE_CONNECT_API_KEY_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_KEY_ID }}
|
||||
APP_STORE_CONNECT_API_KEY_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ISSUER_ID }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
IPA_OUTPUT_PATH: ${{ env.IPA_OUTPUT_PATH }}
|
||||
|
||||
- name: Post PR Comment
|
||||
if: success() && github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
BUILD_NUMBER: ${{ needs.build.outputs.new_build_number }}
|
||||
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
|
||||
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
|
||||
with:
|
||||
script: |
|
||||
const buildNumber = process.env.BUILD_NUMBER;
|
||||
const message = `The build ${buildNumber} has been uploaded to TestFlight.`;
|
||||
const version = process.env.PROJECT_VERSION;
|
||||
const message = `✅ Build ${version} (${buildNumber}) has been uploaded to TestFlight and will be available for testing soon.`;
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
const repo = context.repo;
|
||||
github.rest.issues.createComment({
|
||||
|
|
8
Gemfile
8
Gemfile
|
@ -3,10 +3,14 @@ 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 'rubyzip', '2.4.1'
|
||||
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1'
|
||||
gem 'cocoapods', '~> 1.14.3'
|
||||
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
|
||||
gem "fastlane", ">= 2.225.0"
|
||||
gem "fastlane", "~> 2.226.0"
|
||||
gem 'xcodeproj', '< 1.26.0'
|
||||
gem 'concurrent-ruby', '< 1.3.4'
|
||||
|
||||
# Required for App Store Connect API
|
||||
gem "jwt"
|
||||
|
||||
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
|
||||
eval_gemfile(plugins_path) if File.exist?(plugins_path)
|
||||
|
|
44
Gemfile.lock
44
Gemfile.lock
|
@ -24,18 +24,18 @@ GEM
|
|||
json (>= 1.5.1)
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.1050.0)
|
||||
aws-sdk-core (3.218.1)
|
||||
aws-eventstream (1.3.1)
|
||||
aws-partitions (1.1058.0)
|
||||
aws-sdk-core (3.219.0)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.98.0)
|
||||
aws-sdk-kms (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.180.0)
|
||||
aws-sdk-s3 (1.182.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
|
@ -46,10 +46,10 @@ GEM
|
|||
benchmark (0.4.0)
|
||||
bigdecimal (3.1.9)
|
||||
claide (1.1.0)
|
||||
cocoapods (1.15.2)
|
||||
cocoapods (1.14.3)
|
||||
addressable (~> 2.8)
|
||||
claide (>= 1.0.2, < 2.0)
|
||||
cocoapods-core (= 1.15.2)
|
||||
cocoapods-core (= 1.14.3)
|
||||
cocoapods-deintegrate (>= 1.0.3, < 2.0)
|
||||
cocoapods-downloader (>= 2.1, < 3.0)
|
||||
cocoapods-plugins (>= 1.0.0, < 2.0)
|
||||
|
@ -64,7 +64,7 @@ GEM
|
|||
nap (~> 1.0)
|
||||
ruby-macho (>= 2.3.0, < 3.0)
|
||||
xcodeproj (>= 1.23.0, < 2.0)
|
||||
cocoapods-core (1.15.2)
|
||||
cocoapods-core (1.14.3)
|
||||
activesupport (>= 5.0, < 8)
|
||||
addressable (~> 2.8)
|
||||
algoliasearch (~> 1.0)
|
||||
|
@ -173,6 +173,9 @@ GEM
|
|||
xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
|
||||
fastlane-plugin-browserstack (0.3.3)
|
||||
rest-client (~> 2.0, >= 2.0.2)
|
||||
fastlane-plugin-bugsnag (2.3.1)
|
||||
git
|
||||
xml-simple
|
||||
fastlane-plugin-bugsnag_sourcemaps_upload (0.2.0)
|
||||
fastlane-sirp (1.0.0)
|
||||
sysrandom (~> 1.0)
|
||||
|
@ -180,6 +183,11 @@ GEM
|
|||
fourflusher (2.3.1)
|
||||
fuzzy_match (2.0.4)
|
||||
gh_inspector (1.1.3)
|
||||
git (3.0.0)
|
||||
activesupport (>= 5.0)
|
||||
addressable (~> 2.8)
|
||||
process_executer (~> 1.3)
|
||||
rchardet (~> 1.9)
|
||||
google-apis-androidpublisher_v3 (0.54.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-core (0.11.3)
|
||||
|
@ -220,24 +228,26 @@ GEM
|
|||
http-accept (1.7.0)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.6.2)
|
||||
json (2.10.1)
|
||||
jwt (2.10.1)
|
||||
base64
|
||||
logger (1.6.5)
|
||||
logger (1.6.6)
|
||||
mime-types (3.6.0)
|
||||
logger
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2025.0204)
|
||||
mime-types-data (3.2025.0220)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.4)
|
||||
molinillo (0.8.0)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
mutex_m (0.3.0)
|
||||
nanaimo (0.3.0)
|
||||
nap (1.1.0)
|
||||
naturally (2.2.1)
|
||||
|
@ -246,8 +256,10 @@ GEM
|
|||
optparse (0.6.0)
|
||||
os (1.1.4)
|
||||
plist (3.7.2)
|
||||
process_executer (1.3.0)
|
||||
public_suffix (4.0.7)
|
||||
rake (13.2.1)
|
||||
rchardet (1.9.0)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
|
@ -258,7 +270,7 @@ GEM
|
|||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
retriable (3.1.2)
|
||||
rexml (3.4.0)
|
||||
rexml (3.4.1)
|
||||
rouge (3.28.0)
|
||||
ruby-macho (2.5.1)
|
||||
ruby2_keywords (0.0.5)
|
||||
|
@ -300,17 +312,21 @@ GEM
|
|||
rouge (~> 3.28.0)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
xml-simple (1.1.9)
|
||||
rexml
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
activesupport (>= 6.1.7.5, != 7.1.0)
|
||||
cocoapods (>= 1.13, != 1.15.1, != 1.15.0)
|
||||
cocoapods (~> 1.14.3)
|
||||
concurrent-ruby (< 1.3.4)
|
||||
fastlane (>= 2.225.0)
|
||||
fastlane (~> 2.226.0)
|
||||
fastlane-plugin-browserstack
|
||||
fastlane-plugin-bugsnag
|
||||
fastlane-plugin-bugsnag_sourcemaps_upload
|
||||
jwt
|
||||
rubyzip (= 2.4.1)
|
||||
xcodeproj (< 1.26.0)
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
|
|
|
@ -12,7 +12,6 @@ class BitcoinPriceWidget : AppWidgetProvider() {
|
|||
companion object {
|
||||
private const val TAG = "BitcoinPriceWidget"
|
||||
private const val SHARED_PREF_NAME = "group.io.bluewallet.bluewallet"
|
||||
private const val WIDGET_COUNT_KEY = "widget_count"
|
||||
}
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
|
@ -25,21 +24,12 @@ class BitcoinPriceWidget : AppWidgetProvider() {
|
|||
|
||||
override fun onEnabled(context: Context) {
|
||||
super.onEnabled(context)
|
||||
val sharedPref = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
||||
val widgetCount = sharedPref.getInt(WIDGET_COUNT_KEY, 0)
|
||||
if (widgetCount >= 1) {
|
||||
Toast.makeText(context, "Only one widget instance is allowed.", Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, "Attempted to add multiple widget instances.")
|
||||
return
|
||||
}
|
||||
sharedPref.edit().putInt(WIDGET_COUNT_KEY, widgetCount + 1).apply()
|
||||
Log.d(TAG, "onEnabled called")
|
||||
WidgetUpdateWorker.scheduleWork(context)
|
||||
}
|
||||
|
||||
override fun onDisabled(context: Context) {
|
||||
super.onDisabled(context)
|
||||
clearWidgetCount(context)
|
||||
Log.d(TAG, "onDisabled called")
|
||||
clearCache(context)
|
||||
WorkManager.getInstance(context).cancelUniqueWork(WidgetUpdateWorker.WORK_NAME)
|
||||
|
@ -47,19 +37,9 @@ class BitcoinPriceWidget : AppWidgetProvider() {
|
|||
|
||||
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
|
||||
super.onDeleted(context, appWidgetIds)
|
||||
val sharedPref = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
||||
val widgetCount = sharedPref.getInt(WIDGET_COUNT_KEY, 1)
|
||||
val newCount = widgetCount - appWidgetIds.size
|
||||
sharedPref.edit().putInt(WIDGET_COUNT_KEY, if (newCount >= 0) newCount else 0).apply()
|
||||
Log.d(TAG, "onDeleted called for widgets: ${appWidgetIds.joinToString()}")
|
||||
}
|
||||
|
||||
private fun clearWidgetCount(context: Context) {
|
||||
val sharedPref = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
||||
sharedPref.edit().putInt(WIDGET_COUNT_KEY, 0).apply()
|
||||
Log.d(TAG, "Widget count reset to 0")
|
||||
}
|
||||
|
||||
private fun clearCache(context: Context) {
|
||||
val sharedPref = context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE)
|
||||
sharedPref.edit().clear().apply()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Platform, Pressable, TouchableOpacity } from 'react-native';
|
||||
import { Platform, TouchableOpacity } from 'react-native';
|
||||
import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu';
|
||||
import { ContextMenuView, RenderItem, OnPressMenuItemEventObject, IconConfig, MenuElementConfig } from 'react-native-ios-context-menu';
|
||||
import { ToolTipMenuProps, Action } from './types';
|
||||
import { useSettings } from '../hooks/context/useSettings';
|
||||
|
||||
|
@ -9,11 +8,8 @@ const ToolTipMenu = (props: ToolTipMenuProps) => {
|
|||
const {
|
||||
title = '',
|
||||
isMenuPrimaryAction = false,
|
||||
renderPreview,
|
||||
disabled = false,
|
||||
onPress,
|
||||
onMenuWillShow,
|
||||
onMenuWillHide,
|
||||
buttonStyle,
|
||||
onPressMenuItem,
|
||||
children,
|
||||
|
@ -23,18 +19,6 @@ const ToolTipMenu = (props: ToolTipMenuProps) => {
|
|||
|
||||
const { language } = useSettings();
|
||||
|
||||
// Map Menu Items for iOS Context Menu
|
||||
const mapMenuItemForContextMenuView = useCallback((action: Action) => {
|
||||
if (!action.id) return null;
|
||||
return {
|
||||
actionKey: action.id.toString(),
|
||||
actionTitle: action.text,
|
||||
icon: action.icon?.iconValue ? ({ iconType: 'SYSTEM', iconValue: action.icon.iconValue } as IconConfig) : undefined,
|
||||
state: action.menuState ?? undefined,
|
||||
attributes: action.disabled ? ['disabled'] : [],
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Map Menu Items for RN Menu (supports subactions and displayInline)
|
||||
const mapMenuItemForMenuView = useCallback((action: Action): MenuAction | null => {
|
||||
if (!action.id) return null;
|
||||
|
@ -88,11 +72,6 @@ const ToolTipMenu = (props: ToolTipMenuProps) => {
|
|||
return menuItem;
|
||||
}, []);
|
||||
|
||||
const contextMenuItems = useMemo(() => {
|
||||
const flattenedActions = props.actions.flat().filter(action => action.id);
|
||||
return flattenedActions.map(mapMenuItemForContextMenuView).filter(item => item !== null) as MenuElementConfig[];
|
||||
}, [props.actions, mapMenuItemForContextMenuView]);
|
||||
|
||||
const menuViewItemsIOS = useMemo(() => {
|
||||
return props.actions
|
||||
.map(actionGroup => {
|
||||
|
@ -119,13 +98,6 @@ const ToolTipMenu = (props: ToolTipMenuProps) => {
|
|||
return mergedActions.map(mapMenuItemForMenuView).filter(item => item !== null) as MenuAction[];
|
||||
}, [props.actions, mapMenuItemForMenuView]);
|
||||
|
||||
const handlePressMenuItemForContextMenuView = useCallback(
|
||||
(event: OnPressMenuItemEventObject) => {
|
||||
onPressMenuItem(event.nativeEvent.actionKey);
|
||||
},
|
||||
[onPressMenuItem],
|
||||
);
|
||||
|
||||
const handlePressMenuItemForMenuView = useCallback(
|
||||
({ nativeEvent }: NativeActionEvent) => {
|
||||
onPressMenuItem(nativeEvent.event);
|
||||
|
@ -133,46 +105,6 @@ const ToolTipMenu = (props: ToolTipMenuProps) => {
|
|||
[onPressMenuItem],
|
||||
);
|
||||
|
||||
const renderContextMenuView = () => {
|
||||
return (
|
||||
<ContextMenuView
|
||||
lazyPreview
|
||||
accessibilityLabel={props.accessibilityLabel}
|
||||
accessibilityHint={props.accessibilityHint}
|
||||
accessibilityRole={props.accessibilityRole}
|
||||
accessibilityState={props.accessibilityState}
|
||||
accessibilityLanguage={language}
|
||||
shouldEnableAggressiveCleanup
|
||||
internalCleanupMode="automatic"
|
||||
onPressMenuItem={handlePressMenuItemForContextMenuView}
|
||||
onMenuWillShow={onMenuWillShow}
|
||||
onMenuWillHide={onMenuWillHide}
|
||||
useActionSheetFallback={false}
|
||||
menuConfig={{
|
||||
menuTitle: title,
|
||||
menuItems: contextMenuItems,
|
||||
}}
|
||||
{...(renderPreview
|
||||
? {
|
||||
previewConfig: {
|
||||
previewType: 'CUSTOM',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
renderPreview: renderPreview as RenderItem,
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
{onPress ? (
|
||||
<Pressable accessibilityRole="button" onPress={onPress} {...restProps}>
|
||||
{children}
|
||||
</Pressable>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</ContextMenuView>
|
||||
);
|
||||
};
|
||||
|
||||
const renderMenuView = () => {
|
||||
return (
|
||||
<MenuView
|
||||
|
@ -198,7 +130,7 @@ const ToolTipMenu = (props: ToolTipMenuProps) => {
|
|||
);
|
||||
};
|
||||
|
||||
return props.actions.length > 0 ? (Platform.OS === 'ios' && renderPreview ? renderContextMenuView() : renderMenuView()) : null;
|
||||
return props.actions.length > 0 ? renderMenuView() : null;
|
||||
};
|
||||
|
||||
export default ToolTipMenu;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState, memo } from 'react';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { Linking, View, ViewStyle } from 'react-native';
|
||||
|
@ -36,7 +36,7 @@ interface TransactionListItemProps {
|
|||
|
||||
type NavigationProps = NativeStackNavigationProp<DetailViewStackParamList>;
|
||||
|
||||
export const TransactionListItem: React.FC<TransactionListItemProps> = React.memo(
|
||||
export const TransactionListItem: React.FC<TransactionListItemProps> = memo(
|
||||
({ item, itemPriceUnit = BitcoinUnit.BTC, walletID, searchQuery, style, renderHighlightedText }) => {
|
||||
const [subtitleNumberOfLines, setSubtitleNumberOfLines] = useState(1);
|
||||
const { colors } = useTheme();
|
||||
|
@ -367,4 +367,12 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
|
|||
</ToolTipMenu>
|
||||
);
|
||||
},
|
||||
(prevProps, nextProps) => {
|
||||
return (
|
||||
prevProps.item.hash === nextProps.item.hash &&
|
||||
prevProps.item.received === nextProps.item.received &&
|
||||
prevProps.itemPriceUnit === nextProps.itemPriceUnit &&
|
||||
prevProps.walletID === nextProps.walletID
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
@ -149,6 +149,7 @@ const AddressItem = ({ item, balanceUnit, walletID, allowSignVerifyMessage }: Ad
|
|||
title={item.address}
|
||||
actions={menuActions}
|
||||
onPressMenuItem={onToolTipPress}
|
||||
// Revisit once RNMenu has renderPreview prop
|
||||
renderPreview={renderPreview}
|
||||
onPress={navigateToReceive}
|
||||
isButton
|
||||
|
|
|
@ -192,6 +192,40 @@ end
|
|||
# ===========================
|
||||
|
||||
platform :ios do
|
||||
# Add helper methods for error handling and retries
|
||||
def ensure_env_vars(vars)
|
||||
vars.each do |var|
|
||||
UI.user_error!("#{var} environment variable is missing") if ENV[var].nil? || ENV[var].empty?
|
||||
end
|
||||
end
|
||||
|
||||
def log_success(message)
|
||||
UI.success("✅ #{message}")
|
||||
end
|
||||
|
||||
def log_error(message)
|
||||
UI.error("❌ #{message}")
|
||||
end
|
||||
|
||||
# Method to safely call actions with retry logic
|
||||
def with_retry(max_attempts = 3, action_name = "")
|
||||
attempts = 0
|
||||
begin
|
||||
attempts += 1
|
||||
yield
|
||||
rescue => e
|
||||
if attempts < max_attempts
|
||||
wait_time = 10 * attempts
|
||||
log_error("Attempt #{attempts}/#{max_attempts} for #{action_name} failed: #{e.message}")
|
||||
UI.message("Retrying in #{wait_time} seconds...")
|
||||
sleep(wait_time)
|
||||
retry
|
||||
else
|
||||
log_error("#{action_name} failed after #{max_attempts} attempts: #{e.message}")
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Register new devices from a file"
|
||||
lane :register_devices_from_txt do
|
||||
|
@ -238,26 +272,33 @@ platform :ios do
|
|||
|
||||
desc "Synchronize certificates and provisioning profiles"
|
||||
lane :setup_provisioning_profiles do
|
||||
required_vars = ["GIT_ACCESS_TOKEN", "GIT_URL", "ITC_TEAM_ID", "ITC_TEAM_NAME", "KEYCHAIN_PASSWORD"]
|
||||
ensure_env_vars(required_vars)
|
||||
|
||||
UI.message("Setting up provisioning profiles...")
|
||||
|
||||
platform = "ios"
|
||||
|
||||
|
||||
# Iterate over app identifiers to fetch provisioning profiles
|
||||
app_identifiers.each do |app_identifier|
|
||||
match(
|
||||
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
||||
git_url: ENV["GIT_URL"],
|
||||
type: "appstore",
|
||||
clone_branch_directly: true, # Skip if the branch already exists
|
||||
platform: platform,
|
||||
app_identifier: app_identifier,
|
||||
team_id: ENV["ITC_TEAM_ID"],
|
||||
team_name: ENV["ITC_TEAM_NAME"],
|
||||
readonly: true,
|
||||
keychain_name: "temp_keychain",
|
||||
keychain_password: ENV["KEYCHAIN_PASSWORD"]
|
||||
)
|
||||
with_retry(3, "Fetching provisioning profile for #{app_identifier}") do
|
||||
UI.message("Fetching provisioning profile for #{app_identifier}...")
|
||||
match(
|
||||
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
|
||||
git_url: ENV["GIT_URL"],
|
||||
type: "appstore",
|
||||
clone_branch_directly: true,
|
||||
platform: "ios",
|
||||
app_identifier: app_identifier,
|
||||
team_id: ENV["ITC_TEAM_ID"],
|
||||
team_name: ENV["ITC_TEAM_NAME"],
|
||||
readonly: true,
|
||||
keychain_name: "temp_keychain",
|
||||
keychain_password: ENV["KEYCHAIN_PASSWORD"]
|
||||
)
|
||||
log_success("Successfully fetched provisioning profile for #{app_identifier}")
|
||||
end
|
||||
end
|
||||
|
||||
log_success("All provisioning profiles set up")
|
||||
end
|
||||
|
||||
desc "Fetch development certificates and provisioning profiles for Mac Catalyst"
|
||||
|
@ -402,48 +443,114 @@ lane :upload_bugsnag_sourcemaps do
|
|||
end
|
||||
|
||||
desc "Build the iOS app"
|
||||
lane :build_app_lane do
|
||||
Dir.chdir(project_root) do
|
||||
UI.message("Building the application from: #{Dir.pwd}")
|
||||
lane :build_app_lane do
|
||||
Dir.chdir(project_root) do
|
||||
UI.message("Building the application from: #{Dir.pwd}")
|
||||
|
||||
workspace_path = File.join(project_root, "ios", "BlueWallet.xcworkspace")
|
||||
export_options_path = File.join(project_root, "ios", "export_options.plist")
|
||||
workspace_path = File.join(project_root, "ios", "BlueWallet.xcworkspace")
|
||||
export_options_path = File.join(project_root, "ios", "export_options.plist")
|
||||
|
||||
clear_derived_data_lane
|
||||
|
||||
begin
|
||||
build_ios_app(
|
||||
scheme: "BlueWallet",
|
||||
workspace: workspace_path,
|
||||
export_method: "app-store",
|
||||
include_bitcode: false,
|
||||
configuration: "Release",
|
||||
skip_profile_detection: false,
|
||||
include_symbols: true,
|
||||
export_team_id: ENV["ITC_TEAM_ID"],
|
||||
export_options: export_options_path,
|
||||
output_directory: File.join(project_root, "ios", "build"),
|
||||
output_name: "BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa",
|
||||
buildlog_path: File.join(project_root, "ios", "build_logs"),
|
||||
silent: false,
|
||||
clean: true
|
||||
)
|
||||
rescue => e
|
||||
UI.user_error!("build_ios_app failed: #{e.message}")
|
||||
end
|
||||
clear_derived_data_lane
|
||||
|
||||
# Determine which iOS version to use
|
||||
ios_version = determine_ios_version
|
||||
|
||||
# Use File.join to construct paths without extra slashes
|
||||
ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH]
|
||||
UI.message("Using iOS version: #{ios_version}")
|
||||
UI.message("Using export options from: #{export_options_path}")
|
||||
|
||||
# Define the IPA output path before building
|
||||
ipa_directory = File.join(project_root, "ios", "build")
|
||||
ipa_name = "BlueWallet_#{ENV['PROJECT_VERSION']}_#{ENV['NEW_BUILD_NUMBER']}.ipa"
|
||||
ipa_path = File.join(ipa_directory, ipa_name)
|
||||
|
||||
begin
|
||||
build_ios_app(
|
||||
scheme: "BlueWallet",
|
||||
workspace: workspace_path,
|
||||
export_method: "app-store",
|
||||
export_options: export_options_path,
|
||||
output_directory: ipa_directory,
|
||||
output_name: ipa_name,
|
||||
buildlog_path: File.join(project_root, "ios", "build_logs"),
|
||||
)
|
||||
rescue => e
|
||||
UI.user_error!("build_ios_app failed: #{e.message}")
|
||||
end
|
||||
|
||||
if ipa_path && File.exist?(ipa_path)
|
||||
UI.message("IPA successfully found at: #{ipa_path}")
|
||||
# Check for IPA path from both our defined path and fastlane's context
|
||||
ipa_path = lane_context[SharedValues::IPA_OUTPUT_PATH] || ipa_path
|
||||
|
||||
# Ensure the directory exists
|
||||
FileUtils.mkdir_p(File.dirname(ipa_path)) unless Dir.exist?(File.dirname(ipa_path))
|
||||
|
||||
if ipa_path && File.exist?(ipa_path)
|
||||
UI.message("IPA successfully found at: #{ipa_path}")
|
||||
else
|
||||
# Try to find any IPA file as fallback
|
||||
Dir.chdir(project_root) do
|
||||
fallback_ipa = Dir.glob("**/*.ipa").first
|
||||
if fallback_ipa
|
||||
ipa_path = File.join(project_root, fallback_ipa)
|
||||
UI.message("Found fallback IPA at: #{ipa_path}")
|
||||
else
|
||||
UI.user_error!("No IPA file found after build")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Set both environment variable and GitHub Actions output
|
||||
ENV['IPA_OUTPUT_PATH'] = ipa_path
|
||||
sh("echo 'IPA_OUTPUT_PATH=#{ipa_path}' >> $GITHUB_ENV") # Export for GitHub Actions
|
||||
else
|
||||
UI.user_error!("IPA not found after build_ios_app.")
|
||||
# Set both standard output format and the newer GITHUB_OUTPUT format
|
||||
sh("echo 'ipa_output_path=#{ipa_path}' >> $GITHUB_OUTPUT") if ENV['GITHUB_OUTPUT']
|
||||
sh("echo ::set-output name=ipa_output_path::#{ipa_path}")
|
||||
|
||||
# Also write path to a file that can be read by subsequent steps
|
||||
ipa_path_file = "#{ipa_directory}/ipa_path.txt"
|
||||
File.write(ipa_path_file, ipa_path)
|
||||
UI.success("Saved IPA path to: #{ipa_path_file}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Delete temporary keychain"
|
||||
lane :delete_temp_keychain do
|
||||
UI.message("Deleting temporary keychain...")
|
||||
|
||||
delete_keychain(
|
||||
name: "temp_keychain"
|
||||
) if File.exist?(File.expand_path("~/Library/Keychains/temp_keychain-db"))
|
||||
|
||||
UI.message("Temporary keychain deleted successfully.")
|
||||
end
|
||||
|
||||
# Helper method to determine which iOS version to use
|
||||
private_lane :determine_ios_version do
|
||||
# Get available iOS simulator runtimes
|
||||
runtimes_output = sh("xcrun simctl list runtimes 2>&1", log: false) rescue ""
|
||||
|
||||
if runtimes_output.include?("iOS")
|
||||
# Extract available iOS versions
|
||||
ios_versions = runtimes_output.scan(/iOS ([0-9.]+)/)
|
||||
.flatten
|
||||
.map { |v| Gem::Version.new(v) }
|
||||
.sort
|
||||
.reverse
|
||||
|
||||
if ios_versions.any?
|
||||
latest_version = ios_versions.first.to_s
|
||||
UI.success("Found iOS simulator version: #{latest_version}")
|
||||
latest_version # Implicit return - last expression is returned
|
||||
else
|
||||
# Default to a reasonable iOS version if none found
|
||||
UI.important("No iOS simulator versions found. Using default version.")
|
||||
"17.6" # Implicit return
|
||||
end
|
||||
else
|
||||
# Default to a reasonable iOS version if no iOS runtimes
|
||||
UI.important("No iOS simulator runtimes found. Using default version.")
|
||||
"17.6" # Implicit return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
# ===========================
|
||||
# Global Lanes
|
||||
|
|
|
@ -3,33 +3,39 @@
|
|||
# URL of the Git repository to store the certificates
|
||||
git_url(ENV["GIT_URL"])
|
||||
|
||||
# Define the type of match to run, could be one of 'appstore', 'adhoc', 'development', or 'enterprise'.
|
||||
# For example, use 'appstore' for App Store builds, 'adhoc' for Ad Hoc distribution,
|
||||
# 'development' for development builds, and 'enterprise' for In-House (enterprise) distribution.
|
||||
type("appstore")
|
||||
# Define the type of match to run
|
||||
# Default to "appstore" but can be overridden
|
||||
type(ENV["MATCH_TYPE"] || "appstore")
|
||||
|
||||
app_identifier(["io.bluewallet.bluewallet", "io.bluewallet.bluewallet.watch", "io.bluewallet.bluewallet.watch.extension", "io.bluewallet.bluewallet.Stickers", "io.bluewallet.bluewallet.MarketWidget"]) # Replace with your app identifiers
|
||||
# App identifiers for all BlueWallet apps
|
||||
app_identifier([
|
||||
"io.bluewallet.bluewallet",
|
||||
"io.bluewallet.bluewallet.watch",
|
||||
"io.bluewallet.bluewallet.watch.extension",
|
||||
"io.bluewallet.bluewallet.Stickers",
|
||||
"io.bluewallet.bluewallet.MarketWidget"
|
||||
])
|
||||
|
||||
# List of app identifiers to create provisioning profiles for.
|
||||
# Replace with your app's bundle identifier(s).
|
||||
|
||||
# Your Apple Developer account email address.
|
||||
# Your Apple Developer account email address
|
||||
username(ENV["APPLE_ID"])
|
||||
|
||||
# The ID of your Apple Developer team if you're part of multiple teams
|
||||
# The ID of your Apple Developer team
|
||||
team_id(ENV["ITC_TEAM_ID"])
|
||||
|
||||
# Set this to true if match should only read existing certificates and profiles
|
||||
# and not create new ones.
|
||||
readonly(true)
|
||||
# Set readonly based on environment (default to true for safety)
|
||||
# Set to false explicitly when new profiles need to be created
|
||||
readonly(ENV["MATCH_READONLY"] == "false" ? false : true)
|
||||
|
||||
# Optional: The Git branch that is used for match.
|
||||
# Default is 'master'.
|
||||
|
||||
# Optional: Path to a specific SSH key to be used by match.
|
||||
# Only needed if you're using a private repository and match needs to use SSH keys for authentication.
|
||||
# ssh_key("/path/to/your/private/key")
|
||||
|
||||
# Optional: Define the platform to use, can be 'ios', 'macos', or 'tvos'.
|
||||
# For React Native projects, you'll typically use 'ios'.
|
||||
# Define the platform to use
|
||||
platform("ios")
|
||||
|
||||
# Git basic authentication through access token
|
||||
# This is useful for CI/CD environments where SSH keys aren't available
|
||||
git_basic_authorization(ENV["GIT_ACCESS_TOKEN"])
|
||||
|
||||
# Storage mode (git by default)
|
||||
storage_mode("git")
|
||||
|
||||
# Optional: The Git branch that is used for match
|
||||
# Default is 'master'
|
||||
# branch("main")
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
|
||||
gem 'fastlane-plugin-browserstack'
|
||||
gem 'fastlane-plugin-bugsnag_sourcemaps_upload'
|
||||
gem "fastlane-plugin-bugsnag"
|
||||
|
|
23
helpers/screenProtect.ts
Normal file
23
helpers/screenProtect.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// import { enableSecureView, disableSecureView, forbidAndroidShare, allowAndroidShare } from 'react-native-prevent-screenshot-ios-android';
|
||||
// import { Platform } from 'react-native';
|
||||
// import { isDesktop } from '../blue_modules/environment';
|
||||
|
||||
export const enableScreenProtect = () => {
|
||||
// if (isDesktop) return;
|
||||
// if (Platform.OS === 'ios') {
|
||||
// enableSecureView();
|
||||
// } else if (Platform.OS === 'android') {
|
||||
// forbidAndroidShare();
|
||||
// }
|
||||
};
|
||||
|
||||
export const disableScreenProtect = () => {
|
||||
// if (isDesktop) return;
|
||||
// if (Platform.OS === 'ios') {
|
||||
// disableSecureView();
|
||||
// } else if (Platform.OS === 'android') {
|
||||
// allowAndroidShare();
|
||||
// }
|
||||
};
|
||||
|
||||
// CURRENTLY UNUSED AS WE WAIT FOR NAV 7 SUPPORT
|
|
@ -164,7 +164,7 @@
|
|||
B4D0B2682C1DED67006B6B1B /* ReceiveMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4D0B2672C1DED67006B6B1B /* ReceiveMethod.swift */; };
|
||||
B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
||||
B4EFF73B2C3F6C5E0095D655 /* MockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4EFF73A2C3F6C5E0095D655 /* MockData.swift */; };
|
||||
C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
|
||||
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -428,7 +428,7 @@
|
|||
files = (
|
||||
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */,
|
||||
764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */,
|
||||
C978A716948AB7DEC5B6F677 /* (null) in Frameworks */,
|
||||
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */,
|
||||
17CDA0718F42DB2CE856C872 /* libPods-BlueWallet.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -1584,7 +1584,7 @@
|
|||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = Stickers/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
|
@ -1627,7 +1627,7 @@
|
|||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = Stickers/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/usr/lib/swift",
|
||||
"$(SDKROOT)/System/iOSSupport/usr/lib/swift",
|
||||
|
|
|
@ -1297,7 +1297,7 @@ PODS:
|
|||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- react-native-image-picker (7.2.3):
|
||||
- react-native-image-picker (8.2.0):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
|
@ -1318,10 +1318,29 @@ PODS:
|
|||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- react-native-ios-context-menu (1.15.3):
|
||||
- React-Core
|
||||
- react-native-menu (1.2.1):
|
||||
- React
|
||||
- react-native-prevent-screenshot-ios-android (1.1.0):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2024.01.01.00)
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
- React-Core
|
||||
- React-debug
|
||||
- React-Fabric
|
||||
- React-featureflags
|
||||
- React-graphics
|
||||
- React-ImageManager
|
||||
- React-NativeModulesApple
|
||||
- React-RCTFabric
|
||||
- React-rendererdebug
|
||||
- React-utils
|
||||
- ReactCodegen
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- react-native-randombytes (3.6.1):
|
||||
- React-Core
|
||||
- react-native-safe-area-context (5.2.0):
|
||||
|
@ -1841,7 +1860,7 @@ PODS:
|
|||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- RNShare (11.1.0):
|
||||
- RNShare (12.0.9):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
|
@ -1939,8 +1958,8 @@ DEPENDENCIES:
|
|||
- react-native-bw-file-access (from `../blue_modules/react-native-bw-file-access`)
|
||||
- react-native-document-picker (from `../node_modules/react-native-document-picker`)
|
||||
- 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-prevent-screenshot-ios-android (from `../node_modules/react-native-prevent-screenshot-ios-android`)
|
||||
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- react-native-screen-capture (from `../node_modules/react-native-screen-capture`)
|
||||
|
@ -2094,10 +2113,10 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native-document-picker"
|
||||
react-native-image-picker:
|
||||
: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-prevent-screenshot-ios-android:
|
||||
:path: "../node_modules/react-native-prevent-screenshot-ios-android"
|
||||
react-native-randombytes:
|
||||
:path: "../node_modules/react-native-randombytes"
|
||||
react-native-safe-area-context:
|
||||
|
@ -2258,9 +2277,9 @@ SPEC CHECKSUMS:
|
|||
react-native-blue-crypto: de5babd59b17fbf3fc31d2e1e5d59ec859093fbc
|
||||
react-native-bw-file-access: fe925b77dbf48500df0b294c6851f8c84607a203
|
||||
react-native-document-picker: 530879d9e89b490f0954bcc4ab697c5b5e35d659
|
||||
react-native-image-picker: 130fad649d07e4eec8faaed361d3bba570e1e5ff
|
||||
react-native-ios-context-menu: 986da6dcba70094bcc2a8049f68410fe7d25aff1
|
||||
react-native-image-picker: 86f8954a0b8c0f85d56fa1d85ae87936ae74e615
|
||||
react-native-menu: 2cfe0a3b3c610ed331f00d9f0df300db14ba8692
|
||||
react-native-prevent-screenshot-ios-android: 490b2ae701658753e819ca215201f4aa8cab3d53
|
||||
react-native-randombytes: 3c8f3e89d12487fd03a2f966c288d495415fc116
|
||||
react-native-safe-area-context: 3e33e7c43c8b74dba436a5a32651cb8d7064c740
|
||||
react-native-screen-capture: 7b6121f529681ed2fde36cdedadd0bb39e9a3796
|
||||
|
@ -2313,7 +2332,7 @@ SPEC CHECKSUMS:
|
|||
RNReactNativeHapticFeedback: 00ba111b82aa266bb3ee1aa576831c2ea9a9dfad
|
||||
RNReanimated: 66cf0f600a26d2b5e74c6e0b1c77c1ab1f62fc05
|
||||
RNScreens: b3975354ddafe0fb00112a9054898ccf0d92c78e
|
||||
RNShare: 6204e6a1987ba3e7c47071ef703e5449a0e3548a
|
||||
RNShare: 381ed02f6c0dc42b8c24bb5a1e5df0ee5fd91354
|
||||
RNSVG: a07e14363aa208062c6483bad24a438d5986d490
|
||||
RNVectorIcons: 182892e7d1a2f27b52d3c627eca5d2665a22ee28
|
||||
RNWatch: 28fe1f5e0c6410d45fd20925f4796fce05522e3f
|
||||
|
@ -2323,4 +2342,4 @@ SPEC CHECKSUMS:
|
|||
|
||||
PODFILE CHECKSUM: eb430c3fd96af23d4962c4c041798d65efc6843e
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
COCOAPODS: 1.14.3
|
||||
|
|
115
package-lock.json
generated
115
package-lock.json
generated
|
@ -26,10 +26,10 @@
|
|||
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#038a9c9",
|
||||
"@react-native/gradle-plugin": "0.76.7",
|
||||
"@react-native/metro-config": "0.76.7",
|
||||
"@react-navigation/devtools": "7.0.15",
|
||||
"@react-navigation/drawer": "7.1.1",
|
||||
"@react-navigation/native": "7.0.14",
|
||||
"@react-navigation/native-stack": "7.2.0",
|
||||
"@react-navigation/devtools": "7.0.16",
|
||||
"@react-navigation/drawer": "7.1.2",
|
||||
"@react-navigation/native": "7.0.15",
|
||||
"@react-navigation/native-stack": "7.2.1",
|
||||
"@rneui/base": "4.0.0-rc.8",
|
||||
"@rneui/themed": "4.0.0-rc.8",
|
||||
"@spsina/bip47": "github:BlueWallet/bip47#df82345",
|
||||
|
@ -77,12 +77,12 @@
|
|||
"react-native-gesture-handler": "2.23.1",
|
||||
"react-native-handoff": "github:BlueWallet/react-native-handoff#v0.0.4",
|
||||
"react-native-haptic-feedback": "2.3.3",
|
||||
"react-native-image-picker": "7.2.3",
|
||||
"react-native-ios-context-menu": "github:BlueWallet/react-native-ios-context-menu#e5c1217cd220bfab6e6d9a7c65838545082e3f8e",
|
||||
"react-native-image-picker": "8.2.0",
|
||||
"react-native-keychain": "9.1.0",
|
||||
"react-native-linear-gradient": "2.8.3",
|
||||
"react-native-localize": "3.4.1",
|
||||
"react-native-permissions": "5.2.5",
|
||||
"react-native-prevent-screenshot-ios-android": "github:BlueWallet/react-native-prevent-screenshot-ios-android#133004e",
|
||||
"react-native-prompt-android": "github:BlueWallet/react-native-prompt-android#ed168d66fed556bc2ed07cf498770f058b78a376",
|
||||
"react-native-push-notification": "8.1.1",
|
||||
"react-native-qrcode-svg": "6.3.12",
|
||||
|
@ -94,7 +94,7 @@
|
|||
"react-native-screen-capture": "github:BlueWallet/react-native-screen-capture#18cb79f",
|
||||
"react-native-screens": "4.9.1",
|
||||
"react-native-secure-key-store": "github:BlueWallet/react-native-secure-key-store#2076b4849e88aa0a78e08bfbb4ce3923e0925cbc",
|
||||
"react-native-share": "11.1.0",
|
||||
"react-native-share": "12.0.9",
|
||||
"react-native-svg": "15.11.2",
|
||||
"react-native-tcp-socket": "6.2.0",
|
||||
"react-native-vector-icons": "10.2.0",
|
||||
|
@ -2459,12 +2459,6 @@
|
|||
"bugsnag-source-maps": "bin/cli"
|
||||
}
|
||||
},
|
||||
"node_modules/@dominicstop/ts-event-emitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@dominicstop/ts-event-emitter/-/ts-event-emitter-1.1.0.tgz",
|
||||
"integrity": "sha512-CcxmJIvUb1vsFheuGGVSQf4KdPZC44XolpUT34+vlal+LyQoBUOn31pjFET5M9ctOxEpt8xa0M3/2M7uUiAoJw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@egjs/hammerjs": {
|
||||
"version": "2.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
||||
|
@ -4701,7 +4695,7 @@
|
|||
"node_modules/@lodev09/react-native-true-sheet": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-true-sheet.git#5945184a2fea9fe5ba8f5cfcdb20e3fc5eed6e37",
|
||||
"integrity": "sha512-KmqW5bBFowvbZ0d3u960PUx+avPZ80IaRPHszvarI5leeYrkTSUGqEeVVAQnaBHMfl5u6rrOVA4NoJHPsqU0Vg==",
|
||||
"integrity": "sha512-JoMgC3w8Xgzvb4zHRnBdycBDuhz1O8MuKh9LE3QJjCElcm8x0n3asHzrt+XaLs3XfVrvq/LNyIMQSSYtvvhFKA==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"example",
|
||||
|
@ -6614,12 +6608,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/core": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.3.1.tgz",
|
||||
"integrity": "sha512-S3KCGvNsoqVk8ErAtQI2EAhg9185lahF5OY01ofrrD4Ij/uk3QEHHjoGQhR5l5DXSCSKr1JbMQA7MEKMsBiWZA==",
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.4.0.tgz",
|
||||
"integrity": "sha512-URiDluFl7cLA7GtOAsEvRqPmEMlSSXadqQ3wi9+Dl43dNRMqnoF76WQ9BCXeUPLydJq4yVte9XeMPyD6a0lY1g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^7.1.2",
|
||||
"@react-navigation/routers": "^7.2.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"nanoid": "3.3.8",
|
||||
"query-string": "^7.1.3",
|
||||
|
@ -6638,9 +6632,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-navigation/devtools": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/devtools/-/devtools-7.0.15.tgz",
|
||||
"integrity": "sha512-pxEBVtd6e5ocT7bs6k6ghOJNyb9Fzxm+EYHemHQ53GEin1sQKYpsSHWZEJdFj1cxYp+/+KCT+TueuNDFkJOr4Q==",
|
||||
"version": "7.0.16",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/devtools/-/devtools-7.0.16.tgz",
|
||||
"integrity": "sha512-3rWR5TmI+JhxFyJMQXcAEdPumBIThpI1pj0YInON6u8olpL7nD5QGdGXaF71hilPpjID43+tgtV98fcAvhzzOA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
|
@ -6652,18 +6646,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/drawer": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-7.1.1.tgz",
|
||||
"integrity": "sha512-34UqRS5OLFaNXPs5ocz3Du9c7em0P7fFMPYCZn/MxadDzQ4Mn/74pmJczmiyvyvz8vcWsNRbZ3Qswm0Dv6z60w==",
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-7.1.2.tgz",
|
||||
"integrity": "sha512-EIlS5PPzVQ9WJ4xQZytAUTXiVbZcUYfPFlkaAWZHIl7O/suoJIpu52yXwjbjG0XhNu6Vup23W35HJWHxpgKQEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": "^2.2.5",
|
||||
"@react-navigation/elements": "^2.2.6",
|
||||
"color": "^4.2.3",
|
||||
"react-native-drawer-layout": "^4.1.1",
|
||||
"use-latest-callback": "^0.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^7.0.14",
|
||||
"@react-navigation/native": "^7.0.15",
|
||||
"react": ">= 18.2.0",
|
||||
"react-native": "*",
|
||||
"react-native-gesture-handler": ">= 2.0.0",
|
||||
|
@ -6673,16 +6667,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/elements": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.5.tgz",
|
||||
"integrity": "sha512-sDhE+W14P7MNWLMxXg1MEVXwkLUpMZJGflE6nQNzLmolJQIHgcia0Mrm8uRa3bQovhxYu1UzEojLZ+caoZt7Fg==",
|
||||
"version": "2.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.2.6.tgz",
|
||||
"integrity": "sha512-UPeaCcEDSDRaxjG+qEHbur6jmNW/f9QNCyPsUt6NMgPEdbB5Z8K8oSx2swIaiCnvUbs/K5G3MuWkqQxGj8QXXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color": "^4.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-native-masked-view/masked-view": ">= 0.2.0",
|
||||
"@react-navigation/native": "^7.0.14",
|
||||
"@react-navigation/native": "^7.0.15",
|
||||
"react": ">= 18.2.0",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 4.0.0"
|
||||
|
@ -6694,12 +6688,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native": {
|
||||
"version": "7.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.14.tgz",
|
||||
"integrity": "sha512-Gi6lLw4VOGSWAhmUdJOMauOKGK51/YA1CprjXm91sNfgERWvznqEMw8QmUQx9SEqYfi0LfZhbzpMst09SJ00lw==",
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.0.15.tgz",
|
||||
"integrity": "sha512-72PabJJ8VY3GM8i/DCutFW+ATED96ZV6NH+bW+ry1EL0ZFGHoie96H+KzTqktsrUbBw1rd9KXbEQhBQgo0N7iQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^7.3.1",
|
||||
"@react-navigation/core": "^7.4.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"nanoid": "3.3.8",
|
||||
|
@ -6711,16 +6705,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native-stack": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.2.0.tgz",
|
||||
"integrity": "sha512-mw7Nq9qQrGsmJmCTwIIWB7yY/3tWYXvQswx+HJScGAadIjemvytJXm1fcl3+YZ9T9Ym0aERcVe5kDs+ny3X4vA==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.2.1.tgz",
|
||||
"integrity": "sha512-zqC6DVpO4pFZrl+8JuIgV8qk+AGdTuv+hJ5EHePmzs9gYSUrDpw6LahFCiXshwBvi9LinIw9Do7mtnQK2Q8AGA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": "^2.2.5",
|
||||
"@react-navigation/elements": "^2.2.6",
|
||||
"warn-once": "^0.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^7.0.14",
|
||||
"@react-navigation/native": "^7.0.15",
|
||||
"react": ">= 18.2.0",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 4.0.0",
|
||||
|
@ -6728,9 +6722,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/routers": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.1.2.tgz",
|
||||
"integrity": "sha512-emdEjpVDK8zbiu2GChC8oYIAub9i/OpNuQJekVsbyFCBz4/TzaBzms38Q53YaNhdIFNmiYLfHv/Y1Ub7KYfm3w==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.2.0.tgz",
|
||||
"integrity": "sha512-lMyib39H4a//u+eiyt162U6TwCfI8zJbjl9ovjKtDddQ4/Vf7b8/OhyimnJH09N2CBfm4pv0gCV6Q0WnZcfaJg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "3.3.8"
|
||||
|
@ -22257,28 +22251,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-native-image-picker": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-7.2.3.tgz",
|
||||
"integrity": "sha512-zKIZUlQNU3EtqizsXSH92zPeve4vpUrsqHu2kkpCxWE9TZhJFZBb+irDsBOY8J21k0+Edgt06TMQGJ+iPUIXyA==",
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-8.2.0.tgz",
|
||||
"integrity": "sha512-jIGllQJuJIn0YKss/JEeb0Kos1HSsnIpU+i3bYxR27sOxSyDZQyP9dKR22olssQPlfH+rGNR/Jc6xKRkhm48vw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-ios-context-menu": {
|
||||
"version": "1.15.3",
|
||||
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-ios-context-menu.git#e5c1217cd220bfab6e6d9a7c65838545082e3f8e",
|
||||
"integrity": "sha512-cQnRYOcP3zGQpCEm7w8oSAKDibX3Ncu8G4xof3mXCbXkqwM00Vdbref8ZJcK9omBY5vwEvyNjFLQ+C/NW47iyQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@dominicstop/ts-event-emitter": "^1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-keychain": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-keychain/-/react-native-keychain-9.1.0.tgz",
|
||||
|
@ -22334,6 +22315,18 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-prevent-screenshot-ios-android": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-prevent-screenshot-ios-android.git#133004eff4b2e95176ad2a8cc1d6aa61ea43be98",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-prompt-android": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-prompt-android.git#ed168d66fed556bc2ed07cf498770f058b78a376",
|
||||
|
@ -22482,9 +22475,9 @@
|
|||
"license": "ISC"
|
||||
},
|
||||
"node_modules/react-native-share": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-11.1.0.tgz",
|
||||
"integrity": "sha512-kcpBR90d5//xc8H84HnX6YFeOk4A34mtHz4UEpb7Twbu049KafJwsp4KVVr/SrJwy8W0/Rbe880En9Hq0REamw==",
|
||||
"version": "12.0.9",
|
||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-12.0.9.tgz",
|
||||
"integrity": "sha512-vSuz/9aF+/AZS3I5NC19MrB56h1Yivk2Yz8lf2d8Szv3KuRw2BnDI/AfCTjMWByJLVYr6xgzfkTkAfvbDGzxLQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
|
|
14
package.json
14
package.json
|
@ -94,9 +94,10 @@
|
|||
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#038a9c9",
|
||||
"@react-native/gradle-plugin": "0.76.7",
|
||||
"@react-native/metro-config": "0.76.7",
|
||||
"@react-navigation/drawer": "7.1.1",
|
||||
"@react-navigation/native": "7.0.14",
|
||||
"@react-navigation/native-stack": "7.2.0",
|
||||
"@react-navigation/devtools": "7.0.16",
|
||||
"@react-navigation/drawer": "7.1.2",
|
||||
"@react-navigation/native": "7.0.15",
|
||||
"@react-navigation/native-stack": "7.2.1",
|
||||
"@rneui/base": "4.0.0-rc.8",
|
||||
"@rneui/themed": "4.0.0-rc.8",
|
||||
"@spsina/bip47": "github:BlueWallet/bip47#df82345",
|
||||
|
@ -144,12 +145,12 @@
|
|||
"react-native-gesture-handler": "2.23.1",
|
||||
"react-native-handoff": "github:BlueWallet/react-native-handoff#v0.0.4",
|
||||
"react-native-haptic-feedback": "2.3.3",
|
||||
"react-native-image-picker": "7.2.3",
|
||||
"react-native-ios-context-menu": "github:BlueWallet/react-native-ios-context-menu#e5c1217cd220bfab6e6d9a7c65838545082e3f8e",
|
||||
"react-native-image-picker": "8.2.0",
|
||||
"react-native-keychain": "9.1.0",
|
||||
"react-native-linear-gradient": "2.8.3",
|
||||
"react-native-localize": "3.4.1",
|
||||
"react-native-permissions": "5.2.5",
|
||||
"react-native-prevent-screenshot-ios-android": "github:BlueWallet/react-native-prevent-screenshot-ios-android#133004e",
|
||||
"react-native-prompt-android": "github:BlueWallet/react-native-prompt-android#ed168d66fed556bc2ed07cf498770f058b78a376",
|
||||
"react-native-push-notification": "8.1.1",
|
||||
"react-native-qrcode-svg": "6.3.12",
|
||||
|
@ -157,12 +158,11 @@
|
|||
"react-native-randombytes": "3.6.1",
|
||||
"react-native-rate": "1.2.12",
|
||||
"react-native-reanimated": "3.16.7",
|
||||
"@react-navigation/devtools": "7.0.15",
|
||||
"react-native-safe-area-context": "5.2.0",
|
||||
"react-native-screen-capture": "github:BlueWallet/react-native-screen-capture#18cb79f",
|
||||
"react-native-screens": "4.9.1",
|
||||
"react-native-secure-key-store": "github:BlueWallet/react-native-secure-key-store#2076b4849e88aa0a78e08bfbb4ce3923e0925cbc",
|
||||
"react-native-share": "11.1.0",
|
||||
"react-native-share": "12.0.9",
|
||||
"react-native-svg": "15.11.2",
|
||||
"react-native-tcp-socket": "6.2.0",
|
||||
"react-native-vector-icons": "10.2.0",
|
||||
|
|
|
@ -9,17 +9,16 @@ import { Icon } from '@rneui/themed';
|
|||
import RNFS from 'react-native-fs';
|
||||
import { PERMISSIONS, request, RESULTS } from 'react-native-permissions';
|
||||
import Share from 'react-native-share';
|
||||
|
||||
import { satoshiToBTC } from '../../blue_modules/currency';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { BlueSpacing20, BlueText } from '../../BlueComponents';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import { DynamicQRCode } from '../../components/DynamicQRCode';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import loc from '../../loc';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
const SendCreate = () => {
|
||||
const { fee, recipients, memo = '', satoshiPerByte, psbt, showAnimatedQr, tx } = useRoute().params;
|
||||
|
@ -49,9 +48,11 @@ const SendCreate = () => {
|
|||
|
||||
useEffect(() => {
|
||||
console.log('send/create - useEffect');
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]);
|
||||
|
||||
|
|
|
@ -7,12 +7,11 @@ import { DynamicQRCode } from '../../components/DynamicQRCode';
|
|||
import SaveFileButton from '../../components/SaveFileButton';
|
||||
import { SquareButton } from '../../components/SquareButton';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import loc from '../../loc';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import { ExportMultisigCoordinationSetupStackRootParamList } from '../../navigation/ExportMultisigCoordinationSetupStack';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
const enum ActionType {
|
||||
SET_LOADING = 'SET_LOADING',
|
||||
|
@ -102,7 +101,6 @@ const ExportMultisigCoordinationSetup: React.FC = () => {
|
|||
dispatch({ type: ActionType.SET_LOADING, isLoading: true });
|
||||
|
||||
const task = InteractionManager.runAfterInteractions(() => {
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (wallet) {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
|
@ -128,12 +126,22 @@ const ExportMultisigCoordinationSetup: React.FC = () => {
|
|||
|
||||
return () => {
|
||||
task.cancel();
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [walletID]),
|
||||
);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
return () => {
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]),
|
||||
);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (closeButtonState) {
|
||||
|
|
|
@ -2,7 +2,6 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
import { RouteProp, useRoute } from '@react-navigation/native';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { Keyboard, Platform, ScrollView, StyleSheet, TouchableWithoutFeedback, View, TouchableOpacity, Image } from 'react-native';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { BlueFormLabel, BlueFormMultiInput, BlueSpacing20 } from '../../BlueComponents';
|
||||
import Button from '../../components/Button';
|
||||
import {
|
||||
|
@ -18,8 +17,8 @@ import loc from '../../loc';
|
|||
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { AddressInputScanButton } from '../../components/AddressInputScanButton';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportWallet'>;
|
||||
type NavigationProps = NativeStackNavigationProp<AddWalletStackParamList, 'ImportWallet'>;
|
||||
|
@ -156,9 +155,11 @@ const ImportWallet = () => {
|
|||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]);
|
||||
|
||||
|
|
|
@ -16,10 +16,9 @@ import { useStorage } from '../../hooks/context/useStorage';
|
|||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { THDWalletForWatchOnly, TWallet } from '../../class/wallets/types';
|
||||
import { keepAwake, disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportWalletDiscovery'>;
|
||||
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'ImportWalletDiscovery'>;
|
||||
|
@ -39,7 +38,7 @@ const ImportWalletDiscovery: React.FC = () => {
|
|||
const { colors } = useTheme();
|
||||
const route = useRoute<RouteProps>();
|
||||
const { importText, askPassphrase, searchAccounts } = route.params;
|
||||
const { isElectrumDisabled } = useSettings();
|
||||
const { isElectrumDisabled, isPrivacyBlurEnabled } = useSettings();
|
||||
const task = useRef<TImport | null>(null);
|
||||
const { addAndSaveWallet } = useStorage();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
@ -115,7 +114,6 @@ const ImportWalletDiscovery: React.FC = () => {
|
|||
}
|
||||
};
|
||||
|
||||
if (!isDesktop) keepAwake(true);
|
||||
task.current = startImport(importText, askPassphrase, searchAccounts, isElectrumDisabled, onProgress, onWallet, onPassword);
|
||||
|
||||
task.current.promise
|
||||
|
@ -134,22 +132,24 @@ const ImportWalletDiscovery: React.FC = () => {
|
|||
.finally(() => {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
setLoading(false);
|
||||
if (!isDesktop) keepAwake(false);
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (!isDesktop) keepAwake(false);
|
||||
task.current?.stop();
|
||||
};
|
||||
}, [askPassphrase, importText, isElectrumDisabled, navigation, saveWallet, searchAccounts]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
return () => {
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]);
|
||||
|
||||
const handleCustomDerivation = () => {
|
||||
task.current?.stop();
|
||||
if (!isDesktop) {
|
||||
keepAwake(false);
|
||||
disallowScreenshot(false);
|
||||
}
|
||||
|
||||
navigation.navigate('ImportCustomDerivationPath', { importText, password });
|
||||
};
|
||||
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { RouteProp, useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { BackHandler, I18nManager, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import Button from '../../components/Button';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import loc from '../../loc';
|
||||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
|
||||
import SeedWords from '../../components/SeedWords';
|
||||
import { disableScreenProtect, enableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'PleaseBackup'>;
|
||||
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'PleaseBackup'>;
|
||||
|
@ -34,21 +33,27 @@ const PleaseBackup: React.FC = () => {
|
|||
});
|
||||
|
||||
const handleBackButton = useCallback(() => {
|
||||
// @ts-ignore: Ignore
|
||||
navigation.getParent()?.goBack();
|
||||
return true;
|
||||
}, [navigation]);
|
||||
|
||||
useEffect(() => {
|
||||
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
return () => {
|
||||
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (isPrivacyBlurEnabled) enableScreenProtect();
|
||||
return () => {
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]),
|
||||
);
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
style={styles.root}
|
||||
|
|
|
@ -41,7 +41,7 @@ import { useTheme } from '../../components/themes';
|
|||
import prompt from '../../helpers/prompt';
|
||||
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
import loc from '../../loc';
|
||||
import ActionSheet from '../ActionSheet';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
|
@ -191,7 +191,7 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
|||
// useFocusEffect is called on willAppear (example: when camera dismisses). we want to avoid this.
|
||||
if (hasLoaded.current) return;
|
||||
setIsLoading(true);
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (isPrivacyBlurEnabled) enableScreenProtect();
|
||||
|
||||
const task = InteractionManager.runAfterInteractions(async () => {
|
||||
if (!w.current) {
|
||||
|
@ -207,7 +207,7 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
|||
setIsLoading(false);
|
||||
});
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
disableScreenProtect();
|
||||
task.cancel();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import React, { useCallback, useEffect, useLayoutEffect, useRef, useReducer, useMemo } from 'react';
|
||||
import { useFocusEffect, useRoute, RouteProp } from '@react-navigation/native';
|
||||
import { useRoute, RouteProp, useFocusEffect } from '@react-navigation/native';
|
||||
import { ActivityIndicator, FlatList, StyleSheet, View, Platform, UIManager } from 'react-native';
|
||||
import { WatchOnlyWallet } from '../../class';
|
||||
import { AddressItem } from '../../components/addresses/AddressItem';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
|
||||
|
@ -12,7 +11,8 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
|||
import SegmentedControl from '../../components/SegmentControl';
|
||||
import loc from '../../loc';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { disableScreenProtect, enableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
export const TABS = {
|
||||
EXTERNAL: 'receive',
|
||||
|
@ -131,6 +131,7 @@ const WalletAddresses: React.FC = () => {
|
|||
const allowSignVerifyMessage = (wallet && 'allowSignVerifyMessage' in wallet && wallet.allowSignVerifyMessage()) ?? false;
|
||||
|
||||
const { colors } = useTheme();
|
||||
const { isPrivacyBlurEnabled } = useSettings();
|
||||
const { setOptions } = useExtendedNavigation<NavigationProps>();
|
||||
|
||||
const stylesHook = StyleSheet.create({
|
||||
|
@ -139,6 +140,15 @@ const WalletAddresses: React.FC = () => {
|
|||
},
|
||||
});
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (isPrivacyBlurEnabled) enableScreenProtect();
|
||||
return () => {
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]),
|
||||
);
|
||||
|
||||
const getAddresses = useMemo(() => {
|
||||
if (!walletInstance) return [];
|
||||
const newAddresses: Address[] = [];
|
||||
|
@ -177,15 +187,6 @@ const WalletAddresses: React.FC = () => {
|
|||
});
|
||||
}, [setOptions]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!isDesktop) disallowScreenshot(true);
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
};
|
||||
}, []),
|
||||
);
|
||||
|
||||
const data =
|
||||
search.length > 0 ? filteredAddresses.filter(item => item.address.toLowerCase().includes(search.toLowerCase())) : filteredAddresses;
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { RouteProp, useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
|
||||
import { Icon } from '@rneui/themed';
|
||||
import { ActivityIndicator, InteractionManager, LayoutChangeEvent, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
|
||||
import { LayoutChangeEvent, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
import { validateMnemonic } from '../../blue_modules/bip39';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { BlueText } from '../../BlueComponents';
|
||||
|
@ -15,7 +14,6 @@ import SeedWords from '../../components/SeedWords';
|
|||
import { useTheme } from '../../components/themes';
|
||||
import { HandOffActivityType } from '../../components/types';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import useAppState from '../../hooks/useAppState';
|
||||
import loc from '../../loc';
|
||||
|
@ -57,9 +55,8 @@ const DoNotDisclose: React.FC = () => {
|
|||
};
|
||||
|
||||
const WalletExport: React.FC = () => {
|
||||
const { wallets, saveToDisk } = useStorage();
|
||||
const { wallets } = useStorage();
|
||||
const { walletID } = useRoute<RouteProps>().params;
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const navigation = useNavigation();
|
||||
const { isPrivacyBlurEnabled } = useSettings();
|
||||
const { colors } = useTheme();
|
||||
|
@ -85,28 +82,20 @@ const WalletExport: React.FC = () => {
|
|||
}, [wallet]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && previousAppState === 'active' && currentAppState !== 'active') {
|
||||
if (previousAppState === 'active' && currentAppState !== 'active') {
|
||||
const timer = setTimeout(() => navigation.goBack(), 500);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [currentAppState, previousAppState, navigation, isLoading]);
|
||||
}, [currentAppState, previousAppState, navigation]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
const task = InteractionManager.runAfterInteractions(async () => {
|
||||
if (!wallet.getUserHasSavedExport()) {
|
||||
wallet.setUserHasSavedExport(true);
|
||||
saveToDisk();
|
||||
}
|
||||
setIsLoading(false);
|
||||
});
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
task.cancel();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled, wallet, saveToDisk]),
|
||||
);
|
||||
useEffect(() => {
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
return () => {
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]);
|
||||
|
||||
const onLayout = useCallback((e: LayoutChangeEvent) => {
|
||||
const { height, width } = e.nativeEvent.layout;
|
||||
|
@ -128,22 +117,13 @@ const WalletExport: React.FC = () => {
|
|||
contentContainerStyle={styles.scrollViewContent}
|
||||
onLayout={onLayout}
|
||||
testID="WalletExportScroll"
|
||||
centerContent={isLoading}
|
||||
>
|
||||
{children}
|
||||
</ScrollView>
|
||||
),
|
||||
[isLoading, onLayout, stylesHook.root],
|
||||
[onLayout, stylesHook.root],
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<Scroll>
|
||||
<ActivityIndicator />
|
||||
</Scroll>
|
||||
);
|
||||
}
|
||||
|
||||
// for SLIP39
|
||||
if (secrets.length !== 1) {
|
||||
return (
|
||||
|
@ -177,7 +157,6 @@ const WalletExport: React.FC = () => {
|
|||
contentContainerStyle={styles.scrollViewContent}
|
||||
onLayout={onLayout}
|
||||
testID="WalletExportScroll"
|
||||
centerContent={isLoading}
|
||||
>
|
||||
{wallet.type !== WatchOnlyWallet.type && <DoNotDisclose />}
|
||||
|
||||
|
|
|
@ -290,10 +290,10 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
|||
|
||||
const renderItem = useCallback(
|
||||
// eslint-disable-next-line react/no-unused-prop-types
|
||||
({ item }: { item: Transaction }) => {
|
||||
return <TransactionListItem item={item} itemPriceUnit={wallet?.preferredBalanceUnit} walletID={walletID} />;
|
||||
},
|
||||
[wallet, walletID],
|
||||
({ item }: { item: Transaction }) => (
|
||||
<TransactionListItem key={item.hash} item={item} itemPriceUnit={wallet?.preferredBalanceUnit} walletID={walletID} />
|
||||
),
|
||||
[wallet?.preferredBalanceUnit, walletID],
|
||||
);
|
||||
|
||||
const choosePhoto = () => {
|
||||
|
@ -310,7 +310,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
|||
});
|
||||
};
|
||||
|
||||
const _keyExtractor = (_item: any, index: number) => index.toString();
|
||||
const _keyExtractor = useCallback((_item: any, index: number) => index.toString(), []);
|
||||
|
||||
const pasteFromClipboard = async () => {
|
||||
onBarCodeRead({ data: await getClipboardContent() });
|
||||
|
@ -391,6 +391,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
|||
});
|
||||
return () => {
|
||||
task.cancel();
|
||||
console.debug('Next screen is focused, clearing reloadTransactionsMenuActionFunction');
|
||||
setReloadTransactionsMenuActionFunction(() => {});
|
||||
};
|
||||
}, [setReloadTransactionsMenuActionFunction, refreshTransactions]),
|
||||
|
@ -519,7 +520,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
|||
|
||||
<FlatList<Transaction>
|
||||
getItemLayout={getItemLayout}
|
||||
updateCellsBatchingPeriod={30}
|
||||
updateCellsBatchingPeriod={50}
|
||||
onEndReachedThreshold={0.3}
|
||||
onEndReached={loadMoreTransactions}
|
||||
ListFooterComponent={renderListFooterComponent}
|
||||
|
@ -531,7 +532,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
|||
removeClippedSubviews
|
||||
contentContainerStyle={{ backgroundColor: colors.background }}
|
||||
contentInset={{ top: 0, left: 0, bottom: 90, right: 0 }}
|
||||
maxToRenderPerBatch={15}
|
||||
maxToRenderPerBatch={10}
|
||||
onScroll={handleScroll}
|
||||
scrollEventThrottle={16}
|
||||
stickyHeaderHiddenOnScroll
|
||||
|
@ -549,6 +550,10 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
|
|||
<RefreshControl refreshing={isLoading} onRefresh={() => refreshTransactions(true)} tintColor={colors.msSuccessCheck} />
|
||||
) : undefined
|
||||
}
|
||||
windowSize={15}
|
||||
maintainVisibleContentPosition={{
|
||||
minIndexForVisible: 0,
|
||||
}}
|
||||
/>
|
||||
<FContainer ref={walletActionButtonsRef}>
|
||||
{wallet?.allowReceive() && (
|
||||
|
|
|
@ -260,7 +260,7 @@ const WalletsList: React.FC = () => {
|
|||
const renderTransactionListsRow = useCallback(
|
||||
(item: ExtendedTransaction) => (
|
||||
<View style={styles.transaction}>
|
||||
<TransactionListItem item={item} itemPriceUnit={item.walletPreferredBalanceUnit} walletID={item.walletID} />
|
||||
<TransactionListItem key={item.hash} item={item} itemPriceUnit={item.walletPreferredBalanceUnit} walletID={item.walletID} />
|
||||
</View>
|
||||
),
|
||||
[],
|
||||
|
@ -358,9 +358,9 @@ const WalletsList: React.FC = () => {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [scanImage, wallets.length]);
|
||||
|
||||
const sectionListKeyExtractor = (item: any, index: any) => {
|
||||
const sectionListKeyExtractor = useCallback((item: any, index: any) => {
|
||||
return `${item}${index}}`;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onScanButtonPressed = useCallback(() => {
|
||||
navigation.navigate('ScanQRCode', {
|
||||
|
@ -421,6 +421,15 @@ const WalletsList: React.FC = () => {
|
|||
{ key: WalletsListSections.TRANSACTIONS, data: dataSource },
|
||||
];
|
||||
|
||||
const getItemLayout = useCallback(
|
||||
(data: any, index: number) => ({
|
||||
length: 80, // Approximate height of each item
|
||||
offset: 80 * index,
|
||||
index,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.root}>
|
||||
<View style={[styles.walletsListWrapper, stylesHook.walletsListWrapper]}>
|
||||
|
@ -439,6 +448,7 @@ const WalletsList: React.FC = () => {
|
|||
windowSize={21}
|
||||
maxToRenderPerBatch={10}
|
||||
updateCellsBatchingPeriod={50}
|
||||
getItemLayout={getItemLayout}
|
||||
/>
|
||||
{renderScanButton()}
|
||||
</View>
|
||||
|
|
|
@ -26,14 +26,12 @@ import QRCodeComponent from '../../components/QRCodeComponent';
|
|||
import { useTheme } from '../../components/themes';
|
||||
import confirm from '../../helpers/confirm';
|
||||
import prompt from '../../helpers/prompt';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import loc from '../../loc';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import ToolTipMenu from '../../components/TooltipMenu';
|
||||
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { useKeyboard } from '../../hooks/useKeyboard';
|
||||
import {
|
||||
DoneAndDismissKeyboardInputAccessory,
|
||||
|
@ -45,6 +43,7 @@ import MultipleStepsListItem, {
|
|||
MultipleStepsListItemDashType,
|
||||
} from '../../components/MultipleStepsListItem';
|
||||
import { AddressInputScanButton } from '../../components/AddressInputScanButton';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
const staticCache = {};
|
||||
|
||||
|
@ -72,9 +71,11 @@ const WalletsAddMultisigStep2 = () => {
|
|||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
disableScreenProtect();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled]),
|
||||
);
|
||||
|
|
|
@ -7,11 +7,10 @@ import CopyTextToClipboard from '../../components/CopyTextToClipboard';
|
|||
import QRCodeComponent from '../../components/QRCodeComponent';
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import loc from '../../loc';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
|
||||
const PleaseBackupLNDHub = () => {
|
||||
const { wallets } = useStorage();
|
||||
|
@ -44,10 +43,12 @@ const PleaseBackupLNDHub = () => {
|
|||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (isPrivacyBlurEnabled) {
|
||||
enableScreenProtect();
|
||||
}
|
||||
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
disableScreenProtect();
|
||||
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
|
||||
};
|
||||
}, [handleBackButton, isPrivacyBlurEnabled]);
|
||||
|
|
|
@ -8,13 +8,12 @@ import CopyTextToClipboard from '../../components/CopyTextToClipboard';
|
|||
import HandOffComponent from '../../components/HandOffComponent';
|
||||
import QRCodeComponent from '../../components/QRCodeComponent';
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
|
||||
import loc from '../../loc';
|
||||
import { styles, useDynamicStyles } from './xpub.styles';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import { HandOffActivityType } from '../../components/types';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
|
||||
type WalletXpubRouteProp = RouteProp<{ params: { walletID: string; xpub: string } }, 'params'>;
|
||||
export type RootStackParamList = {
|
||||
|
@ -39,7 +38,7 @@ const WalletXpub: React.FC = () => {
|
|||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||
if (isPrivacyBlurEnabled) enableScreenProtect();
|
||||
// Skip execution if walletID hasn't changed
|
||||
if (lastWalletIdRef.current === walletID) {
|
||||
return;
|
||||
|
@ -58,7 +57,7 @@ const WalletXpub: React.FC = () => {
|
|||
});
|
||||
lastWalletIdRef.current = walletID;
|
||||
return () => {
|
||||
if (!isDesktop) disallowScreenshot(false);
|
||||
disableScreenProtect();
|
||||
task.cancel();
|
||||
};
|
||||
}, [isPrivacyBlurEnabled, walletID, wallet, xpub, navigation]),
|
||||
|
|
|
@ -229,10 +229,6 @@ jest.mock('realm', () => {
|
|||
};
|
||||
});
|
||||
|
||||
jest.mock('react-native-ios-context-menu', () => {
|
||||
return {};
|
||||
});
|
||||
|
||||
jest.mock('rn-qr-generator', () => ({
|
||||
detect: jest.fn(uri => {
|
||||
if (uri === 'invalid-image') {
|
||||
|
|
Loading…
Add table
Reference in a new issue