Merge branch 'master' into propsper

This commit is contained in:
Marcos Rodriguez Vélez 2024-03-28 17:48:58 -04:00 committed by GitHub
commit f96067ba66
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 594 additions and 678 deletions

View File

@ -79,7 +79,7 @@ jobs:
- name: Setup Provisioning Profiles
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
ITC_TEAM_NAME: ${{ secrets.ITC_TEAM_NAME }}

View File

@ -1,14 +1,17 @@
name: Build Release Pull Request (iOS)
name: Build Release and Upload to TestFlight (iOS)
on:
push:
branches:
- master
pull_request:
types: [opened, reopened, synchronize, labeled, unlabeled]
types: [opened, reopened, synchronize, labeled]
branches:
- master
workflow_dispatch:
jobs:
build:
if: contains(github.event.pull_request.labels.*.name, 'testflight')
runs-on: macos-14
timeout-minutes: 180
outputs:
@ -22,171 +25,150 @@ jobs:
uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetches all history
- name: Specify node version
uses: actions/setup-node@v2-beta
with:
node-version: 18
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 15.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install dependencies with Bundler
run: bundle install
- name: Install Fastlane 2.217.0
run: gem install fastlane -v 2.217.0
- name: Install CocoaPods
run: sudo gem install cocoapods
- name: Install Fastlane
run: gem install fastlane -v 2.217.0 # If a specific version is needed for PR or not specified, keep only one version
- name: Clear Derived Data
run: bundle exec fastlane ios clear_derived_data_lane
working-directory: ./ios
- name: Install node_modules
run: npm install
- name: Install CocoaPods Dependencies
run: |
sudo gem install cocoapods # Ensure CocoaPods is installed
bundle exec pod install
working-directory: ./ios
- name: Cache CocoaPods Pods
uses: actions/cache@v2
with:
path: ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
- name: Display release-notes.txt
run: cat release-notes.txt
- name: Get Latest Commit Message
id: get_latest_commit_message
run: |
LATEST_COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
echo "LATEST_COMMIT_MESSAGE=${LATEST_COMMIT_MESSAGE}" >> $GITHUB_ENV
echo "::set-output name=commit_message::$LATEST_COMMIT_MESSAGE"
- name: Set up Git Authentication
env:
ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
run: |
git config --global credential.helper 'cache --timeout=3600'
git config --global http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n x-access-token:${ACCESS_TOKEN} | base64)"
- name: Create Temporary Keychain
run: bundle exec fastlane ios create_temp_keychain
working-directory: ./ios
env:
env:
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
- name: Setup Provisioning Profiles
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
ITC_TEAM_NAME: ${{ secrets.ITC_TEAM_NAME }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: bundle exec fastlane ios setup_provisioning_profiles
working-directory: ./ios
- name: Generate Build Number based on timestamp
id: generate_build_number
run: |
NEW_BUILD_NUMBER=$(date +%s)
echo "NEW_BUILD_NUMBER=$NEW_BUILD_NUMBER" >> $GITHUB_ENV
echo "::set-output name=build_number::$NEW_BUILD_NUMBER"
- name: Set Build Number
run: bundle exec fastlane ios increment_build_number_lane
working-directory: ./ios
- name: Determine Marketing Version
id: determine_marketing_version
run: |
MARKETING_VERSION=$(grep MARKETING_VERSION ios/BlueWallet.xcodeproj/project.pbxproj | awk -F '= ' '{print $2}' | tr -d ' ;' | head -1)
echo "PROJECT_VERSION=$MARKETING_VERSION" >> $GITHUB_ENV
echo "::set-output name=project_version::$MARKETING_VERSION"
- name: Expected IPA file name
run: |
echo "IPA file name: BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa"
- name: Install CocoaPods Dependencies
run: bundle exec fastlane ios install_pods
working-directory: ./ios
- name: Build App
run: bundle exec fastlane ios build_app_lane
working-directory: ./ios
- name: Upload IPA as Artifact
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
testflight-upload:
if: contains(github.event.pull_request.labels.*.name, 'testflight')
needs: build
runs-on: macos-14
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
NEW_BUILD_NUMBER: ${{ needs.build.outputs.new_build_number }}
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
steps:
- name: Checkout project
uses: actions/checkout@v3
- name: Cache Ruby Gems
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install dependencies with Bundler
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- 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
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
- name: Upload to TestFlight
env:
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/ios/appstore_api_key.p8
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
ITC_TEAM_NAME: ${{ secrets.ITC_TEAM_NAME }}
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 }}
run: bundle exec fastlane ios upload_to_testflight_lane
working-directory: ./ios
- name: Post PR Comment
uses: actions/github-script@v6
if: success() # Ensures the message is only posted if previous steps succeed
env:
BUILD_NUMBER: ${{ needs.build.outputs.new_build_number }}
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 prNumber = context.payload.pull_request.number;
const repo = context.repo;
github.rest.issues.createComment({
...repo,
issue_number: prNumber,
body: message,
});
needs: build
runs-on: macos-14
if: github.event_name == 'push' || contains(github.event.pull_request.labels.*.name, 'testflight')
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
NEW_BUILD_NUMBER: ${{ needs.build.outputs.new_build_number }}
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
steps:
- name: Checkout project
uses: actions/checkout@v3
- name: Cache Ruby Gems
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install dependencies with Bundler
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- 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
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
- name: Upload to TestFlight
env:
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/ios/appstore_api_key.p8
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
GIT_ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
ITC_TEAM_NAME: ${{ secrets.ITC_TEAM_NAME }}
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 }}
run: bundle exec fastlane ios upload_to_testflight_lane
working-directory: ./ios
- 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 }}
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 prNumber = context.payload.pull_request.number;
const repo = context.repo;
github.rest.issues.createComment({
...repo,
issue_number: prNumber,
body: message,
});

View File

@ -1,180 +0,0 @@
name: Build Release and Upload to TestFlight (iOS)
on:
push:
branches:
- master
jobs:
build:
runs-on: macos-14
timeout-minutes: 180
outputs:
new_build_number: ${{ steps.generate_build_number.outputs.build_number }}
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
steps:
- name: Checkout project
uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetches all history
- name: Specify node version
uses: actions/setup-node@v2-beta
with:
node-version: 18
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 15.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Install dependencies with Bundler
run: bundle install
- name: Install Fastlane
run: gem install fastlane
- name: Clear Derived Data
run: bundle exec fastlane ios clear_derived_data_lane
working-directory: ./ios
- name: Install node_modules
run: npm install
- name: Install CocoaPods Dependencies
run: bundle exec pod install
working-directory: ./ios
- name: Cache CocoaPods Pods
uses: actions/cache@v2
with:
path: ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
- name: Display release-notes.txt
run: cat release-notes.txt
- name: Get Latest Commit Message
id: get_latest_commit_message
run: |
LATEST_COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
echo "LATEST_COMMIT_MESSAGE=${LATEST_COMMIT_MESSAGE}" >> $GITHUB_ENV
echo "::set-output name=commit_message::$LATEST_COMMIT_MESSAGE"
- name: Set up Git Authentication
env:
ACCESS_TOKEN: ${{ secrets.GIT_ACCESS_TOKEN }}
run: |
git config --global credential.helper 'cache --timeout=3600'
git config --global http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n x-access-token:${ACCESS_TOKEN} | base64)"
- name: Create Temporary Keychain
run: bundle exec fastlane ios create_temp_keychain
working-directory: ./ios
env:
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
- name: Setup Provisioning Profiles
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
ITC_TEAM_NAME: ${{ secrets.ITC_TEAM_NAME }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: bundle exec fastlane ios setup_provisioning_profiles
working-directory: ./ios
- name: Generate Build Number based on timestamp
id: generate_build_number
run: |
NEW_BUILD_NUMBER=$(date +%s)
echo "NEW_BUILD_NUMBER=$NEW_BUILD_NUMBER" >> $GITHUB_ENV
echo "::set-output name=build_number::$NEW_BUILD_NUMBER"
- name: Set Build Number
run: bundle exec fastlane ios increment_build_number_lane
working-directory: ./ios
- name: Determine Marketing Version
id: determine_marketing_version
run: |
MARKETING_VERSION=$(grep MARKETING_VERSION ios/BlueWallet.xcodeproj/project.pbxproj | awk -F '= ' '{print $2}' | tr -d ' ;' | head -1)
echo "PROJECT_VERSION=$MARKETING_VERSION" >> $GITHUB_ENV
echo "::set-output name=project_version::$MARKETING_VERSION"
- name: Expected IPA file name
run: |
echo "IPA file name: BlueWallet.${{env.PROJECT_VERSION}}(${{env.NEW_BUILD_NUMBER}}).ipa"
- name: Build App
run: bundle exec fastlane ios build_app_lane
working-directory: ./ios
- name: Upload IPA as Artifact
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
testflight-upload:
needs: build
runs-on: macos-14
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
NEW_BUILD_NUMBER: ${{ needs.build.outputs.new_build_number }}
PROJECT_VERSION: ${{ needs.build.outputs.project_version }}
LATEST_COMMIT_MESSAGE: ${{ needs.build.outputs.latest_commit_message }}
steps:
- name: Checkout project
uses: actions/checkout@v3
- name: Cache CocoaPods Pods
uses: actions/cache@v2
with:
path: ios/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
- name: Cache Ruby Gems
uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
${{ runner.os }}-gems-
- name: Install dependencies with Bundler
run: |
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- 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
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
- name: Upload to TestFlight
env:
APP_STORE_CONNECT_API_KEY_PATH: $(pwd)/ios/appstore_api_key.p8
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.GIT_ACCESS_TOKEN }}
GIT_URL: ${{ secrets.GIT_URL }}
ITC_TEAM_ID: ${{ secrets.ITC_TEAM_ID }}
ITC_TEAM_NAME: ${{ secrets.ITC_TEAM_NAME }}
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 }}
run: bundle exec fastlane ios upload_to_testflight_lane
working-directory: ./ios

59
App.js
View File

@ -33,6 +33,7 @@ import HandoffComponent from './components/handoff';
import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback';
import MenuElements from './components/MenuElements';
import { updateExchangeRate } from './blue_modules/currency';
import { NavigationProvider } from './components/NavigationProvider';
const A = require('./blue_modules/analytics');
const eventEmitter = Platform.OS === 'ios' ? new NativeEventEmitter(NativeModules.EventEmitter) : undefined;
@ -99,28 +100,42 @@ const App = () => {
}
};
useEffect(() => {
if (walletsInitialized) {
addListeners();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletsInitialized]);
const addListeners = () => {
Linking.addEventListener('url', handleOpenURL);
AppState.addEventListener('change', handleAppStateChange);
const urlSubscription = Linking.addEventListener('url', handleOpenURL);
const appStateSubscription = AppState.addEventListener('change', handleAppStateChange);
// Note: `getMostRecentUserActivity` doesn't create a persistent listener, so no need to unsubscribe
EventEmitter?.getMostRecentUserActivity()
.then(onUserActivityOpen)
.catch(() => console.log('No userActivity object sent'));
handleAppStateChange(undefined);
/*
When a notification on iOS is shown while the app is on foreground;
On willPresent on AppDelegate.m
*/
eventEmitter?.addListener('onNotificationReceived', onNotificationReceived);
eventEmitter?.addListener('onUserActivityOpen', onUserActivityOpen);
const notificationSubscription = eventEmitter?.addListener('onNotificationReceived', onNotificationReceived);
const activitySubscription = eventEmitter?.addListener('onUserActivityOpen', onUserActivityOpen);
// Store subscriptions in a ref or state to remove them later
return {
urlSubscription,
appStateSubscription,
notificationSubscription,
activitySubscription,
};
};
useEffect(() => {
if (walletsInitialized) {
const subscriptions = addListeners();
// Cleanup function
return () => {
subscriptions.urlSubscription?.remove();
subscriptions.appStateSubscription?.remove();
subscriptions.notificationSubscription?.remove();
subscriptions.activitySubscription?.remove();
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletsInitialized]); // Re-run when walletsInitialized changes
/**
* Processes push notifications stored in AsyncStorage. Might navigate to some screen.
*
@ -285,14 +300,16 @@ const App = () => {
<SafeAreaProvider>
<View style={styles.root}>
<NavigationContainer ref={navigationRef} theme={colorScheme === 'dark' ? BlueDarkTheme : BlueDefaultTheme}>
<InitRoot />
<Notifications onProcessNotifications={processPushNotifications} />
<MenuElements />
<DeviceQuickActions />
<NavigationProvider>
<InitRoot />
<Notifications onProcessNotifications={processPushNotifications} />
<MenuElements />
<DeviceQuickActions />
<Biometric />
</NavigationProvider>
</NavigationContainer>
</View>
<WatchConnectivity />
<Biometric />
<WidgetCommunication />
</SafeAreaProvider>
);

View File

@ -859,7 +859,11 @@ export class AppStorage {
isDoNotTrackEnabled = async (): Promise<boolean> => {
try {
return !!(await AsyncStorage.getItem(AppStorage.DO_NOT_TRACK));
const doNotTrackValue = !!(await AsyncStorage.getItem(AppStorage.DO_NOT_TRACK));
if (doNotTrackValue) {
await DefaultPreference.set(AppStorage.DO_NOT_TRACK, '1');
AsyncStorage.removeItem(AppStorage.DO_NOT_TRACK);
}
} catch (_) {}
return false;
};

View File

@ -4,8 +4,6 @@ import PropTypes from 'prop-types';
import { Icon, Text, Header } from 'react-native-elements';
import {
ActivityIndicator,
Alert,
Animated,
Dimensions,
Image,
InputAccessoryView,
@ -18,7 +16,6 @@ import {
View,
I18nManager,
ImageBackground,
findNodeHandle,
} from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
import NetworkTransactionFees, { NetworkTransactionFee, NetworkTransactionFeeType } from './models/networkTransactionFees';
@ -27,8 +24,6 @@ import { BlueCurrentTheme, useTheme } from './components/themes';
import PlusIcon from './components/icons/PlusIcon';
import loc, { formatStringAddTwoWhiteSpaces } from './loc';
import SafeArea from './components/SafeArea';
import { isDesktop } from './blue_modules/environment';
import ActionSheet from './screen/ActionSheet';
const { height, width } = Dimensions.get('window');
const aspectRatio = height / width;
@ -196,39 +191,6 @@ export const BlueButtonLink = forwardRef((props, ref) => {
);
});
export const BlueAlertWalletExportReminder = ({ onSuccess = () => {}, onFailure, anchor }) => {
if (isDesktop) {
ActionSheet.showActionSheetWithOptions(
{
title: loc.wallets.details_title, // Changed from loc.send.header to loc.wallets.details_title
message: loc.pleasebackup.ask,
options: [loc.pleasebackup.ask_yes, loc.pleasebackup.ask_no],
anchor: findNodeHandle(anchor), // Kept the same for context
},
buttonIndex => {
switch (buttonIndex) {
case 0:
onSuccess(); // Assuming the first button (yes) triggers onSuccess
break;
case 1:
onFailure(); // Assuming the second button (no) triggers onFailure
break;
}
},
);
} else {
Alert.alert(
loc.wallets.details_title,
loc.pleasebackup.ask,
[
{ text: loc.pleasebackup.ask_yes, onPress: onSuccess, style: 'cancel' },
{ text: loc.pleasebackup.ask_no, onPress: onFailure },
],
{ cancelable: false },
);
}
};
export const BluePrivateBalance = () => {
return (
<View style={{ flexDirection: 'row', alignItems: 'center', marginTop: 13, borderRadius: 9 }}>
@ -241,80 +203,6 @@ export const BluePrivateBalance = () => {
);
};
export const BlueCopyToClipboardButton = ({ stringToCopy, displayText = false }) => {
return (
<TouchableOpacity accessibilityRole="button" onPress={() => Clipboard.setString(stringToCopy)}>
<Text style={{ fontSize: 13, fontWeight: '400', color: '#68bbe1' }}>{displayText || loc.transactions.details_copy}</Text>
</TouchableOpacity>
);
};
export class BlueCopyTextToClipboard extends Component {
static propTypes = {
text: PropTypes.string,
truncated: PropTypes.bool,
};
static defaultProps = {
text: '',
truncated: false,
};
constructor(props) {
super(props);
this.state = { hasTappedText: false, address: props.text };
}
static getDerivedStateFromProps(props, state) {
if (state.hasTappedText) {
return { hasTappedText: state.hasTappedText, address: state.address, truncated: props.truncated };
} else {
return { hasTappedText: state.hasTappedText, address: props.text, truncated: props.truncated };
}
}
copyToClipboard = () => {
this.setState({ hasTappedText: true }, () => {
Clipboard.setString(this.props.text);
this.setState({ address: loc.wallets.xpub_copiedToClipboard }, () => {
setTimeout(() => {
this.setState({ hasTappedText: false, address: this.props.text });
}, 1000);
});
});
};
render() {
return (
<View style={{ justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
<TouchableOpacity
accessibilityRole="button"
onPress={this.copyToClipboard}
disabled={this.state.hasTappedText}
testID="BlueCopyTextToClipboard"
>
<Animated.Text
style={styleCopyTextToClipboard.address}
{...(this.props.truncated ? { numberOfLines: 1, ellipsizeMode: 'middle' } : { numberOfLines: 0 })}
testID="AddressValue"
>
{this.state.address}
</Animated.Text>
</TouchableOpacity>
</View>
);
}
}
const styleCopyTextToClipboard = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
export const BlueCard = props => {
return <View {...props} style={{ padding: 20 }} />;
};

View File

@ -639,7 +639,7 @@ const Navigation = () => {
/>
<RootStack.Screen name="PaymentCodeRoot" component={PaymentCodeStackRoot} options={NavigationDefaultOptions} />
<InitStack.Screen
<RootStack.Screen
name="ReorderWallets"
component={ReorderWalletsStackRoot}
options={{

View File

@ -13,7 +13,6 @@ import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import java.util.List;
import com.bugsnag.android.Bugsnag;
public class MainApplication extends Application implements ReactApplication {
@ -57,7 +56,6 @@ public class MainApplication extends Application implements ReactApplication {
@Override
public void onCreate() {
super.onCreate();
Bugsnag.start(this);
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
sharedI18nUtilInstance.allowRTL(getApplicationContext(), true);
SoLoader.init(this, /* native exopackage */ false);

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { forwardRef } from 'react';
import { TouchableOpacity, View, Text, StyleSheet, StyleProp, ViewStyle } from 'react-native';
import { Icon } from 'react-native-elements';
import { useTheme } from './themes';
@ -19,7 +19,7 @@ interface ButtonProps {
onPress?: () => void;
}
export const Button: React.FC<ButtonProps> = props => {
export const Button = forwardRef<TouchableOpacity, ButtonProps>((props, ref) => {
const { colors } = useTheme();
let backgroundColor = props.backgroundColor ?? colors.mainColor;
@ -42,6 +42,7 @@ export const Button: React.FC<ButtonProps> = props => {
return (
<TouchableOpacity
ref={ref}
testID={props.testID}
style={[buttonStyle, props.style]}
accessibilityRole="button"
@ -54,7 +55,7 @@ export const Button: React.FC<ButtonProps> = props => {
</View>
</TouchableOpacity>
);
};
});
const styles = StyleSheet.create({
button: {

View File

@ -0,0 +1,65 @@
import Clipboard from '@react-native-clipboard/clipboard';
import React, { useState, useEffect, forwardRef } from 'react';
import { View, TouchableOpacity, Animated, StyleSheet } from 'react-native';
import loc from '../loc';
type CopyTextToClipboardProps = {
text: string;
truncated?: boolean;
};
const styleCopyTextToClipboard = StyleSheet.create({
address: {
marginVertical: 32,
fontSize: 15,
color: '#9aa0aa',
textAlign: 'center',
},
});
const CopyTextToClipboard = forwardRef<TouchableOpacity, CopyTextToClipboardProps>(({ text, truncated }, ref) => {
const [hasTappedText, setHasTappedText] = useState(false);
const [address, setAddress] = useState(text);
useEffect(() => {
if (!hasTappedText) {
setAddress(text);
}
}, [text, hasTappedText]);
const copyToClipboard = () => {
setHasTappedText(true);
Clipboard.setString(text);
setAddress(loc.wallets.xpub_copiedToClipboard); // Adjust according to your localization logic
setTimeout(() => {
setHasTappedText(false);
setAddress(text);
}, 1000);
};
return (
<View style={styles.container}>
<TouchableOpacity
ref={ref}
accessibilityRole="button"
onPress={copyToClipboard}
disabled={hasTappedText}
testID="CopyTextToClipboard"
>
<Animated.Text
style={styleCopyTextToClipboard.address}
{...(truncated ? { numberOfLines: 1, ellipsizeMode: 'middle' } : { numberOfLines: 0 })}
testID="AddressValue"
>
{address}
</Animated.Text>
</TouchableOpacity>
</View>
);
});
export default CopyTextToClipboard;
const styles = StyleSheet.create({
container: { justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 },
});

View File

@ -0,0 +1,27 @@
import Clipboard from '@react-native-clipboard/clipboard';
import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
import loc from '../loc';
type CopyToClipboardButtonProps = {
stringToCopy: string;
displayText?: string;
};
export const CopyToClipboardButton: React.FC<CopyToClipboardButtonProps> = ({ stringToCopy, displayText }) => {
const onPress = () => {
Clipboard.setString(stringToCopy);
};
return (
<TouchableOpacity accessibilityRole="button" onPress={onPress}>
<Text style={styles.text}>{displayText && displayText.length > 0 ? displayText : loc.transactions.details_copy}</Text>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
text: { fontSize: 13, fontWeight: '400', color: '#68bbe1' },
});
export default CopyToClipboardButton;

View File

@ -0,0 +1,9 @@
import React, { ReactNode } from 'react';
interface NavigationProviderProps {
children: ReactNode;
}
export const NavigationProvider: React.FC<NavigationProviderProps> = ({ children }) => {
return <>{children}</>;
};

View File

@ -0,0 +1,16 @@
import { Alert } from 'react-native';
import loc from '../loc';
export const presentWalletExportReminder = (): Promise<void> => {
return new Promise<void>((resolve, reject) => {
Alert.alert(
loc.wallets.details_title,
loc.pleasebackup.ask,
[
{ text: loc.pleasebackup.ask_yes, onPress: () => resolve(), style: 'default' },
{ text: loc.pleasebackup.ask_no, onPress: () => reject(new Error('User has denied saving the wallet backup.')), style: 'cancel' },
],
{ cancelable: false },
);
});
};

View File

@ -0,0 +1,94 @@
import { useNavigation, NavigationProp, ParamListBase } from '@react-navigation/native';
import Biometric from '../class/biometrics';
import { navigationRef } from '../NavigationService';
import { BlueStorageContext } from '../blue_modules/storage-context';
import { useContext } from 'react';
import { presentWalletExportReminder } from '../helpers/presentWalletExportReminder';
// List of screens that require biometrics
const requiresBiometrics = ['WalletExportRoot', 'WalletXpubRoot', 'ViewEditMultisigCosignersRoot', 'ExportMultisigCoordinationSetupRoot'];
// List of screens that require wallet export to be saved
const requiresWalletExportIsSaved = ['ReceiveDetailsRoot', 'WalletAddresses'];
export const useExtendedNavigation = (): NavigationProp<ParamListBase> => {
const originalNavigation = useNavigation<NavigationProp<ParamListBase>>();
const { wallets, saveToDisk } = useContext(BlueStorageContext);
const enhancedNavigate: NavigationProp<ParamListBase>['navigate'] = (screenOrOptions: any, params?: any) => {
let screenName: string;
if (typeof screenOrOptions === 'string') {
screenName = screenOrOptions;
} else if (typeof screenOrOptions === 'object' && 'name' in screenOrOptions) {
screenName = screenOrOptions.name;
params = screenOrOptions.params; // Assign params from object if present
} else {
throw new Error('Invalid navigation options');
}
const isRequiresBiometrics = requiresBiometrics.includes(screenName);
const isRequiresWalletExportIsSaved = requiresWalletExportIsSaved.includes(screenName);
const proceedWithNavigation = () => {
console.log('Proceeding with navigation to', screenName);
if (navigationRef.current?.isReady()) {
typeof screenOrOptions === 'string'
? originalNavigation.navigate(screenOrOptions, params)
: originalNavigation.navigate(screenName, params); // Fixed to use screenName and params
}
};
(async () => {
if (isRequiresBiometrics) {
const isBiometricsEnabled = await Biometric.isBiometricUseEnabled();
if (isBiometricsEnabled) {
const isAuthenticated = await Biometric.unlockWithBiometrics();
if (isAuthenticated) {
proceedWithNavigation();
return; // Ensure the function exits if this path is taken
} else {
console.error('Biometric authentication failed');
// Decide if navigation should proceed or not after failed authentication
}
}
}
if (isRequiresWalletExportIsSaved) {
console.log('Checking if wallet export is saved');
let walletID: string | undefined;
if (params && params.walletID) {
walletID = params.walletID;
} else if (params && params.params && params.params.walletID) {
walletID = params.params.walletID;
}
if (!walletID) {
proceedWithNavigation();
return;
}
const wallet = wallets.find(w => w.getID() === walletID);
if (wallet && !wallet.getUserHasSavedExport()) {
try {
await presentWalletExportReminder();
wallet.setUserHasSavedExport(true);
await saveToDisk(); // Assuming saveToDisk() returns a Promise.
proceedWithNavigation();
} catch {
originalNavigation.navigate('WalletExportRoot', {
screen: 'WalletExport',
params: { walletID },
});
}
return; // Prevent proceeding with the original navigation if the reminder is shown
}
}
proceedWithNavigation();
})();
};
return {
...originalNavigation,
navigate: enhancedNavigate,
};
};

View File

@ -2498,7 +2498,7 @@
repositoryURL = "https://github.com/bugsnag/bugsnag-cocoa";
requirement = {
kind = exactVersion;
version = 6.28.0;
version = 6.28.1;
};
};
/* End XCRemoteSwiftPackageReference section */

View File

@ -1,5 +1,15 @@
{
"originHash" : "89509f555bc90a15b96ca0a326a69850770bdaac04a46f9cf482d81533702e3c",
"pins" : [
{
"identity" : "bugsnag-cocoa",
"kind" : "remoteSourceControl",
"location" : "https://github.com/bugsnag/bugsnag-cocoa",
"state" : {
"revision" : "49f60b8dc2e94e7ede1114e2c39ba6ac0b576f42",
"version" : "6.28.1"
}
},
{
"identity" : "efqrcode",
"kind" : "remoteSourceControl",

View File

@ -1,4 +1,3 @@
#import <Bugsnag/Bugsnag.h>
#import "AppDelegate.h"
#import <React/RCTLinkingManager.h>
#import <React/RCTBundleURLProvider.h>
@ -9,6 +8,7 @@
#import <RNCPushNotificationIOS.h>
#import "EventEmitter.h"
#import <React/RCTRootView.h>
#import <Bugsnag/Bugsnag.h>
@interface AppDelegate() <UNUserNotificationCenterDelegate>
@ -21,7 +21,10 @@
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Set the appType based on the current platform
NSUserDefaults *group = [[NSUserDefaults alloc] initWithSuiteName:@"group.io.bluewallet.bluewallet"];
NSString *isDoNotTrackEnabled = [group stringForKey:@"donottrack"];
if (![isDoNotTrackEnabled isEqualToString:@"1"]) {
// Set the appType based on the current platform
#if TARGET_OS_MACCATALYST
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
config.appType = @"macOS";
@ -30,6 +33,8 @@
#else
[Bugsnag start];
#endif
}
[self copyDeviceUID];

View File

@ -1,92 +1,134 @@
{
"images" : [
{
"size" : "24x24",
"idiom" : "watch",
"filename" : "Icon-48.png",
"scale" : "2x",
"idiom" : "watch",
"role" : "notificationCenter",
"scale" : "2x",
"size" : "24x24",
"subtype" : "38mm"
},
{
"size" : "27.5x27.5",
"idiom" : "watch",
"filename" : "Icon-55.png",
"scale" : "2x",
"idiom" : "watch",
"role" : "notificationCenter",
"scale" : "2x",
"size" : "27.5x27.5",
"subtype" : "42mm"
},
{
"size" : "29x29",
"idiom" : "watch",
"filename" : "58.png",
"role" : "companionSettings",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "watch",
"filename" : "87.png",
"role" : "companionSettings",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "watch",
"filename" : "watch.png",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "87.png",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "watch",
"role" : "notificationCenter",
"scale" : "2x",
"size" : "33x33",
"subtype" : "45mm"
},
{
"filename" : "watch.png",
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "40x40",
"subtype" : "38mm"
},
{
"size" : "44x44",
"idiom" : "watch",
"filename" : "Icon-88.png",
"scale" : "2x",
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "44x44",
"subtype" : "40mm"
},
{
"size" : "50x50",
"idiom" : "watch",
"filename" : "Icon-173.png",
"scale" : "2x",
"role" : "appLauncher",
"scale" : "2x",
"size" : "46x46",
"subtype" : "41mm"
},
{
"filename" : "Icon-173.png",
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "50x50",
"subtype" : "44mm"
},
{
"size" : "86x86",
"idiom" : "watch",
"filename" : "Icon-172.png",
"role" : "appLauncher",
"scale" : "2x",
"size" : "51x51",
"subtype" : "45mm"
},
{
"idiom" : "watch",
"role" : "appLauncher",
"scale" : "2x",
"size" : "54x54",
"subtype" : "49mm"
},
{
"filename" : "Icon-172.png",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "86x86",
"subtype" : "38mm"
},
{
"size" : "98x98",
"idiom" : "watch",
"filename" : "Icon-196.png",
"scale" : "2x",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "98x98",
"subtype" : "42mm"
},
{
"size" : "108x108",
"idiom" : "watch",
"filename" : "group-copy-2@3x.png",
"scale" : "2x",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "108x108",
"subtype" : "44mm"
},
{
"size" : "1024x1024",
"idiom" : "watch-marketing",
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "117x117",
"subtype" : "45mm"
},
{
"idiom" : "watch",
"role" : "quickLook",
"scale" : "2x",
"size" : "129x129",
"subtype" : "49mm"
},
{
"filename" : "1024.png",
"scale" : "1x"
"idiom" : "watch-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

View File

@ -494,7 +494,7 @@ PODS:
- React-Core
- RNLocalize (3.0.6):
- React-Core
- RNPermissions (4.1.4):
- RNPermissions (4.1.5):
- React-Core
- RNPrivacySnapshot (1.0.0):
- React
@ -508,10 +508,10 @@ PODS:
- RCT-Folly (= 2021.07.22.00)
- React-Core
- ReactCommon/turbomodule/core
- RNScreens (3.29.0):
- RNScreens (3.30.1):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- RNShare (10.0.2):
- RNShare (10.1.0):
- React-Core
- RNSVG (13.14.0):
- React-Core
@ -854,14 +854,14 @@ SPEC CHECKSUMS:
RNHandoff: d3b0754cca3a6bcd9b25f544f733f7f033ccf5fa
RNKeychain: bfe3d12bf4620fe488771c414530bf16e88f3678
RNLocalize: 4222a3756cdbe2dc9a5bdf445765a4d2572107cb
RNPermissions: 31223c0cf32b7623e6ec4cd13a7e4552fd43c71c
RNPermissions: 9fa74223844f437bc309e112994859dc47194829
RNPrivacySnapshot: 71919dde3c6a29dd332115409c2aec564afee8f4
RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93
RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a
RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9
RNReanimated: fc36806836aca984b797f01432abe31689663421
RNScreens: 8ba3eeb8f5cb9f13662df564e785d64ef7214bf2
RNShare: 859ff710211285676b0bcedd156c12437ea1d564
RNScreens: e5ee7223f7c8fa261f0c4594a0541c56ea99bbfc
RNShare: b674d9f1cb0dc11116983bebd8712908a226a3ee
RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396
RNVectorIcons: 2b974a961e7ad079fafdd8af68b12210d5b4b28e
RNWatch: fd30ca40a5b5ef58dcbc195638e68219bc455236

View File

@ -4,13 +4,13 @@ echo "===== Installling CocoaPods ====="
export HOMEBREW_NO_INSTALL_CLEANUP=TRUE
brew install cocoapods
echo "===== Installing Node.js ====="
brew install node@21
brew install node@18
echo "===== Installing yarn (Xcode Cloud doenst like NPM ) ====="
brew install yarn
# Install dependencies
echo "===== Running yarn install ====="
yarn install
npm install -y
echo "===== Running pod install ====="
cd ios
pod install

View File

@ -66,7 +66,7 @@ platform :ios do
platform = options[:platform] || "ios" # Default to iOS if not specified
target_to_app_identifier.each do |target, app_identifier|
match(
git_basic_authorization: ENV["MATCH_GIT_BASIC_AUTHORIZATION"],
git_basic_authorization: ENV["GIT_ACCESS_TOKEN"],
git_url: ENV["GIT_URL"],
type: "appstore",
platform: platform,

View File

@ -402,7 +402,7 @@
"details_delete": "Delete",
"details_delete_wallet": "Delete Wallet",
"details_derivation_path": "derivation path",
"details_display": "Display in Wallets List",
"details_display": "Display in Home Screen",
"details_export_backup": "Export/Backup",
"details_export_history": "Export History to CSV",
"details_master_fingerprint": "Master Fingerprint",

View File

@ -2,7 +2,7 @@
"USD": {
"endPointKey": "USD",
"locale": "en-US",
"source": "Bitstamp",
"source": "CoinGecko",
"symbol": "$"
},
"AED": {
@ -92,13 +92,13 @@
"EUR": {
"endPointKey": "EUR",
"locale": "en-IE",
"source": "Bitstamp",
"source": "CoinGecko",
"symbol": "€"
},
"GBP": {
"endPointKey": "GBP",
"locale": "en-GB",
"source": "Bitstamp",
"source": "CoinGecko",
"symbol": "£"
},
"HRK": {

42
package-lock.json generated
View File

@ -80,7 +80,7 @@
"react-native-modal": "13.0.1",
"react-native-obscure": "https://github.com/BlueWallet/react-native-obscure.git#f4b83b4a261e39b1f5ed4a45ac5bcabc8a59eadb",
"react-native-passcode-auth": "https://github.com/BlueWallet/react-native-passcode-auth#a2ff977ba92b36f8d0a5567f59c05cc608e8bd12",
"react-native-permissions": "4.1.4",
"react-native-permissions": "4.1.5",
"react-native-privacy-snapshot": "https://github.com/BlueWallet/react-native-privacy-snapshot#529e4627d93f67752a27e82a040ff7b64dca0783",
"react-native-prompt-android": "https://github.com/BlueWallet/react-native-prompt-android#ed168d66fed556bc2ed07cf498770f058b78a376",
"react-native-push-notification": "8.1.1",
@ -90,9 +90,9 @@
"react-native-rate": "1.2.12",
"react-native-reanimated": "3.8.1",
"react-native-safe-area-context": "4.9.0",
"react-native-screens": "3.29.0",
"react-native-screens": "3.30.1",
"react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48",
"react-native-share": "10.0.2",
"react-native-share": "10.1.0",
"react-native-svg": "13.14.0",
"react-native-tcp-socket": "6.0.6",
"react-native-vector-icons": "10.0.3",
@ -19542,9 +19542,9 @@
"license": "ISC"
},
"node_modules/react-native-permissions": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-4.1.4.tgz",
"integrity": "sha512-el6u90VZNFDEtmHpSheirwRhGvs6M5rSZcoqIqB128IPO00f2c1q+PP4kEaM1u19Q0ldQ+R+S7C/l8Zrduy6JQ==",
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-4.1.5.tgz",
"integrity": "sha512-r6VMRacASmtRHS+GZ+5HQCp9p9kiE+UU9magHOZCXZLTJitdTuVHWZRrb4v4oqZGU+zAp3mZhTQftuMMv+WLUg==",
"peerDependencies": {
"react": ">=18.1.0",
"react-native": ">=0.70.0",
@ -19671,9 +19671,9 @@
}
},
"node_modules/react-native-screens": {
"version": "3.29.0",
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.29.0.tgz",
"integrity": "sha512-yB1GoAMamFAcYf4ku94uBPn0/ani9QG7NdI98beJ5cet2YFESYYzuEIuU+kt+CNRcO8qqKeugxlfgAa3HyTqlg==",
"version": "3.30.1",
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.30.1.tgz",
"integrity": "sha512-/muEvjocCtFb+j5J3YmLvB25+f4rIU8hnnxgGTkXcAf2omPBY8uhPjJaaFUlvj64VEoEzJcRpugbXWsjfPPIFg==",
"dependencies": {
"react-freeze": "^1.0.0",
"warn-once": "^0.1.0"
@ -19689,9 +19689,9 @@
"license": "ISC"
},
"node_modules/react-native-share": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-10.0.2.tgz",
"integrity": "sha512-EZs4MtsyauAI1zP8xXT1hIFB/pXOZJNDCKcgCpEfTZFXgCUzz8MDVbI1ocP2hA59XHRSkqAQdbJ0BFTpjxOBlg==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-10.1.0.tgz",
"integrity": "sha512-fKKvwaZe5s3HW0tcRKyR5AWvAfXvkk0FgTw1nYWYjI4gNqntXbMjRqWZed8Hmd1MvIJS17K/ELPges0tsxbp3g==",
"engines": {
"node": ">=16"
}
@ -37159,9 +37159,9 @@
"from": "react-native-passcode-auth@https://github.com/BlueWallet/react-native-passcode-auth#a2ff977ba92b36f8d0a5567f59c05cc608e8bd12"
},
"react-native-permissions": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-4.1.4.tgz",
"integrity": "sha512-el6u90VZNFDEtmHpSheirwRhGvs6M5rSZcoqIqB128IPO00f2c1q+PP4kEaM1u19Q0ldQ+R+S7C/l8Zrduy6JQ=="
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-4.1.5.tgz",
"integrity": "sha512-r6VMRacASmtRHS+GZ+5HQCp9p9kiE+UU9magHOZCXZLTJitdTuVHWZRrb4v4oqZGU+zAp3mZhTQftuMMv+WLUg=="
},
"react-native-privacy-snapshot": {
"version": "git+ssh://git@github.com/BlueWallet/react-native-privacy-snapshot.git#529e4627d93f67752a27e82a040ff7b64dca0783",
@ -37252,9 +37252,9 @@
"integrity": "sha512-/OJD9Pb8IURyvn+1tWTszWPJqsbZ4hyHBU9P0xhOmk7h5owSuqL0zkfagU0pg7Vh0G2NKQkaPpUKUMMCUMDh/w=="
},
"react-native-screens": {
"version": "3.29.0",
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.29.0.tgz",
"integrity": "sha512-yB1GoAMamFAcYf4ku94uBPn0/ani9QG7NdI98beJ5cet2YFESYYzuEIuU+kt+CNRcO8qqKeugxlfgAa3HyTqlg==",
"version": "3.30.1",
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.30.1.tgz",
"integrity": "sha512-/muEvjocCtFb+j5J3YmLvB25+f4rIU8hnnxgGTkXcAf2omPBY8uhPjJaaFUlvj64VEoEzJcRpugbXWsjfPPIFg==",
"requires": {
"react-freeze": "^1.0.0",
"warn-once": "^0.1.0"
@ -37265,9 +37265,9 @@
"from": "react-native-secure-key-store@https://github.com/BlueWallet/react-native-secure-key-store#2076b48"
},
"react-native-share": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-10.0.2.tgz",
"integrity": "sha512-EZs4MtsyauAI1zP8xXT1hIFB/pXOZJNDCKcgCpEfTZFXgCUzz8MDVbI1ocP2hA59XHRSkqAQdbJ0BFTpjxOBlg=="
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-10.1.0.tgz",
"integrity": "sha512-fKKvwaZe5s3HW0tcRKyR5AWvAfXvkk0FgTw1nYWYjI4gNqntXbMjRqWZed8Hmd1MvIJS17K/ELPges0tsxbp3g=="
},
"react-native-size-matters": {
"version": "0.3.1",

View File

@ -154,7 +154,7 @@
"react-native-draggable-flatlist": "github:BlueWallet/react-native-draggable-flatlist#ebfddc4",
"react-native-elements": "3.4.3",
"react-native-fs": "2.20.0",
"react-native-gesture-handler": "2.15.0",
"react-native-gesture-handler": "2.16.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#8587876d68ab5920e79619726aeca9e672beaf2b",
@ -176,14 +176,14 @@
"react-native-rate": "1.2.12",
"react-native-reanimated": "3.8.1",
"react-native-safe-area-context": "4.9.0",
"react-native-screens": "3.29.0",
"react-native-screens": "3.30.1",
"react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48",
"react-native-share": "10.1.0",
"react-native-svg": "13.14.0",
"react-native-tcp-socket": "6.0.6",
"react-native-vector-icons": "10.0.3",
"react-native-watch-connectivity": "1.1.0",
"react-native-webview": "13.8.2",
"react-native-webview": "13.8.4",
"react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38",
"readable-stream": "3.6.2",
"realm": "12.6.2",

View File

@ -16,7 +16,7 @@ import {
import { Icon } from 'react-native-elements';
import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
import { BlueAlertWalletExportReminder, BlueDismissKeyboardInputAccessory, BlueLoading } from '../../BlueComponents';
import { BlueDismissKeyboardInputAccessory, BlueLoading } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import AmountInput from '../../components/AmountInput';
import * as NavigationService from '../../NavigationService';
@ -32,11 +32,13 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { btcToSatoshi, fiatToBTC, satoshiToBTC } from '../../blue_modules/currency';
import { presentWalletExportReminder } from '../../helpers/presentWalletExportReminder';
const LNDCreateInvoice = () => {
const { wallets, saveToDisk, setSelectedWalletID } = useContext(BlueStorageContext);
const { walletID, uri } = useRoute().params;
const wallet = useRef(wallets.find(item => item.getID() === walletID) || wallets.find(item => item.chain === Chain.OFFCHAIN));
const createInvoiceRef = useRef();
const { name } = useRoute();
const { colors } = useTheme();
const { navigate, getParent, goBack, pop, setParams } = useNavigation();
@ -117,9 +119,11 @@ const LNDCreateInvoice = () => {
if (wallet.current.getUserHasSavedExport()) {
renderReceiveDetails();
} else {
BlueAlertWalletExportReminder({
onSuccess: () => renderReceiveDetails(),
onFailure: () => {
presentWalletExportReminder()
.then(() => {
renderReceiveDetails();
})
.catch(() => {
getParent().pop();
NavigationService.navigate('WalletExportRoot', {
screen: 'WalletExport',
@ -127,8 +131,7 @@ const LNDCreateInvoice = () => {
walletID,
},
});
},
});
});
}
} else {
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
@ -192,7 +195,7 @@ const LNDCreateInvoice = () => {
// lets decode payreq and subscribe groundcontrol so we can receive push notification when our invoice is paid
/** @type LightningCustodianWallet */
const decoded = await wallet.current.decodeInvoice(invoiceRequest);
await Notifications.tryToObtainPermissions();
await Notifications.tryToObtainPermissions(createInvoiceRef);
Notifications.majorTomToGroundControl([], [decoded.payment_hash], []);
// send to lnurl-withdraw callback url if that exists
@ -315,7 +318,11 @@ const LNDCreateInvoice = () => {
const renderCreateButton = () => {
return (
<View style={styles.createButton}>
{isLoading ? <ActivityIndicator /> : <Button disabled={!(amount > 0)} onPress={createInvoice} title={loc.send.details_create} />}
{isLoading ? (
<ActivityIndicator />
) : (
<Button disabled={!(amount > 0)} ref={createInvoiceRef} onPress={createInvoice} title={loc.send.details_create} />
)}
</View>
);
};

View File

@ -1,7 +1,7 @@
import React, { useContext, useEffect, useState } from 'react';
import { View, Share, StyleSheet } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
import { BlueCopyTextToClipboard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -10,6 +10,7 @@ import presentAlert from '../../components/Alert';
import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const LNDViewAdditionalInvoiceInformation = () => {
const { walletID } = useRoute().params;
@ -60,7 +61,7 @@ const LNDViewAdditionalInvoiceInformation = () => {
</View>
<BlueSpacing20 />
<BlueText>{loc.lndViewInvoice.open_direct_channel}</BlueText>
<BlueCopyTextToClipboard text={walletInfo.uris[0]} />
<CopyTextToClipboard text={walletInfo.uris[0]} />
<View style={styles.share}>
<Button
icon={{

View File

@ -1,12 +1,13 @@
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { useRoute } from '@react-navigation/native';
import { BlueCopyTextToClipboard, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import { BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import QRCodeComponent from '../../components/QRCodeComponent';
import { useTheme } from '../../components/themes';
import SafeArea from '../../components/SafeArea';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const LNDViewAdditionalInvoicePreImage = () => {
// state = { walletInfo: undefined };
@ -27,7 +28,7 @@ const LNDViewAdditionalInvoicePreImage = () => {
<QRCodeComponent value={preImageData} size={300} logoSize={90} />
</View>
<BlueSpacing20 />
<BlueCopyTextToClipboard text={preImageData} />
<CopyTextToClipboard text={preImageData} />
</View>
</SafeArea>
);

View File

@ -4,7 +4,7 @@ import Share from 'react-native-share';
import { Icon } from 'react-native-elements';
import QRCodeComponent from '../../components/QRCodeComponent';
import { useNavigation, useNavigationState, useRoute } from '@react-navigation/native';
import { BlueLoading, BlueText, BlueCopyTextToClipboard, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import { BlueLoading, BlueText, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -15,6 +15,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const LNDViewInvoice = () => {
const { invoice, walletID } = useRoute().params;
@ -252,7 +253,7 @@ const LNDViewInvoice = () => {
{loc.lndViewInvoice.for} {invoice.description}
</BlueText>
)}
<BlueCopyTextToClipboard truncated text={invoice.payment_request} />
<CopyTextToClipboard truncated text={invoice.payment_request} />
<Button onPress={handleOnSharePressed} title={loc.receive.details_share} />

View File

@ -10,19 +10,10 @@ import {
TextInput,
View,
} from 'react-native';
import { useNavigation, useRoute, useFocusEffect } from '@react-navigation/native';
import { useRoute, useFocusEffect } from '@react-navigation/native';
import Share from 'react-native-share';
import QRCodeComponent from '../../components/QRCodeComponent';
import {
BlueLoading,
BlueCopyTextToClipboard,
BlueButtonLink,
BlueText,
BlueSpacing20,
BlueAlertWalletExportReminder,
BlueCard,
BlueSpacing40,
} from '../../BlueComponents';
import { BlueLoading, BlueButtonLink, BlueText, BlueSpacing20, BlueCard, BlueSpacing40 } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import BottomModal from '../../components/BottomModal';
import { Chain, BitcoinUnit } from '../../models/bitcoinUnits';
@ -39,6 +30,8 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { fiatToBTC, satoshiToBTC } from '../../blue_modules/currency';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const ReceiveDetails = () => {
const { walletID, address } = useRoute().params;
@ -53,7 +46,7 @@ const ReceiveDetails = () => {
const [showPendingBalance, setShowPendingBalance] = useState(false);
const [showConfirmedBalance, setShowConfirmedBalance] = useState(false);
const [showAddress, setShowAddress] = useState(false);
const { navigate, goBack, setParams } = useNavigation();
const { goBack, setParams } = useExtendedNavigation();
const { colors } = useTheme();
const [intervalMs, setIntervalMs] = useState(5000);
const [eta, setEta] = useState('');
@ -101,34 +94,27 @@ const ReceiveDetails = () => {
// re-fetching address balance periodically
useEffect(() => {
console.log('receive/defails - useEffect');
console.log('receive/details - useEffect');
if (fetchAddressInterval.current) {
// interval already exists, lets cleanup it and recreate, so theres no duplicate intervals
clearInterval(fetchAddressInterval.current);
fetchAddressInterval.current = undefined;
}
fetchAddressInterval.current = setInterval(async () => {
const intervalId = setInterval(async () => {
try {
const decoded = DeeplinkSchemaMatch.bip21decode(bip21encoded);
const address2use = address || decoded.address;
if (!address2use) return;
const addressToUse = address || decoded.address;
if (!addressToUse) return;
console.log('checking address', address2use, 'for balance...');
const balance = await BlueElectrum.getBalanceByAddress(address2use);
console.log('checking address', addressToUse, 'for balance...');
const balance = await BlueElectrum.getBalanceByAddress(addressToUse);
console.log('...got', balance);
if (balance.unconfirmed > 0) {
if (initialConfirmed === 0 && initialUnconfirmed === 0) {
// saving initial values for later (when tx gets confirmed)
setInitialConfirmed(balance.confirmed);
setInitialUnconfirmed(balance.unconfirmed);
setIntervalMs(25000);
triggerHapticFeedback(HapticFeedbackTypes.ImpactHeavy);
}
const txs = await BlueElectrum.getMempoolTransactionsByAddress(address2use);
const txs = await BlueElectrum.getMempoolTransactionsByAddress(addressToUse);
const tx = txs.pop();
if (tx) {
const rez = await BlueElectrum.multiGetTransactionByTxid([tx.tx_hash], 10, true);
@ -137,11 +123,9 @@ const ReceiveDetails = () => {
const fees = await BlueElectrum.estimateFees();
if (satPerVbyte >= fees.fast) {
setEta(loc.formatString(loc.transactions.eta_10m));
}
if (satPerVbyte >= fees.medium && satPerVbyte < fees.fast) {
} else if (satPerVbyte >= fees.medium) {
setEta(loc.formatString(loc.transactions.eta_3h));
}
if (satPerVbyte < fees.medium) {
} else {
setEta(loc.formatString(loc.transactions.eta_1d));
}
}
@ -158,7 +142,6 @@ const ReceiveDetails = () => {
} else if (balance.unconfirmed === 0 && initialUnconfirmed !== 0) {
// now, handling a case when unconfirmed == 0, but in past it wasnt (i.e. it changed while user was
// staring at the screen)
const balanceToShow = balance.confirmed - initialConfirmed;
if (balanceToShow > 0) {
@ -166,17 +149,12 @@ const ReceiveDetails = () => {
setShowConfirmedBalance(true);
setShowPendingBalance(false);
setShowAddress(false);
clearInterval(fetchAddressInterval.current);
fetchAddressInterval.current = undefined;
setDisplayBalance(
loc.formatString(loc.transactions.received_with_amount, {
amt1: formatBalance(balanceToShow, BitcoinUnit.LOCAL_CURRENCY, true).toString(),
amt2: formatBalance(balanceToShow, BitcoinUnit.BTC, true).toString(),
}),
);
fetchAndSaveWalletTransactions(walletID);
} else {
// rare case, but probable. transaction evicted from mempool (maybe cancelled by the sender)
@ -189,6 +167,8 @@ const ReceiveDetails = () => {
console.log(error);
}
}, intervalMs);
return () => clearInterval(intervalId);
}, [bip21encoded, address, initialConfirmed, initialUnconfirmed, intervalMs, fetchAndSaveWalletTransactions, walletID]);
const renderConfirmedBalance = () => {
@ -271,7 +251,7 @@ const ReceiveDetails = () => {
)}
<QRCodeComponent value={bip21encoded} />
<BlueCopyTextToClipboard text={isCustom ? bip21encoded : address} ref={receiveAddressButton} />
<CopyTextToClipboard text={isCustom ? bip21encoded : address} ref={receiveAddressButton} />
</View>
<View style={styles.share}>
<BlueCard>
@ -296,7 +276,7 @@ const ReceiveDetails = () => {
let newAddress;
if (address) {
setAddressBIP21Encoded(address);
await Notifications.tryToObtainPermissions(receiveAddressButton.current);
await Notifications.tryToObtainPermissions(receiveAddressButton);
Notifications.majorTomToGroundControl([address], [], []);
} else {
if (wallet.chain === Chain.ONCHAIN) {
@ -324,7 +304,7 @@ const ReceiveDetails = () => {
}
}
setAddressBIP21Encoded(newAddress);
await Notifications.tryToObtainPermissions(receiveAddressButton.current);
await Notifications.tryToObtainPermissions(receiveAddressButton);
Notifications.majorTomToGroundControl([newAddress], [], []);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -341,22 +321,7 @@ const ReceiveDetails = () => {
useCallback(() => {
const task = InteractionManager.runAfterInteractions(async () => {
if (wallet) {
if (!wallet.getUserHasSavedExport()) {
BlueAlertWalletExportReminder({
onSuccess: obtainWalletAddress,
onFailure: () => {
navigate('WalletExportRoot', {
screen: 'WalletExport',
params: {
walletID: wallet.getID(),
},
});
},
anchor: receiveAddressButton.current,
});
} else {
obtainWalletAddress();
}
obtainWalletAddress();
} else if (!wallet && address) {
setAddressBIP21Encoded(address);
}

View File

@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from 'react';
import { ActivityIndicator, findNodeHandle, ScrollView, StyleSheet, View } from 'react-native';
import { ActivityIndicator, ScrollView, StyleSheet, View } from 'react-native';
import { useNavigation, useRoute, useIsFocused } from '@react-navigation/native';
import { BlueSpacing20 } from '../../BlueComponents';
@ -9,10 +9,9 @@ import { SquareButton } from '../../components/SquareButton';
import loc from '../../loc';
import presentAlert from '../../components/Alert';
import { requestCameraAuthorization } from '../../helpers/scan-qr';
import { scanQrHelper } from '../../helpers/scan-qr';
import { useTheme } from '../../components/themes';
import SafeArea from '../../components/SafeArea';
import { isDesktop } from '../../blue_modules/environment';
const bitcoin = require('bitcoinjs-lib');
const fs = require('../../blue_modules/fs');
@ -21,6 +20,7 @@ const PsbtMultisigQRCode = () => {
const { colors } = useTheme();
const openScannerButton = useRef();
const { psbtBase64, isShowOpenScanner } = useRoute().params;
const { name } = useRoute();
const [isLoading, setIsLoading] = useState(false);
const dynamicQRCode = useRef();
const isFocused = useIsFocused();
@ -61,20 +61,9 @@ const PsbtMultisigQRCode = () => {
}
};
const openScanner = () => {
if (isDesktop) {
fs.showActionSheet({ anchor: findNodeHandle(openScannerButton.current) }).then(data => onBarScanned({ data }));
} else {
requestCameraAuthorization().then(() =>
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
onBarScanned,
showFileImportButton: true,
},
}),
);
}
const openScanner = async () => {
const scanned = await scanQrHelper(navigate, name, true);
onBarScanned({ data: scanned });
};
const exportPSBT = () => {

View File

@ -6,7 +6,7 @@ import { useNavigation, useRoute, useIsFocused } from '@react-navigation/native'
import RNFS from 'react-native-fs';
import Biometric from '../../class/biometrics';
import { BlueText, BlueCard, BlueSpacing20, BlueCopyToClipboardButton } from '../../BlueComponents';
import { BlueText, BlueCard, BlueSpacing20 } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -18,6 +18,7 @@ import { useTheme } from '../../components/themes';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import SafeArea from '../../components/SafeArea';
import { SecondButton } from '../../components/SecondButton';
import CopyToClipboardButton from '../../components/CopyToClipboardButton';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
const bitcoin = require('bitcoinjs-lib');
const fs = require('../../blue_modules/fs');
@ -275,7 +276,7 @@ const PsbtWithHardwareWallet = () => {
/>
<BlueSpacing20 />
<View style={styles.copyToClipboard}>
<BlueCopyToClipboardButton
<CopyToClipboardButton
stringToCopy={typeof psbt === 'string' ? psbt : psbt.toBase64()}
displayText={loc.send.psbt_clipboard}
/>

View File

@ -4,13 +4,14 @@ import { ScrollView, TouchableWithoutFeedback, I18nManager, StyleSheet, Linking,
import { Button as ButtonRNElements } from 'react-native-elements';
import navigationStyle from '../../components/navigationStyle';
import { BlueCard, BlueCopyToClipboardButton, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import loc from '../../loc';
import { BlueCurrentTheme, useTheme } from '../../components/themes';
import Notifications from '../../blue_modules/notifications';
import presentAlert from '../../components/Alert';
import { Button } from '../../components/Button';
import ListItem from '../../components/ListItem';
import CopyToClipboardButton from '../../components/CopyToClipboardButton';
const NotificationSettings = () => {
const [isLoading, setIsLoading] = useState(true);
@ -147,7 +148,7 @@ const NotificationSettings = () => {
{isShowTokenInfo >= 9 && (
<View>
<BlueCopyToClipboardButton stringToCopy={tokenInfo} displayText={tokenInfo} />
<CopyToClipboardButton stringToCopy={tokenInfo} displayText={tokenInfo} />
</View>
)}

View File

@ -2,7 +2,7 @@ import React, { useContext, useEffect, useLayoutEffect, useState } from 'react';
import { View, ScrollView, TouchableOpacity, Text, TextInput, Linking, StyleSheet, Keyboard } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
import Clipboard from '@react-native-clipboard/clipboard';
import { BlueCard, BlueCopyToClipboardButton, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import HandoffComponent from '../../components/handoff';
import loc from '../../loc';
@ -11,6 +11,7 @@ import ToolTipMenu from '../../components/TooltipMenu';
import presentAlert from '../../components/Alert';
import { useTheme } from '../../components/themes';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import CopyToClipboardButton from '../../components/CopyToClipboardButton';
const dayjs = require('dayjs');
function onlyUnique(value, index, self) {
@ -240,7 +241,7 @@ const TransactionsDetails = () => {
<>
<View style={styles.rowHeader}>
<BlueText style={styles.rowCaption}>{loc.transactions.details_from}</BlueText>
<BlueCopyToClipboardButton stringToCopy={from.filter(onlyUnique).join(', ')} />
<CopyToClipboardButton stringToCopy={from.filter(onlyUnique).join(', ')} />
</View>
{renderSection(from.filter(onlyUnique))}
<View style={styles.marginBottom18} />
@ -251,7 +252,7 @@ const TransactionsDetails = () => {
<>
<View style={styles.rowHeader}>
<BlueText style={styles.rowCaption}>{loc.transactions.details_to}</BlueText>
<BlueCopyToClipboardButton stringToCopy={to.filter(onlyUnique).join(', ')} />
<CopyToClipboardButton stringToCopy={to.filter(onlyUnique).join(', ')} />
</View>
{renderSection(arrDiff(from, to.filter(onlyUnique)))}
<View style={styles.marginBottom18} />
@ -270,7 +271,7 @@ const TransactionsDetails = () => {
<>
<View style={styles.rowHeader}>
<BlueText style={styles.txid}>{loc.transactions.txid}</BlueText>
<BlueCopyToClipboardButton stringToCopy={tx.hash} />
<CopyToClipboardButton stringToCopy={tx.hash} />
</View>
<BlueText style={styles.rowValue}>{tx.hash}</BlueText>
<View style={styles.marginBottom18} />

View File

@ -341,7 +341,9 @@ const TransactionsStatus = () => {
if (txMetadata[tx.hash].memo) {
return (
<View style={styles.memo}>
<Text style={styles.memoText}>{txMetadata[tx.hash].memo}</Text>
<Text selectable style={styles.memoText}>
{txMetadata[tx.hash].memo}
</Text>
<BlueSpacing20 />
</View>
);
@ -367,7 +369,7 @@ const TransactionsStatus = () => {
<View style={styles.container}>
<BlueCard>
<View style={styles.center}>
<Text style={[styles.value, stylesHook.value]}>
<Text style={[styles.value, stylesHook.value]} selectable>
{formatBalanceWithoutSuffix(tx.value, wallet.current.preferredBalanceUnit, true)}{' '}
{wallet.current.preferredBalanceUnit !== BitcoinUnit.LOCAL_CURRENCY && (
<Text style={[styles.valueUnit, stylesHook.valueUnit]}>{loc.units[wallet.current.preferredBalanceUnit]}</Text>

View File

@ -13,7 +13,6 @@ import {
Text,
TouchableOpacity,
View,
findNodeHandle,
} from 'react-native';
import { Icon } from 'react-native-elements';
import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
@ -37,7 +36,6 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import usePrivacy from '../../hooks/usePrivacy';
import { isDesktop } from '../../blue_modules/environment';
const prompt = require('../../helpers/prompt');
const A = require('../../blue_modules/analytics');
@ -467,15 +465,11 @@ const WalletsAddMultisigStep2 = () => {
};
const scanOrOpenFile = () => {
if (isDesktop) {
fs.showActionSheet({ anchor: findNodeHandle(openScannerButton.current) }).then(onBarScanned);
} else {
setIsProvideMnemonicsModalVisible(false);
InteractionManager.runAfterInteractions(async () => {
const scanned = await scanQrHelper(navigation.navigate, name, true);
onBarScanned({ data: scanned });
});
}
setIsProvideMnemonicsModalVisible(false);
InteractionManager.runAfterInteractions(async () => {
const scanned = await scanQrHelper(navigation.navigate, name, true);
onBarScanned({ data: scanned });
});
};
const dashType = ({ index, lastIndex, isChecked, isFocus }) => {

View File

@ -32,7 +32,7 @@ import {
LightningLdkWallet,
} from '../../class';
import loc, { formatBalanceWithoutSuffix } from '../../loc';
import { useRoute, useNavigation } from '@react-navigation/native';
import { useRoute } from '@react-navigation/native';
import RNFS from 'react-native-fs';
import Share from 'react-native-share';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -48,6 +48,7 @@ import ListItem from '../../components/ListItem';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import Button from '../../components/Button';
import { SecondButton } from '../../components/SecondButton';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
const prompt = require('../../helpers/prompt');
@ -134,7 +135,7 @@ const WalletDetails = () => {
const [isAdvancedModeEnabledRender, setIsAdvancedModeEnabledRender] = useState(false);
const [isBIP47Enabled, setIsBIP47Enabled] = useState(wallet.isBIP47Enabled());
const [hideTransactionsInWalletsList, setHideTransactionsInWalletsList] = useState(!wallet.getHideTransactionsInWalletsList());
const { goBack, navigate, setOptions, popToTop } = useNavigation();
const { goBack, setOptions, popToTop, navigate } = useExtendedNavigation();
const { colors } = useTheme();
const [masterFingerprint, setMasterFingerprint] = useState();
const walletTransactionsLength = useMemo(() => wallet.getTransactions().length, [wallet]);

View File

@ -1,10 +1,8 @@
import React, { useState, useCallback, useContext, useRef, useEffect } from 'react';
import { InteractionManager, ScrollView, ActivityIndicator, View, StyleSheet, AppState } from 'react-native';
import { useNavigation, useFocusEffect, useRoute } from '@react-navigation/native';
import { BlueSpacing20, BlueText, BlueCopyTextToClipboard, BlueCard } from '../../BlueComponents';
import { BlueSpacing20, BlueText, BlueCard } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import Biometric from '../../class/biometrics';
import { LegacyWallet, LightningCustodianWallet, SegwitBech32Wallet, SegwitP2SHWallet, WatchOnlyWallet } from '../../class';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -13,6 +11,7 @@ import HandoffComponent from '../../components/handoff';
import { useTheme } from '../../components/themes';
import SafeArea from '../../components/SafeArea';
import usePrivacy from '../../hooks/usePrivacy';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const WalletExport = () => {
const { wallets, saveToDisk } = useContext(BlueStorageContext);
@ -56,13 +55,6 @@ const WalletExport = () => {
enableBlur();
const task = InteractionManager.runAfterInteractions(async () => {
if (wallet) {
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return goBack();
}
}
if (!wallet.getUserHasSavedExport()) {
wallet.setUserHasSavedExport(true);
saveToDisk();
@ -75,7 +67,7 @@ const WalletExport = () => {
disableBlur();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [goBack, saveToDisk, wallet]),
}, [wallet]),
);
if (isLoading || !wallet)
@ -117,7 +109,7 @@ const WalletExport = () => {
)}
<BlueSpacing20 />
{wallet.type === LightningCustodianWallet.type || wallet.type === WatchOnlyWallet.type ? (
<BlueCopyTextToClipboard text={wallet.getSecret()} />
<CopyTextToClipboard text={wallet.getSecret()} />
) : (
<BlueText style={[styles.secret, styles.secretWritingDirection, stylesHook.secret]} testID="Secret">
{wallet.getSecret()}

View File

@ -1,10 +1,9 @@
import React, { useCallback, useContext, useRef, useState } from 'react';
import { ActivityIndicator, InteractionManager, ScrollView, StyleSheet, View } from 'react-native';
import { useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
import { useFocusEffect, useRoute } from '@react-navigation/native';
import { BlueSpacing20, BlueText } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import { DynamicQRCode } from '../../components/DynamicQRCode';
import Biometric from '../../class/biometrics';
import loc from '../../loc';
import { SquareButton } from '../../components/SquareButton';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -21,7 +20,6 @@ const ExportMultisigCoordinationSetup = () => {
const dynamicQRCode = useRef();
const [isLoading, setIsLoading] = useState(true);
const [isShareButtonTapped, setIsShareButtonTapped] = useState(false);
const { goBack } = useNavigation();
const { colors } = useTheme();
const { enableBlur, disableBlur } = usePrivacy();
const stylesHook = StyleSheet.create({
@ -54,13 +52,6 @@ const ExportMultisigCoordinationSetup = () => {
enableBlur();
const task = InteractionManager.runAfterInteractions(async () => {
if (wallet) {
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return goBack();
}
}
qrCodeContents.current = Buffer.from(wallet.getXpub(), 'ascii').toString('hex');
setIsLoading(false);
}
@ -69,7 +60,7 @@ const ExportMultisigCoordinationSetup = () => {
task.cancel();
disableBlur();
};
}, [disableBlur, enableBlur, goBack, wallet]),
}, [disableBlur, enableBlur, wallet]),
);
return isLoading ? (

View File

@ -20,7 +20,7 @@ import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import ActionSheet from '../ActionSheet';
import loc from '../../loc';
import { FContainer, FButton } from '../../components/FloatButtons';
import { useFocusEffect, useIsFocused, useNavigation, useRoute } from '@react-navigation/native';
import { useFocusEffect, useIsFocused, useRoute } from '@react-navigation/native';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import { isDesktop, isTablet } from '../../blue_modules/environment';
import BlueClipboard from '../../blue_modules/clipboard';
@ -30,6 +30,7 @@ import { scanQrHelper } from '../../helpers/scan-qr';
import { useTheme } from '../../components/themes';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import presentAlert from '../../components/Alert';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
const A = require('../../blue_modules/analytics');
const fs = require('../../blue_modules/fs');
@ -49,7 +50,7 @@ const WalletsList = () => {
} = useContext(BlueStorageContext);
const { width } = useWindowDimensions();
const { colors, scanImage } = useTheme();
const { navigate, setOptions } = useNavigation();
const { navigate, setOptions } = useExtendedNavigation();
const isFocused = useIsFocused();
const routeName = useRoute().name;
const [isLoading, setIsLoading] = useState(false);

View File

@ -1,10 +1,10 @@
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { BlueCopyTextToClipboard } from '../../BlueComponents';
import { PaymentCodeStackParamList } from '../../Navigation';
import QRCodeComponent from '../../components/QRCodeComponent';
import loc from '../../loc';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
type Props = NativeStackScreenProps<PaymentCodeStackParamList, 'PaymentCode'>;
@ -17,7 +17,7 @@ export default function PaymentCode({ route }: Props) {
{paymentCode && (
<>
<QRCodeComponent value={paymentCode} />
<BlueCopyTextToClipboard text={paymentCode} />
<CopyTextToClipboard text={paymentCode} truncated={false} />
</>
)}
</View>

View File

@ -1,10 +1,10 @@
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import React, { useContext, useEffect, useState } from 'react';
import { SectionList, StyleSheet, Text, View } from 'react-native';
import { BlueCopyTextToClipboard } from '../../BlueComponents';
import { PaymentCodeStackParamList } from '../../Navigation';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import loc from '../../loc';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
interface DataSection {
title: string;
@ -45,7 +45,7 @@ export default function PaymentCodesList({ route }: Props) {
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => (
<View>
<BlueCopyTextToClipboard truncated text={item} />
<CopyTextToClipboard truncated text={item} />
</View>
)}
renderSectionHeader={({ section: { title } }) => <Text style={styles.titleText}>{title}</Text>}

View File

@ -2,7 +2,7 @@ import React, { useCallback, useContext, useEffect, useState } from 'react';
import { useNavigation, useRoute } from '@react-navigation/native';
import { View, StyleSheet, ScrollView, BackHandler } from 'react-native';
import { BlueCopyTextToClipboard, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import { BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -11,6 +11,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea';
import usePrivacy from '../../hooks/usePrivacy';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const PleaseBackupLNDHub = () => {
const { wallets } = useContext(BlueStorageContext);
@ -63,7 +64,7 @@ const PleaseBackupLNDHub = () => {
</View>
<BlueSpacing20 />
<QRCodeComponent value={wallet.getSecret()} size={qrCodeSize} />
<BlueCopyTextToClipboard text={wallet.getSecret()} />
<CopyTextToClipboard text={wallet.getSecret()} />
<BlueSpacing20 />
<Button onPress={pop} title={loc.pleasebackup.ok_lnd} />
</ScrollView>

View File

@ -2,7 +2,7 @@ import React, { useCallback, useContext, useEffect } from 'react';
import { useNavigation, useRoute } from '@react-navigation/native';
import { View, useWindowDimensions, StyleSheet, BackHandler, ScrollView } from 'react-native';
import QRCode from 'react-native-qrcode-svg';
import { BlueCopyTextToClipboard, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import { BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -10,6 +10,7 @@ import { useTheme } from '../../components/themes';
import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea';
import usePrivacy from '../../hooks/usePrivacy';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
const PleaseBackupLdk = () => {
const { wallets } = useContext(BlueStorageContext);
@ -71,7 +72,7 @@ const PleaseBackupLdk = () => {
ecl="H"
/>
</View>
<BlueCopyTextToClipboard text={wallet.getSecret()} />
<CopyTextToClipboard text={wallet.getSecret()} />
<BlueSpacing20 />
<Button onPress={pop} title={loc.pleasebackup.ok_lnd} />
</ScrollView>

View File

@ -1,7 +1,6 @@
import React, { useEffect, useRef, useContext, useState } from 'react';
import { StyleSheet, useColorScheme, Platform } from 'react-native';
import DraggableFlatList, { ScaleDecorator } from 'react-native-draggable-flatlist';
import { useNavigation } from '@react-navigation/native';
import navigationStyle from '../../components/navigationStyle';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
@ -9,6 +8,7 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { useTheme } from '../../components/themes';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { WalletCarouselItem } from '../../components/WalletsCarousel';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
const styles = StyleSheet.create({
root: {
@ -24,7 +24,7 @@ const ReorderWallets = () => {
const { colors } = useTheme();
const { wallets, setWalletsWithNewOrder } = useContext(BlueStorageContext);
const colorScheme = useColorScheme();
const { navigate, setOptions } = useNavigation();
const { navigate, setOptions } = useExtendedNavigation();
const [searchQuery, setSearchQuery] = useState('');
const [isSearchFocused, setIsSearchFocused] = useState(false);
const [walletData, setWalletData] = useState([]);

View File

@ -15,9 +15,8 @@ import {
findNodeHandle,
} from 'react-native';
import { Icon } from 'react-native-elements';
import { useRoute, useNavigation, useFocusEffect } from '@react-navigation/native';
import { useRoute, useFocusEffect } from '@react-navigation/native';
import { Chain } from '../../models/bitcoinUnits';
import { BlueAlertWalletExportReminder } from '../../BlueComponents';
import WalletGradient from '../../class/wallet-gradient';
import navigationStyle from '../../components/navigationStyle';
import { LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet, WatchOnlyWallet } from '../../class';
@ -35,6 +34,8 @@ import PropTypes from 'prop-types';
import { scanQrHelper } from '../../helpers/scan-qr';
import { useTheme } from '../../components/themes';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { presentWalletExportReminder } from '../../helpers/presentWalletExportReminder';
const fs = require('../../blue_modules/fs');
const BlueElectrum = require('../../blue_modules/BlueElectrum');
@ -63,7 +64,7 @@ const WalletTransactions = ({ navigation }) => {
const [timeElapsed, setTimeElapsed] = useState(0);
const [limit, setLimit] = useState(15);
const [pageSize, setPageSize] = useState(20);
const { setParams, setOptions, navigate } = useNavigation();
const { setParams, setOptions, navigate } = useExtendedNavigation();
const { colors } = useTheme();
const [lnNodeInfo, setLnNodeInfo] = useState({ canReceive: 0, canSend: 0 });
const walletActionButtonsRef = useRef();
@ -518,20 +519,20 @@ const WalletTransactions = ({ navigation }) => {
if (wallet.getUserHasSavedExport()) {
onManageFundsPressed({ id });
} else {
BlueAlertWalletExportReminder({
onSuccess: async () => {
presentWalletExportReminder()
.then(async () => {
wallet.setUserHasSavedExport(true);
await saveToDisk();
onManageFundsPressed({ id });
},
onFailure: () =>
})
.catch(() => {
navigate('WalletExportRoot', {
screen: 'WalletExport',
params: {
walletID: wallet.getID(),
},
}),
});
});
});
}
}
}}

View File

@ -1,4 +1,4 @@
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { useFocusEffect } from '@react-navigation/native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import {
@ -52,6 +52,7 @@ import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc';
import { isDesktop } from '../../blue_modules/environment';
import ActionSheet from '../ActionSheet';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
const fs = require('../../blue_modules/fs');
const prompt = require('../../helpers/prompt');
@ -61,7 +62,7 @@ const ViewEditMultisigCosigners = ({ route }: Props) => {
const hasLoaded = useRef(false);
const { colors } = useTheme();
const { wallets, setWalletsWithNewOrder, isElectrumDisabled, isAdvancedModeEnabled } = useContext(BlueStorageContext);
const { navigate, goBack, dispatch, addListener } = useNavigation();
const { navigate, dispatch, addListener } = useExtendedNavigation();
const openScannerButtonRef = useRef();
const { walletId } = route.params;
const w = useRef(wallets.find(wallet => wallet.getID() === walletId));
@ -214,13 +215,6 @@ const ViewEditMultisigCosigners = ({ route }: Props) => {
enableBlur();
const task = InteractionManager.runAfterInteractions(async () => {
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return goBack();
}
}
if (!w.current) {
// lets create fake wallet so renderer wont throw any errors
w.current = new MultisigHDWallet();
@ -538,11 +532,11 @@ const ViewEditMultisigCosigners = ({ route }: Props) => {
};
const renderProvideMnemonicsModal = () => {
// @ts-ignore weird, property exists on typedefinition. might be some ts bugs
// @ts-ignore weird, property exists on type definition. might be some ts bugs
const isPad: boolean = Platform.isPad;
return (
<BottomModal isVisible={isProvideMnemonicsModalVisible} onClose={hideProvideMnemonicsModal} coverScreen={false}>
<KeyboardAvoidingView enabled={!isPad} behavior={Platform.OS === 'ios' ? 'position' : undefined}>
<BottomModal avoidKeyboard isVisible={isProvideMnemonicsModalVisible} onClose={hideProvideMnemonicsModal} coverScreen={false}>
<KeyboardAvoidingView enabled={!isPad} behavior={Platform.OS === 'ios' ? 'position' : 'padding'} keyboardVerticalOffset={120}>
<View style={[styles.modalContent, stylesHook.modalContent]}>
<BlueTextCentered>{loc.multisig.type_your_mnemonics}</BlueTextCentered>
<BlueSpacing20 />

View File

@ -2,9 +2,8 @@ import { NavigationProp, RouteProp, useFocusEffect, useNavigation, useRoute } fr
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { ActivityIndicator, InteractionManager, View } from 'react-native';
import Share from 'react-native-share';
import { BlueCopyTextToClipboard, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import Biometric from '../../class/biometrics';
import Button from '../../components/Button';
import QRCodeComponent from '../../components/QRCodeComponent';
import SafeArea from '../../components/SafeArea';
@ -12,6 +11,7 @@ import HandoffComponent from '../../components/handoff';
import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc';
import { styles, useDynamicStyles } from './xpub.styles';
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
type WalletXpubRouteProp = RouteProp<{ params: { walletID: string; xpub: string } }, 'params'>;
export type RootStackParamList = {
@ -43,13 +43,6 @@ const WalletXpub: React.FC = () => {
enableBlur();
const task = InteractionManager.runAfterInteractions(async () => {
if (wallet) {
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return navigation.goBack();
}
}
const walletXpub = wallet.getXpub();
if (xpub !== walletXpub) {
navigation.setParams({ xpub: walletXpub || undefined });
@ -99,7 +92,7 @@ const WalletXpub: React.FC = () => {
<QRCodeComponent value={xpub} size={qrCodeSize} />
<BlueSpacing20 />
<BlueCopyTextToClipboard text={xPubText} />
{xPubText && <CopyTextToClipboard text={xPubText} />}
</View>
<HandoffComponent title={loc.wallets.xpub_title} type={HandoffComponent.activityTypes.Xpub} userInfo={{ xpub: xPubText }} />
<View style={styles.share}>

View File

@ -2,7 +2,7 @@ const fs = require('fs');
const path = require('path');
const mainLocFile = './loc/en.json';
const dirsToInterate = ['components', 'screen', 'blue_modules', 'class'];
const dirsToInterate = ['components', 'screen', 'blue_modules', 'class', 'hooks', 'helpers'];
const addFiles = ['BlueComponents.js', 'App.js', 'BlueApp.ts', 'Navigation.tsx'];
const allowedLocPrefixes = ['loc.lnurl_auth', 'loc.units'];

View File

@ -206,7 +206,7 @@ describe('BlueWallet UI Tests - no wallets', () => {
await element(by.text(`No, and do not ask me again.`)).tap();
} catch (_) {}
await yo('BitcoinAddressQRCodeContainer');
await yo('BlueCopyTextToClipboard');
await yo('CopyTextToClipboard');
await element(by.id('SetCustomAmountButton')).tap();
await element(by.id('BitcoinAmountInput')).replaceText('1');
await element(by.id('CustomAmountDescription')).typeText('test');
@ -214,7 +214,7 @@ describe('BlueWallet UI Tests - no wallets', () => {
await sup('1 BTC');
await sup('test');
await yo('BitcoinAddressQRCodeContainer');
await yo('BlueCopyTextToClipboard');
await yo('CopyTextToClipboard');
await device.pressBack();
await device.pressBack();
await helperDeleteWallet('cr34t3d');

View File

@ -402,7 +402,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
// XPUB
await element(by.id('WalletDetailsScroll')).swipe('up', 'fast', 1);
await element(by.id('XPub')).tap();
await expect(element(by.id('BlueCopyTextToClipboard'))).toBeVisible();
await expect(element(by.id('CopyTextToClipboard'))).toBeVisible();
await device.pressBack();
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');