mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 09:50:15 +01:00
Merge branch 'master' into propsper
This commit is contained in:
commit
f96067ba66
@ -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 }}
|
||||
|
178
.github/workflows/build-ios-release-pullrequest.yml
vendored
178
.github/workflows/build-ios-release-pullrequest.yml
vendored
@ -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,
|
||||
});
|
||||
|
180
.github/workflows/build-ios-release-testflight.yml
vendored
180
.github/workflows/build-ios-release-testflight.yml
vendored
@ -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
59
App.js
@ -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>
|
||||
);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 }} />;
|
||||
};
|
||||
|
@ -639,7 +639,7 @@ const Navigation = () => {
|
||||
/>
|
||||
|
||||
<RootStack.Screen name="PaymentCodeRoot" component={PaymentCodeStackRoot} options={NavigationDefaultOptions} />
|
||||
<InitStack.Screen
|
||||
<RootStack.Screen
|
||||
name="ReorderWallets"
|
||||
component={ReorderWalletsStackRoot}
|
||||
options={{
|
||||
|
@ -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);
|
||||
|
@ -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: {
|
||||
|
65
components/CopyTextToClipboard.tsx
Normal file
65
components/CopyTextToClipboard.tsx
Normal 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 },
|
||||
});
|
27
components/CopyToClipboardButton.tsx
Normal file
27
components/CopyToClipboardButton.tsx
Normal 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;
|
9
components/NavigationProvider.tsx
Normal file
9
components/NavigationProvider.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
|
||||
interface NavigationProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const NavigationProvider: React.FC<NavigationProviderProps> = ({ children }) => {
|
||||
return <>{children}</>;
|
||||
};
|
16
helpers/presentWalletExportReminder.ts
Normal file
16
helpers/presentWalletExportReminder.ts
Normal 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 },
|
||||
);
|
||||
});
|
||||
};
|
94
hooks/useExtendedNavigation.ts
Normal file
94
hooks/useExtendedNavigation.ts
Normal 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,
|
||||
};
|
||||
};
|
@ -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 */
|
||||
|
@ -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",
|
@ -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];
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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
42
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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={{
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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} />
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 = () => {
|
||||
|
@ -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}
|
||||
/>
|
||||
|
@ -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>
|
||||
)}
|
||||
|
||||
|
@ -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} />
|
||||
|
@ -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>
|
||||
|
@ -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 }) => {
|
||||
|
@ -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]);
|
||||
|
@ -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()}
|
||||
|
@ -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 ? (
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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>}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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([]);
|
||||
|
@ -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(),
|
||||
},
|
||||
}),
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
@ -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 />
|
||||
|
@ -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}>
|
||||
|
@ -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'];
|
||||
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
Loading…
Reference in New Issue
Block a user