mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 23:08:07 +01:00
REF: resolved conflict
This commit is contained in:
commit
7288682b56
203 changed files with 83085 additions and 24127 deletions
3
.babelrc
3
.babelrc
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"presets": ["module:metro-react-native-babel-preset"]
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
|
|
||||||
[android]
|
|
||||||
target = Google Inc.:Google APIs:23
|
|
||||||
|
|
||||||
[download]
|
|
||||||
max_number_of_retries = 3
|
|
||||||
|
|
||||||
[maven_repositories]
|
|
||||||
central = https://repo1.maven.org/maven2
|
|
|
@ -3,7 +3,7 @@ jobs:
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:16.17.1
|
- image: cimg/node:16.20.0
|
||||||
|
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ jobs:
|
||||||
|
|
||||||
unit:
|
unit:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:16.17.1
|
- image: cimg/node:16.20.0
|
||||||
|
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
|
|
||||||
|
@ -50,10 +50,12 @@ jobs:
|
||||||
|
|
||||||
integration:
|
integration:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:16.17.1
|
- image: cimg/node:16.20.0
|
||||||
|
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
|
|
||||||
|
resource_class: large
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
{
|
{
|
||||||
"testRunner": "jest",
|
"testRunner": {
|
||||||
"runnerConfig": "tests/e2e/config.json",
|
"$0": "jest",
|
||||||
"skipLegacyWorkersInjection": true,
|
"args": {
|
||||||
|
"config": "tests/e2e/jest.config.js",
|
||||||
|
"_": ["e2e"]
|
||||||
|
}
|
||||||
|
},
|
||||||
"apps": {
|
"apps": {
|
||||||
"ios": {
|
"ios": {
|
||||||
"type": "ios.app",
|
"type": "ios.app",
|
||||||
|
|
|
@ -68,5 +68,10 @@
|
||||||
"env": {
|
"env": {
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"globals": { "fetch": false }
|
"globals": { "fetch": false },
|
||||||
|
"settings": {
|
||||||
|
"react": { // this is for eslint-plugin-react
|
||||||
|
"version": "detect" // React version. "detect" automatically picks the version you have installed.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
2
.github/workflows/build-release-apk.yml
vendored
2
.github/workflows/build-release-apk.yml
vendored
|
@ -30,7 +30,7 @@ jobs:
|
||||||
cache: 'gradle'
|
cache: 'gradle'
|
||||||
|
|
||||||
- name: Install node_modules
|
- name: Install node_modules
|
||||||
run: npm install
|
run: npm install --production
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
|
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
|
@ -39,6 +39,7 @@ jobs:
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: npm test || npm test || npm test
|
run: npm test || npm test || npm test
|
||||||
env:
|
env:
|
||||||
|
BIP47_HD_MNEMONIC: ${{ secrets.BIP47_HD_MNEMONIC}}
|
||||||
HD_MNEMONIC: ${{ secrets.HD_MNEMONIC }}
|
HD_MNEMONIC: ${{ secrets.HD_MNEMONIC }}
|
||||||
HD_MNEMONIC_BIP49: ${{ secrets.HD_MNEMONIC_BIP49 }}
|
HD_MNEMONIC_BIP49: ${{ secrets.HD_MNEMONIC_BIP49 }}
|
||||||
HD_MNEMONIC_BIP49_MANY_TX: ${{ secrets.HD_MNEMONIC_BIP49_MANY_TX }}
|
HD_MNEMONIC_BIP49_MANY_TX: ${{ secrets.HD_MNEMONIC_BIP49_MANY_TX }}
|
||||||
|
@ -94,7 +95,7 @@ jobs:
|
||||||
avd-name: Pixel_API_29_AOSP
|
avd-name: Pixel_API_29_AOSP
|
||||||
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none -camera-front none -partition-size 2047
|
emulator-options: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim -camera-back none -camera-front none -partition-size 2047
|
||||||
arch: x86_64
|
arch: x86_64
|
||||||
script: npm run e2e:release-test || npm run e2e:release-test || npm run e2e:release-test
|
script: npm run e2e:release-test || npm run e2e:release-test || npm run e2e:release-test || npm run e2e:release-test
|
||||||
env:
|
env:
|
||||||
TRAVIS: 1
|
TRAVIS: 1
|
||||||
HD_MNEMONIC: ${{ secrets.HD_MNEMONIC }}
|
HD_MNEMONIC: ${{ secrets.HD_MNEMONIC }}
|
||||||
|
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -20,7 +20,11 @@ DerivedData
|
||||||
*.hmap
|
*.hmap
|
||||||
*.ipa
|
*.ipa
|
||||||
*.xcuserstate
|
*.xcuserstate
|
||||||
|
ios/.xcode.env.local
|
||||||
*.hprof
|
*.hprof
|
||||||
|
.cxx/
|
||||||
|
*.keystore
|
||||||
|
!debug.keystore
|
||||||
|
|
||||||
# Android/IntelliJ
|
# Android/IntelliJ
|
||||||
#
|
#
|
||||||
|
@ -52,6 +56,7 @@ buck-out/
|
||||||
*/fastlane/report.xml
|
*/fastlane/report.xml
|
||||||
*/fastlane/Preview.html
|
*/fastlane/Preview.html
|
||||||
*/fastlane/screenshots
|
*/fastlane/screenshots
|
||||||
|
**/fastlane/test_output
|
||||||
|
|
||||||
# Bundle artifact
|
# Bundle artifact
|
||||||
*.jsbundle
|
*.jsbundle
|
||||||
|
@ -61,8 +66,12 @@ release-notes.json
|
||||||
release-notes.txt
|
release-notes.txt
|
||||||
current-branch.json
|
current-branch.json
|
||||||
|
|
||||||
ios/Pods/
|
# Ruby / CocoaPods
|
||||||
|
/ios/Pods/
|
||||||
|
/vendor/bundle/
|
||||||
|
|
||||||
|
# Temporary files created by Metro to check the health of the file watcher
|
||||||
|
.metro-health-check*
|
||||||
artifacts/
|
artifacts/
|
||||||
|
|
||||||
# Editors
|
# Editors
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
2.7.4
|
2.7.6
|
||||||
|
|
75
.tx/config
75
.tx/config
|
@ -1,42 +1,43 @@
|
||||||
[main]
|
[main]
|
||||||
host = https://www.transifex.com
|
host = https://www.transifex.com
|
||||||
|
|
||||||
[bluewallet.loc-en-json--master]
|
[o:bluewallet:p:bluewallet-fastlane:r:ios-fastlane-metadata-en-us-description-txt--master]
|
||||||
file_filter = loc/<lang>.json
|
file_filter = ios/fastlane/metadata/<lang>/description.txt
|
||||||
|
source_file = ios/fastlane/metadata/en-US/description.txt
|
||||||
|
source_lang = en_US
|
||||||
|
type = TXT
|
||||||
|
minimum_perc = 10
|
||||||
|
lang_map = fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, zh_CN: zh-Hans, zh_HK: zh-Hant, ar_SA: ar-SA, es_MX: es-MX, fr_CA: fr-CA, pt_PT: pt-PT, de_DE: de-DE, es_ES: es-ES
|
||||||
|
|
||||||
|
[o:bluewallet:p:bluewallet-fastlane:r:ios-fastlane-metadata-en-us-keywords-txt--master]
|
||||||
|
file_filter = ios/fastlane/metadata/<lang>/keywords.txt
|
||||||
|
source_file = ios/fastlane/metadata/en-US/keywords.txt
|
||||||
|
source_lang = en_US
|
||||||
|
type = TXT
|
||||||
|
minimum_perc = 10
|
||||||
|
lang_map = es_ES: es-ES, es_MX: es-MX, fr_CA: fr-CA, fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, zh_CN: zh-Hans, ar_SA: ar-SA, de_DE: de-DE, pt_PT: pt-PT, zh_HK: zh-Hant
|
||||||
|
|
||||||
|
[o:bluewallet:p:bluewallet-fastlane:r:ios-fastlane-metadata-en-us-name-txt--master]
|
||||||
|
file_filter = ios/fastlane/metadata/<lang>/name.txt
|
||||||
|
source_file = ios/fastlane/metadata/en-US/name.txt
|
||||||
|
source_lang = en_US
|
||||||
|
type = TXT
|
||||||
|
minimum_perc = 10
|
||||||
|
lang_map = zh_HK: zh-Hant, ar_SA: ar-SA, es_MX: es-MX, fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, de_DE: de-DE, es_ES: es-ES, fr_CA: fr-CA
|
||||||
|
|
||||||
|
[o:bluewallet:p:bluewallet-fastlane:r:ios-fastlane-metadata-en-us-promotional-text-txt--master]
|
||||||
|
file_filter = ios/fastlane/metadata/<lang>/promotional_text.txt
|
||||||
|
source_file = ios/fastlane/metadata/en-US/promotional_text.txt
|
||||||
|
source_lang = en_US
|
||||||
|
type = TXT
|
||||||
|
minimum_perc = 10
|
||||||
|
lang_map = zh_CN: zh-Hans, zh_HK: zh-Hant, ar_SA: ar-SA, es_MX: es-MX, fr_CA: fr-CA, fr_FR: fr-FR, pt_PT: pt-PT, de_DE: de-DE, es_ES: es-ES, nl_NL: nl-NL, pt_BR: pt-BR
|
||||||
|
|
||||||
|
[o:bluewallet:p:bluewallet:r:loc-en-json--master]
|
||||||
|
file_filter = loc/<lang>.json
|
||||||
|
source_file = loc/en.json
|
||||||
|
source_lang = en
|
||||||
|
type = KEYVALUEJSON
|
||||||
minimum_perc = 30
|
minimum_perc = 30
|
||||||
source_file = loc/en.json
|
lang_map = vi_VN: vi_vn, zh_TW: zh_tw, af_ZA: zar_afr, id_ID: id_id, sk_SK: sk_sk, ja_JP: jp_jp, uk_UA: ua, zh_CN: zh_cn, hr_HR: hr_hr, tr_TR: tr_tr, sv_SE: sv_se, th_TH: th_th, pt_BR: pt_br, es_ES: es, fr_FR: fr_fr, hu_HU: hu_hu, nl_NL: nl_nl, ro: ro, ca: ca, cy: cy, de_DE: de_de, nb_NO: nb_no, pt_PT: pt_pt, xh: zar_xho, bg_BG: bg_bg, cs_CZ: cs_cz, da_DK: da_dk, el: el, fa_IR: fa, fi_FI: fi_fi
|
||||||
source_lang = en
|
|
||||||
type = KEYVALUEJSON
|
|
||||||
lang_map = af_ZA: zar_afr, bg_BG: bg_bg, ca: ca, cs_CZ: cs_cz, cy: cy, da_DK: da_dk, de_DE: de_de, el: el, es_ES: es, fa_IR: fa, fi_FI: fi_fi, fr_FR: fr_fr, hr_HR: hr_hr, hu_HU: hu_hu, id_ID: id_id, ja_JP: jp_jp, nb_NO: nb_no, nl_NL: nl_nl, pt_BR: pt_br, pt_PT: pt_pt, ro: ro, sk_SK: sk_sk, sv_SE: sv_se, th_TH: th_th, tr_TR: tr_tr, uk_UA: ua, vi_VN: vi_vn, xh: zar_xho, zh_CN: zh_cn, zh_TW: zh_tw
|
|
||||||
|
|
||||||
[bluewallet-fastlane.ios-fastlane-metadata-en-us-description-txt--master]
|
|
||||||
file_filter = ios/fastlane/metadata/<lang>/description.txt
|
|
||||||
minimum_perc = 10
|
|
||||||
source_file = ios/fastlane/metadata/en-US/description.txt
|
|
||||||
source_lang = en_US
|
|
||||||
type = TXT
|
|
||||||
lang_map = ar_SA: ar-SA, de_DE: de-DE, es_ES: es-ES, es_MX: es-MX, fr_CA: fr-CA, fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_HK: zh-Hant
|
|
||||||
|
|
||||||
[bluewallet-fastlane.ios-fastlane-metadata-en-us-keywords-txt--master]
|
|
||||||
file_filter = ios/fastlane/metadata/<lang>/keywords.txt
|
|
||||||
minimum_perc = 10
|
|
||||||
source_file = ios/fastlane/metadata/en-US/keywords.txt
|
|
||||||
source_lang = en_US
|
|
||||||
type = TXT
|
|
||||||
lang_map = ar_SA: ar-SA, de_DE: de-DE, es_ES: es-ES, es_MX: es-MX, fr_CA: fr-CA, fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_HK: zh-Hant
|
|
||||||
|
|
||||||
[bluewallet-fastlane.ios-fastlane-metadata-en-us-name-txt--master]
|
|
||||||
file_filter = ios/fastlane/metadata/<lang>/name.txt
|
|
||||||
minimum_perc = 10
|
|
||||||
source_file = ios/fastlane/metadata/en-US/name.txt
|
|
||||||
source_lang = en_US
|
|
||||||
type = TXT
|
|
||||||
lang_map = ar_SA: ar-SA, de_DE: de-DE, es_ES: es-ES, es_MX: es-MX, fr_CA: fr-CA, fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_HK: zh-Hant
|
|
||||||
|
|
||||||
[bluewallet-fastlane.ios-fastlane-metadata-en-us-promotional-text-txt--master]
|
|
||||||
file_filter = ios/fastlane/metadata/<lang>/promotional_text.txt
|
|
||||||
minimum_perc = 10
|
|
||||||
source_file = ios/fastlane/metadata/en-US/promotional_text.txt
|
|
||||||
source_lang = en_US
|
|
||||||
type = TXT
|
|
||||||
lang_map = ar_SA: ar-SA, de_DE: de-DE, es_ES: es-ES, es_MX: es-MX, fr_CA: fr-CA, fr_FR: fr-FR, nl_NL: nl-NL, pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_HK: zh-Hant
|
|
||||||
|
|
13
.xcode-env
Normal file
13
.xcode-env
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# This `.xcode.env` file is versioned and is used to source the
|
||||||
|
environment
|
||||||
|
# used when running script phases inside Xcode.
|
||||||
|
# To customize your local environment, you can create an
|
||||||
|
`.xcode.env.local`
|
||||||
|
# file that is not versioned.
|
||||||
|
|
||||||
|
# NODE_BINARY variable contains the PATH to the node executable.
|
||||||
|
#
|
||||||
|
# Customize the NODE_BINARY variable here.
|
||||||
|
# For example, to use nvm with brew, add the following line
|
||||||
|
# . "$(brew --prefix nvm)/nvm.sh" --no-use
|
||||||
|
export NODE_BINARY=$(command -v node)
|
64
App.js
64
App.js
|
@ -291,7 +291,7 @@ const App = () => {
|
||||||
currency.updateExchangeRate();
|
currency.updateExchangeRate();
|
||||||
const processed = await processPushNotifications();
|
const processed = await processPushNotifications();
|
||||||
if (processed) return;
|
if (processed) return;
|
||||||
const clipboard = await BlueClipboard.getClipboardContent();
|
const clipboard = await BlueClipboard().getClipboardContent();
|
||||||
const isAddressFromStoredWallet = wallets.some(wallet => {
|
const isAddressFromStoredWallet = wallets.some(wallet => {
|
||||||
if (wallet.chain === Chain.ONCHAIN) {
|
if (wallet.chain === Chain.ONCHAIN) {
|
||||||
// checking address validity is faster than unwrapping hierarchy only to compare it to garbage
|
// checking address validity is faster than unwrapping hierarchy only to compare it to garbage
|
||||||
|
@ -332,38 +332,40 @@ const App = () => {
|
||||||
|
|
||||||
const showClipboardAlert = ({ contentType }) => {
|
const showClipboardAlert = ({ contentType }) => {
|
||||||
ReactNativeHapticFeedback.trigger('impactLight', { ignoreAndroidSystemSettings: false });
|
ReactNativeHapticFeedback.trigger('impactLight', { ignoreAndroidSystemSettings: false });
|
||||||
BlueClipboard.getClipboardContent().then(clipboard => {
|
BlueClipboard()
|
||||||
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
.getClipboardContent()
|
||||||
ActionSheet.showActionSheetWithOptions(
|
.then(clipboard => {
|
||||||
{
|
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
||||||
options: [loc._.cancel, loc._.continue],
|
ActionSheet.showActionSheetWithOptions(
|
||||||
|
{
|
||||||
|
options: [loc._.cancel, loc._.continue],
|
||||||
|
title: loc._.clipboard,
|
||||||
|
message: contentType === ClipboardContentType.BITCOIN ? loc.wallets.clipboard_bitcoin : loc.wallets.clipboard_lightning,
|
||||||
|
cancelButtonIndex: 0,
|
||||||
|
},
|
||||||
|
buttonIndex => {
|
||||||
|
if (buttonIndex === 1) {
|
||||||
|
handleOpenURL({ url: clipboard });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ActionSheet.showActionSheetWithOptions({
|
||||||
|
buttons: [
|
||||||
|
{ text: loc._.cancel, style: 'cancel', onPress: () => {} },
|
||||||
|
{
|
||||||
|
text: loc._.continue,
|
||||||
|
style: 'default',
|
||||||
|
onPress: () => {
|
||||||
|
handleOpenURL({ url: clipboard });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
title: loc._.clipboard,
|
title: loc._.clipboard,
|
||||||
message: contentType === ClipboardContentType.BITCOIN ? loc.wallets.clipboard_bitcoin : loc.wallets.clipboard_lightning,
|
message: contentType === ClipboardContentType.BITCOIN ? loc.wallets.clipboard_bitcoin : loc.wallets.clipboard_lightning,
|
||||||
cancelButtonIndex: 0,
|
});
|
||||||
},
|
}
|
||||||
buttonIndex => {
|
});
|
||||||
if (buttonIndex === 1) {
|
|
||||||
handleOpenURL({ url: clipboard });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
ActionSheet.showActionSheetWithOptions({
|
|
||||||
buttons: [
|
|
||||||
{ text: loc._.cancel, style: 'cancel', onPress: () => {} },
|
|
||||||
{
|
|
||||||
text: loc._.continue,
|
|
||||||
style: 'default',
|
|
||||||
onPress: () => {
|
|
||||||
handleOpenURL({ url: clipboard });
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
title: loc._.clipboard,
|
|
||||||
message: contentType === ClipboardContentType.BITCOIN ? loc.wallets.clipboard_bitcoin : loc.wallets.clipboard_lightning,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -53,7 +53,7 @@ export const BlueButton = props => {
|
||||||
style={{
|
style={{
|
||||||
borderWidth: 0.7,
|
borderWidth: 0.7,
|
||||||
borderColor: 'transparent',
|
borderColor: 'transparent',
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor,
|
||||||
minHeight: 45,
|
minHeight: 45,
|
||||||
height: 45,
|
height: 45,
|
||||||
maxHeight: 45,
|
maxHeight: 45,
|
||||||
|
@ -89,7 +89,7 @@ export const SecondButton = forwardRef((props, ref) => {
|
||||||
style={{
|
style={{
|
||||||
borderWidth: 0.7,
|
borderWidth: 0.7,
|
||||||
borderColor: 'transparent',
|
borderColor: 'transparent',
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor,
|
||||||
minHeight: 45,
|
minHeight: 45,
|
||||||
height: 45,
|
height: 45,
|
||||||
maxHeight: 45,
|
maxHeight: 45,
|
||||||
|
@ -559,7 +559,12 @@ export const BlueHeaderDefaultMain = props => {
|
||||||
>
|
>
|
||||||
{props.leftText}
|
{props.leftText}
|
||||||
</Text>
|
</Text>
|
||||||
<PlusIcon onPress={props.onNewWalletPress} Component={TouchableOpacity} />
|
<PlusIcon
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc.wallets.add_title}
|
||||||
|
onPress={props.onNewWalletPress}
|
||||||
|
Component={TouchableOpacity}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
4
Gemfile
4
Gemfile
|
@ -1,6 +1,6 @@
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
|
||||||
ruby '2.7.4'
|
ruby '>= 2.6.10'
|
||||||
|
|
||||||
gem 'cocoapods', '~> 1.11', '>= 1.11.2'
|
gem 'cocoapods', '~> 1.11', '>= 1.11.3'
|
|
@ -83,6 +83,9 @@ import { isDesktop, isTablet, isHandset } from './blue_modules/environment';
|
||||||
import SettingsPrivacy from './screen/settings/SettingsPrivacy';
|
import SettingsPrivacy from './screen/settings/SettingsPrivacy';
|
||||||
import LNDViewAdditionalInvoicePreImage from './screen/lnd/lndViewAdditionalInvoicePreImage';
|
import LNDViewAdditionalInvoicePreImage from './screen/lnd/lndViewAdditionalInvoicePreImage';
|
||||||
import LdkViewLogs from './screen/wallets/ldkViewLogs';
|
import LdkViewLogs from './screen/wallets/ldkViewLogs';
|
||||||
|
import PaymentCode from './screen/wallets/paymentCode';
|
||||||
|
import PaymentCodesList from './screen/wallets/paymentCodesList';
|
||||||
|
import loc from './loc';
|
||||||
|
|
||||||
const WalletsStack = createNativeStackNavigator();
|
const WalletsStack = createNativeStackNavigator();
|
||||||
|
|
||||||
|
@ -465,6 +468,20 @@ const ExportMultisigCoordinationSetupRoot = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PaymentCodeStack = createNativeStackNavigator();
|
||||||
|
const PaymentCodeStackRoot = () => {
|
||||||
|
return (
|
||||||
|
<PaymentCodeStack.Navigator name="PaymentCodeRoot" screenOptions={{ headerHideShadow: true }} initialRouteName="PaymentCode">
|
||||||
|
<PaymentCodeStack.Screen name="PaymentCode" component={PaymentCode} options={{ headerTitle: loc.bip47.payment_code }} />
|
||||||
|
<PaymentCodeStack.Screen
|
||||||
|
name="PaymentCodesList"
|
||||||
|
component={PaymentCodesList}
|
||||||
|
options={{ headerTitle: loc.bip47.payment_codes_list }}
|
||||||
|
/>
|
||||||
|
</PaymentCodeStack.Navigator>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const RootStack = createNativeStackNavigator();
|
const RootStack = createNativeStackNavigator();
|
||||||
const NavigationDefaultOptions = { headerShown: false, stackPresentation: isDesktop ? 'containedModal' : 'modal' };
|
const NavigationDefaultOptions = { headerShown: false, stackPresentation: isDesktop ? 'containedModal' : 'modal' };
|
||||||
const Navigation = () => {
|
const Navigation = () => {
|
||||||
|
@ -500,6 +517,8 @@ const Navigation = () => {
|
||||||
stackPresentation: isDesktop ? 'containedModal' : 'fullScreenModal',
|
stackPresentation: isDesktop ? 'containedModal' : 'fullScreenModal',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<RootStack.Screen name="PaymentCodeRoot" component={PaymentCodeStackRoot} options={NavigationDefaultOptions} />
|
||||||
</RootStack.Navigator>
|
</RootStack.Navigator>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -83,8 +83,7 @@ npx react-native run-ios
|
||||||
npm run maccatalystpatches
|
npm run maccatalystpatches
|
||||||
```
|
```
|
||||||
|
|
||||||
Once the patches are applied, open Xcode and select "My Mac" as destination. If you are running macOS Catalina, you may need to remove all iOS 14 Widget targets.
|
Once the patches are applied, open Xcode and select "My Mac" as destination.
|
||||||
|
|
||||||
|
|
||||||
## TESTS
|
## TESTS
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ Grab an issue from [the backlog](https://github.com/BlueWallet/BlueWallet/projec
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
|
|
||||||
We accepts translations via [Transifex](https://www.transifex.com/bluewallet/bluewallet/)
|
We accept translations via [Transifex](https://www.transifex.com/bluewallet/bluewallet/)
|
||||||
|
|
||||||
To participate you need to:
|
To participate you need to:
|
||||||
1. Sign up to Transifex
|
1. Sign up to Transifex
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
watchEvents,
|
watchEvents,
|
||||||
useReachability,
|
useReachability,
|
||||||
useInstalled,
|
useInstalled,
|
||||||
|
usePaired,
|
||||||
transferCurrentComplicationUserInfo,
|
transferCurrentComplicationUserInfo,
|
||||||
} from 'react-native-watch-connectivity';
|
} from 'react-native-watch-connectivity';
|
||||||
import { Chain } from './models/bitcoinUnits';
|
import { Chain } from './models/bitcoinUnits';
|
||||||
|
@ -17,13 +18,14 @@ function WatchConnectivity() {
|
||||||
const { walletsInitialized, wallets, fetchWalletTransactions, saveToDisk, txMetadata, preferredFiatCurrency } =
|
const { walletsInitialized, wallets, fetchWalletTransactions, saveToDisk, txMetadata, preferredFiatCurrency } =
|
||||||
useContext(BlueStorageContext);
|
useContext(BlueStorageContext);
|
||||||
const isReachable = useReachability();
|
const isReachable = useReachability();
|
||||||
|
const isPaired = usePaired();
|
||||||
const isInstalled = useInstalled(); // true | false
|
const isInstalled = useInstalled(); // true | false
|
||||||
const messagesListenerActive = useRef(false);
|
const messagesListenerActive = useRef(false);
|
||||||
const lastPreferredCurrency = useRef(FiatUnit.USD.endPointKey);
|
const lastPreferredCurrency = useRef(FiatUnit.USD.endPointKey);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let messagesListener = () => {};
|
let messagesListener = () => {};
|
||||||
if (isInstalled && isReachable && walletsInitialized && messagesListenerActive.current === false) {
|
if (isPaired && isInstalled && isReachable && walletsInitialized && messagesListenerActive.current === false) {
|
||||||
messagesListener = watchEvents.addListener('message', handleMessages);
|
messagesListener = watchEvents.addListener('message', handleMessages);
|
||||||
messagesListenerActive.current = true;
|
messagesListenerActive.current = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -35,14 +37,14 @@ function WatchConnectivity() {
|
||||||
messagesListenerActive.current = false;
|
messagesListenerActive.current = false;
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [walletsInitialized, isReachable, isInstalled]);
|
}, [walletsInitialized, isPaired, isReachable, isInstalled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInstalled && isReachable && walletsInitialized) {
|
if (isPaired && isInstalled && isReachable && walletsInitialized) {
|
||||||
sendWalletsToWatch();
|
sendWalletsToWatch();
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [walletsInitialized, wallets, isReachable, isInstalled]);
|
}, [walletsInitialized, wallets, isPaired, isReachable, isInstalled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateApplicationContext({ isWalletsInitialized: walletsInitialized, randomID: Math.floor(Math.random() * 11) });
|
updateApplicationContext({ isWalletsInitialized: walletsInitialized, randomID: Math.floor(Math.random() * 11) });
|
||||||
|
@ -208,7 +210,7 @@ function WatchConnectivity() {
|
||||||
balance: formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true),
|
balance: formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true),
|
||||||
type: wallet.type,
|
type: wallet.type,
|
||||||
preferredBalanceUnit: wallet.getPreferredBalanceUnit(),
|
preferredBalanceUnit: wallet.getPreferredBalanceUnit(),
|
||||||
receiveAddress: receiveAddress,
|
receiveAddress,
|
||||||
transactions: watchTransactions,
|
transactions: watchTransactions,
|
||||||
hideBalance: wallet.hideBalance,
|
hideBalance: wallet.hideBalance,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,173 +1,124 @@
|
||||||
apply plugin: "com.android.application"
|
apply plugin: "com.android.application"
|
||||||
|
apply plugin: "kotlin-android"
|
||||||
|
apply plugin: "com.facebook.react"
|
||||||
|
|
||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
* This is the configuration block to customize your React Native Android app.
|
||||||
* and bundleReleaseJsAndAssets).
|
* By default you don't need to apply any configuration, just uncomment the lines you need.
|
||||||
* These basically call `react-native bundle` with the correct arguments during the Android build
|
|
||||||
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
|
|
||||||
* bundle directly from the development server. Below you can see all the possible configurations
|
|
||||||
* and their defaults. If you decide to add a configuration block, make sure to add it before the
|
|
||||||
* `apply from: "../../node_modules/react-native/react.gradle"` line.
|
|
||||||
*
|
|
||||||
* project.ext.react = [
|
|
||||||
* // the name of the generated asset file containing your JS bundle
|
|
||||||
* bundleAssetName: "index.android.bundle",
|
|
||||||
*
|
|
||||||
* // the entry file for bundle generation. If none specified and
|
|
||||||
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
|
|
||||||
* // default. Can be overridden with ENTRY_FILE environment variable.
|
|
||||||
* entryFile: "index.android.js",
|
|
||||||
*
|
|
||||||
* // https://reactnative.dev/docs/performance#enable-the-ram-format
|
|
||||||
* bundleCommand: "ram-bundle",
|
|
||||||
*
|
|
||||||
* // whether to bundle JS and assets in debug mode
|
|
||||||
* bundleInDebug: false,
|
|
||||||
*
|
|
||||||
* // whether to bundle JS and assets in release mode
|
|
||||||
* bundleInRelease: true,
|
|
||||||
*
|
|
||||||
* // whether to bundle JS and assets in another build variant (if configured).
|
|
||||||
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
|
|
||||||
* // The configuration property can be in the following formats
|
|
||||||
* // 'bundleIn${productFlavor}${buildType}'
|
|
||||||
* // 'bundleIn${buildType}'
|
|
||||||
* // bundleInFreeDebug: true,
|
|
||||||
* // bundleInPaidRelease: true,
|
|
||||||
* // bundleInBeta: true,
|
|
||||||
*
|
|
||||||
* // whether to disable dev mode in custom build variants (by default only disabled in release)
|
|
||||||
* // for example: to disable dev mode in the staging build type (if configured)
|
|
||||||
* devDisabledInStaging: true,
|
|
||||||
* // The configuration property can be in the following formats
|
|
||||||
* // 'devDisabledIn${productFlavor}${buildType}'
|
|
||||||
* // 'devDisabledIn${buildType}'
|
|
||||||
*
|
|
||||||
* // the root of your project, i.e. where "package.json" lives
|
|
||||||
* root: "../../",
|
|
||||||
*
|
|
||||||
* // where to put the JS bundle asset in debug mode
|
|
||||||
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
|
|
||||||
*
|
|
||||||
* // where to put the JS bundle asset in release mode
|
|
||||||
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
|
|
||||||
*
|
|
||||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
|
||||||
* // require('./image.png')), in debug mode
|
|
||||||
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
|
|
||||||
*
|
|
||||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
|
||||||
* // require('./image.png')), in release mode
|
|
||||||
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
|
|
||||||
*
|
|
||||||
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
|
|
||||||
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
|
|
||||||
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
|
|
||||||
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
|
|
||||||
* // for example, you might want to remove it from here.
|
|
||||||
* inputExcludes: ["android/**", "ios/**"],
|
|
||||||
*
|
|
||||||
* // override which node gets called and with what additional arguments
|
|
||||||
* nodeExecutableAndArgs: ["node"],
|
|
||||||
*
|
|
||||||
* // supply additional arguments to the packager
|
|
||||||
* extraPackagerArgs: []
|
|
||||||
* ]
|
|
||||||
*/
|
*/
|
||||||
|
react {
|
||||||
|
/* Folders */
|
||||||
|
// The root of your project, i.e. where "package.json" lives. Default is '..'
|
||||||
|
// root = file("../")
|
||||||
|
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
|
||||||
|
// reactNativeDir = file("../node_modules/react-native")
|
||||||
|
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
|
||||||
|
// codegenDir = file("../node_modules/react-native-codegen")
|
||||||
|
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
|
||||||
|
// cliFile = file("../node_modules/react-native/cli.js")
|
||||||
|
|
||||||
project.ext.react = [
|
/* Variants */
|
||||||
enableHermes: true, // clean and rebuild if changing
|
// The list of variants to that are debuggable. For those we're going to
|
||||||
]
|
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
|
||||||
|
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
|
||||||
|
// debuggableVariants = ["liteDebug", "prodDebug"]
|
||||||
|
|
||||||
apply from: "../../node_modules/react-native/react.gradle"
|
/* Bundling */
|
||||||
apply plugin: "com.bugsnag.android.gradle"
|
// A list containing the node command and its flags. Default is just 'node'.
|
||||||
|
// nodeExecutableAndArgs = ["node"]
|
||||||
|
//
|
||||||
|
// The command to run when bundling. By default is 'bundle'
|
||||||
|
// bundleCommand = "ram-bundle"
|
||||||
|
//
|
||||||
|
// The path to the CLI configuration file. Default is empty.
|
||||||
|
// bundleConfig = file(../rn-cli.config.js)
|
||||||
|
//
|
||||||
|
// The name of the generated asset file containing your JS bundle
|
||||||
|
// bundleAssetName = "MyApplication.android.bundle"
|
||||||
|
//
|
||||||
|
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
|
||||||
|
// entryFile = file("../js/MyApplication.android.js")
|
||||||
|
//
|
||||||
|
// A list of extra flags to pass to the 'bundle' commands.
|
||||||
|
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
|
||||||
|
// extraPackagerArgs = []
|
||||||
|
|
||||||
|
/* Hermes Commands */
|
||||||
|
// The hermes compiler command to run. By default it is 'hermesc'
|
||||||
|
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
|
||||||
|
//
|
||||||
|
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
|
||||||
|
// hermesFlags = ["-O", "-output-source-map"]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this to true to create two separate APKs instead of one:
|
* Set this to true to create four separate APKs instead of one,
|
||||||
* - An APK that only works on ARM devices
|
* one for each native architecture. This is useful if you don't
|
||||||
* - An APK that only works on x86 devices
|
* use App Bundles (https://developer.android.com/guide/app-bundle/)
|
||||||
* The advantage is the size of the APK is reduced by about 4MB.
|
* and want to have separate APKs to upload to the Play Store.
|
||||||
* Upload all the APKs to the Play Store and people will download
|
|
||||||
* the correct one based on the CPU architecture of their device.
|
|
||||||
*/
|
*/
|
||||||
def enableSeparateBuildPerCPUArchitecture = false
|
def enableSeparateBuildPerCPUArchitecture = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run Proguard to shrink the Java bytecode in release builds.
|
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
|
||||||
*/
|
*/
|
||||||
def enableProguardInReleaseBuilds = false
|
def enableProguardInReleaseBuilds = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The preferred build flavor of JavaScriptCore.
|
* The preferred build flavor of JavaScriptCore (JSC)
|
||||||
*
|
*
|
||||||
* For example, to use the international variant, you can use:
|
* For example, to use the international variant, you can use:
|
||||||
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
|
||||||
*
|
*
|
||||||
* The international variant includes ICU i18n library and necessary data
|
* The international variant includes ICU i18n library and necessary data
|
||||||
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
|
||||||
* give correct results when using with locales other than en-US. Note that
|
* give correct results when using with locales other than en-US. Note that
|
||||||
* this variant is about 6MiB larger per architecture than default.
|
* this variant is about 6MiB larger per architecture than default.
|
||||||
*/
|
*/
|
||||||
def jscFlavor = 'org.webkit:android-jsc-intl:+'
|
def jscFlavor = 'org.webkit:android-jsc-intl:+'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to enable the Hermes VM.
|
* Private function to get the list of Native Architectures you want to build.
|
||||||
*
|
* This reads the value from reactNativeArchitectures in your gradle.properties
|
||||||
* This should be set on project.ext.react and mirrored here. If it is not set
|
* file and works together with the --active-arch-only flag of react-native run-android.
|
||||||
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
|
|
||||||
* and the benefits of using Hermes will therefore be sharply reduced.
|
|
||||||
*/
|
*/
|
||||||
def enableHermes = project.ext.react.get("enableHermes", false);
|
def reactNativeArchitectures() {
|
||||||
|
def value = project.getProperties().get("reactNativeArchitectures")
|
||||||
|
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
ndkVersion rootProject.ext.ndkVersion
|
ndkVersion rootProject.ext.ndkVersion
|
||||||
|
|
||||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "io.bluewallet.bluewallet"
|
applicationId "io.bluewallet.bluewallet"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "6.3.2"
|
versionName "6.4.0"
|
||||||
multiDexEnabled true
|
testBuildType System.getProperty('testBuildType', 'debug')
|
||||||
missingDimensionStrategy 'react-native-camera', 'general'
|
|
||||||
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
|
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
ndk {
|
|
||||||
abiFilters 'arm64-v8a', 'x86_64', 'x86', 'armeabi-v7a'
|
|
||||||
}
|
|
||||||
|
|
||||||
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
|
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
|
||||||
missingDimensionStrategy 'detox', 'full'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
reset()
|
reset()
|
||||||
enable enableSeparateBuildPerCPUArchitecture
|
enable enableSeparateBuildPerCPUArchitecture
|
||||||
universalApk false // If true, also generate a universal APK
|
universalApk false // If true, also generate a universal APK
|
||||||
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
|
include (*reactNativeArchitectures())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// Caution! In production, you need to generate your own keystore file.
|
// Caution! In production, you need to generate your own keystore file.
|
||||||
// see https://reactnative.dev/docs/signed-apk-android.
|
// see https://reactnative.dev/docs/signed-apk-android.
|
||||||
minifyEnabled enableProguardInReleaseBuilds
|
minifyEnabled enableProguardInReleaseBuilds
|
||||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
|
||||||
|
proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +131,8 @@ android {
|
||||||
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
|
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
|
||||||
def abi = output.getFilter(OutputFile.ABI)
|
def abi = output.getFilter(OutputFile.ABI)
|
||||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||||
output.versionCodeOverride = versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
|
output.versionCodeOverride =
|
||||||
|
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -188,47 +140,20 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// The version of react-native is set by the React Native Gradle Plugin
|
||||||
|
implementation("com.facebook.react:react-android")
|
||||||
implementation files("../../node_modules/rn-ldk/android/libs/LDK-release.aar")
|
implementation files("../../node_modules/rn-ldk/android/libs/LDK-release.aar")
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
|
||||||
//noinspection GradleDynamicVersion
|
|
||||||
implementation files("../../node_modules/react-native-tor/android/libs/sifir_android.aar")
|
implementation files("../../node_modules/react-native-tor/android/libs/sifir_android.aar")
|
||||||
implementation "com.facebook.react:react-native:+" // From node_modules
|
|
||||||
|
|
||||||
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
|
if (hermesEnabled.toBoolean()) {
|
||||||
|
implementation("com.facebook.react:hermes-android")
|
||||||
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
|
|
||||||
exclude group:'com.facebook.fbjni'
|
|
||||||
}
|
|
||||||
|
|
||||||
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
|
|
||||||
exclude group:'com.facebook.flipper'
|
|
||||||
exclude group:'com.squareup.okhttp3', module:'okhttp'
|
|
||||||
}
|
|
||||||
|
|
||||||
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
|
|
||||||
exclude group:'com.facebook.flipper'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enableHermes) {
|
|
||||||
def hermesPath = "../../node_modules/hermes-engine/android/";
|
|
||||||
debugImplementation files(hermesPath + "hermes-debug.aar")
|
|
||||||
releaseImplementation files(hermesPath + "hermes-release.aar")
|
|
||||||
} else {
|
} else {
|
||||||
implementation jscFlavor
|
implementation jscFlavor
|
||||||
}
|
}
|
||||||
|
androidTestImplementation('com.wix:detox:+')
|
||||||
androidTestImplementation(project(path: ":detox"))
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run this once to be able to run the application with BUCK
|
|
||||||
// puts all compile dependencies into folder libs for BUCK to use
|
|
||||||
task copyDownloadableDepsToLibs(type: Copy) {
|
|
||||||
from configurations.implementation
|
|
||||||
into 'libs'
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: 'com.google.gms.google-services' // Google Services plugin
|
apply plugin: 'com.google.gms.google-services' // Google Services plugin
|
||||||
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
|
||||||
bugsnag {
|
|
||||||
uploadReactNativeMappings = true
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
"""Helper definitions to glob .aar and .jar targets"""
|
|
||||||
|
|
||||||
def create_aar_targets(aarfiles):
|
|
||||||
for aarfile in aarfiles:
|
|
||||||
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
|
|
||||||
lib_deps.append(":" + name)
|
|
||||||
android_prebuilt_aar(
|
|
||||||
name = name,
|
|
||||||
aar = aarfile,
|
|
||||||
)
|
|
||||||
|
|
||||||
def create_jar_targets(jarfiles):
|
|
||||||
for jarfile in jarfiles:
|
|
||||||
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
|
|
||||||
lib_deps.append(":" + name)
|
|
||||||
prebuilt_jar(
|
|
||||||
name = name,
|
|
||||||
binary_jar = jarfile,
|
|
||||||
)
|
|
|
@ -1,72 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
|
|
||||||
* directory of this source tree.
|
|
||||||
*/
|
|
||||||
package io.bluewallet.bluewallet;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import com.facebook.flipper.android.AndroidFlipperClient;
|
|
||||||
import com.facebook.flipper.android.utils.FlipperUtils;
|
|
||||||
import com.facebook.flipper.core.FlipperClient;
|
|
||||||
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
|
|
||||||
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
|
|
||||||
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
|
|
||||||
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
|
|
||||||
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
|
|
||||||
import com.facebook.react.ReactInstanceManager;
|
|
||||||
import com.facebook.react.bridge.ReactContext;
|
|
||||||
import com.facebook.react.modules.network.NetworkingModule;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
|
|
||||||
public class ReactNativeFlipper {
|
|
||||||
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
|
|
||||||
if (FlipperUtils.shouldEnableFlipper(context)) {
|
|
||||||
final FlipperClient client = AndroidFlipperClient.getInstance(context);
|
|
||||||
|
|
||||||
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
|
|
||||||
client.addPlugin(new ReactFlipperPlugin());
|
|
||||||
client.addPlugin(new DatabasesFlipperPlugin(context));
|
|
||||||
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
|
|
||||||
client.addPlugin(CrashReporterPlugin.getInstance());
|
|
||||||
|
|
||||||
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
|
|
||||||
NetworkingModule.setCustomClientBuilder(
|
|
||||||
new NetworkingModule.CustomClientBuilder() {
|
|
||||||
@Override
|
|
||||||
public void apply(OkHttpClient.Builder builder) {
|
|
||||||
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
client.addPlugin(networkFlipperPlugin);
|
|
||||||
client.start();
|
|
||||||
|
|
||||||
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
|
|
||||||
// Hence we run if after all native modules have been initialized
|
|
||||||
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
|
|
||||||
if (reactContext == null) {
|
|
||||||
reactInstanceManager.addReactInstanceEventListener(
|
|
||||||
new ReactInstanceManager.ReactInstanceEventListener() {
|
|
||||||
@Override
|
|
||||||
public void onReactContextInitialized(ReactContext reactContext) {
|
|
||||||
reactInstanceManager.removeReactInstanceEventListener(this);
|
|
||||||
reactContext.runOnNativeModulesQueueThread(
|
|
||||||
new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
client.addPlugin(new FrescoFlipperPlugin());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
client.addPlugin(new FrescoFlipperPlugin());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,6 +14,7 @@
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
android:largeHeap="true"
|
||||||
android:extractNativeLibs="true"
|
android:extractNativeLibs="true"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
|
@ -38,7 +39,8 @@
|
||||||
|
|
||||||
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions" />
|
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions" />
|
||||||
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
|
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
|
||||||
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
|
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
@ -57,7 +59,8 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
@ -71,8 +74,6 @@
|
||||||
<data android:scheme="bluewallet" />
|
<data android:scheme="bluewallet" />
|
||||||
<data android:scheme="lapp" />
|
<data android:scheme="lapp" />
|
||||||
<data android:scheme="blue" />
|
<data android:scheme="blue" />
|
||||||
<data android:scheme="bankid" />
|
|
||||||
<data android:scheme="swish" />
|
|
||||||
<data android:scheme="http" />
|
<data android:scheme="http" />
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
|
@ -8,6 +8,10 @@ import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.facebook.react.ReactActivity;
|
import com.facebook.react.ReactActivity;
|
||||||
|
|
||||||
|
import com.facebook.react.ReactActivityDelegate;
|
||||||
|
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
||||||
|
import com.facebook.react.defaults.DefaultReactActivityDelegate;
|
||||||
|
|
||||||
public class MainActivity extends ReactActivity {
|
public class MainActivity extends ReactActivity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,10 +24,27 @@ public class MainActivity extends ReactActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(null);
|
super.onCreate(null);
|
||||||
if (getResources().getBoolean(R.bool.portrait_only)) {
|
if (getResources().getBoolean(R.bool.portrait_only)) {
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link
|
||||||
|
* DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React
|
||||||
|
* (aka React 18) with two boolean flags.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected ReactActivityDelegate createReactActivityDelegate() {
|
||||||
|
return new DefaultReactActivityDelegate(
|
||||||
|
this,
|
||||||
|
getMainComponentName(),
|
||||||
|
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
|
||||||
|
DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled
|
||||||
|
// If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18).
|
||||||
|
DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,18 @@ import com.facebook.react.ReactApplication;
|
||||||
import com.facebook.react.ReactInstanceManager;
|
import com.facebook.react.ReactInstanceManager;
|
||||||
import com.facebook.react.ReactNativeHost;
|
import com.facebook.react.ReactNativeHost;
|
||||||
import com.facebook.react.ReactPackage;
|
import com.facebook.react.ReactPackage;
|
||||||
|
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
|
||||||
|
import com.facebook.react.defaults.DefaultReactNativeHost;
|
||||||
import com.facebook.soloader.SoLoader;
|
import com.facebook.soloader.SoLoader;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.bugsnag.android.Bugsnag;
|
import com.bugsnag.android.Bugsnag;
|
||||||
import com.facebook.react.bridge.JSIModulePackage;
|
|
||||||
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
|
|
||||||
|
|
||||||
public class MainApplication extends Application implements ReactApplication {
|
public class MainApplication extends Application implements ReactApplication {
|
||||||
|
|
||||||
private final ReactNativeHost mReactNativeHost =
|
private final ReactNativeHost mReactNativeHost =
|
||||||
new ReactNativeHost(this) {
|
new DefaultReactNativeHost(this) {
|
||||||
@Override
|
@Override
|
||||||
public boolean getUseDeveloperSupport() {
|
public boolean getUseDeveloperSupport() {
|
||||||
return BuildConfig.DEBUG;
|
return BuildConfig.DEBUG;
|
||||||
|
@ -38,10 +38,15 @@ public class MainApplication extends Application implements ReactApplication {
|
||||||
return "index";
|
return "index";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JSIModulePackage getJSIModulePackage() {
|
protected boolean isNewArchEnabled() {
|
||||||
return new ReanimatedJSIModulePackage();
|
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Boolean isHermesEnabled() {
|
||||||
|
return BuildConfig.IS_HERMES_ENABLED;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,37 +61,9 @@ public class MainApplication extends Application implements ReactApplication {
|
||||||
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
|
I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
|
||||||
sharedI18nUtilInstance.allowRTL(getApplicationContext(), true);
|
sharedI18nUtilInstance.allowRTL(getApplicationContext(), true);
|
||||||
SoLoader.init(this, /* native exopackage */ false);
|
SoLoader.init(this, /* native exopackage */ false);
|
||||||
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
||||||
}
|
// If you opted-in for the New Architecture, we load the native entry point for this app.
|
||||||
|
DefaultNewArchitectureEntryPoint.load();
|
||||||
/**
|
}
|
||||||
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
|
|
||||||
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @param reactInstanceManager
|
|
||||||
*/
|
|
||||||
private static void initializeFlipper(
|
|
||||||
Context context, ReactInstanceManager reactInstanceManager) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
try {
|
|
||||||
/*
|
|
||||||
We use reflection here to pick up the class that initializes Flipper,
|
|
||||||
since Flipper library is not available in release mode
|
|
||||||
*/
|
|
||||||
Class<?> aClass = Class.forName("com.rndiffapp.ReactNativeFlipper");
|
|
||||||
aClass
|
|
||||||
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
|
|
||||||
.invoke(null, context, reactInstanceManager);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,33 +4,39 @@ buildscript {
|
||||||
ext {
|
ext {
|
||||||
minSdkVersion = 28
|
minSdkVersion = 28
|
||||||
supportLibVersion = "28.0.0"
|
supportLibVersion = "28.0.0"
|
||||||
buildToolsVersion = "30.0.3"
|
buildToolsVersion = "33.0.0"
|
||||||
compileSdkVersion = 30
|
compileSdkVersion = 33
|
||||||
targetSdkVersion = 30
|
targetSdkVersion = 33
|
||||||
googlePlayServicesVersion = "16.+"
|
googlePlayServicesVersion = "16.+"
|
||||||
googlePlayServicesIidVersion = "16.0.1"
|
googlePlayServicesIidVersion = "16.0.1"
|
||||||
firebaseVersion = "17.3.4"
|
firebaseVersion = "17.3.4"
|
||||||
firebaseMessagingVersion = "20.2.1"
|
firebaseMessagingVersion = "21.1.0"
|
||||||
ndkVersion = "23.0.7599858"
|
|
||||||
|
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
|
||||||
|
ndkVersion = "23.1.7779620"
|
||||||
|
kotlin_version = '1.8.0'
|
||||||
|
kotlinVersion = '1.8.0'
|
||||||
|
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath('com.android.tools.build:gradle:4.2.2')
|
classpath("com.android.tools.build:gradle:7.4.2")
|
||||||
classpath("com.bugsnag:bugsnag-android-gradle-plugin:5.+")
|
classpath("com.bugsnag:bugsnag-android-gradle-plugin:5.+")
|
||||||
classpath 'com.google.gms:google-services:4.3.14' // Google Services plugin
|
classpath 'com.google.gms:google-services:4.3.14' // Google Services plugin
|
||||||
|
classpath("com.facebook.react:react-native-gradle-plugin")
|
||||||
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
|
||||||
|
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
|
||||||
// in the individual module build.gradle files
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
|
maven {
|
||||||
|
url("$rootDir/../node_modules/detox/Detox-android")
|
||||||
|
}
|
||||||
jcenter() {
|
jcenter() {
|
||||||
content {
|
content {
|
||||||
includeModule("com.facebook.yoga", "proguard-annotations")
|
includeModule("com.facebook.yoga", "proguard-annotations")
|
||||||
|
@ -73,9 +79,8 @@ subprojects {
|
||||||
afterEvaluate {project ->
|
afterEvaluate {project ->
|
||||||
if (project.hasProperty("android")) {
|
if (project.hasProperty("android")) {
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
|
||||||
buildToolsVersion '30.0.3'
|
buildToolsVersion '30.0.3'
|
||||||
compileSdkVersion 29
|
compileSdkVersion 31
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 28
|
minSdkVersion 28
|
||||||
}
|
}
|
||||||
|
@ -83,3 +88,9 @@ subprojects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subprojects { subproject ->
|
||||||
|
if(project['name'] == 'react-native-widget-center') {
|
||||||
|
project.configurations { compile { } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
|
||||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
|
||||||
|
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
@ -24,11 +24,18 @@ android.useAndroidX=true
|
||||||
# Automatically convert third-party libraries to use AndroidX
|
# Automatically convert third-party libraries to use AndroidX
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
|
|
||||||
# added when build failed because of memory:
|
# Use this property to specify which architecture you want to build.
|
||||||
# https://stackoverflow.com/questions/56075455/expiring-daemon-because-jvm-heap-space-is-exhausted
|
# You can also override it from the CLI using
|
||||||
org.gradle.daemon=true
|
# ./gradlew <task> -PreactNativeArchitectures=x86_64
|
||||||
org.gradle.configureondemand=true
|
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
||||||
org.gradle.jvmargs=-Xmx4g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
|
||||||
|
|
||||||
# Version of flipper SDK to use with React Native
|
# Use this property to enable support to the new architecture.
|
||||||
FLIPPER_VERSION=0.127.0
|
# This will allow you to use TurboModules and the Fabric render in
|
||||||
|
# your application. You should enable this flag either if you want
|
||||||
|
# to write custom TurboModules/Fabric components OR use libraries that
|
||||||
|
# are providing them.
|
||||||
|
newArchEnabled=false
|
||||||
|
|
||||||
|
# Use this property to enable or disable the Hermes JS engine.
|
||||||
|
# If set to false, you will be using JSC instead.
|
||||||
|
hermesEnabled=true
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
|
||||||
|
|
271
android/gradlew
vendored
271
android/gradlew
vendored
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright 2015 the original author or authors.
|
# Copyright © 2015-2021 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
|
@ -17,78 +17,113 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
#
|
||||||
## Gradle start up script for UN*X
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
##
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
# Resolve links: $0 may be a link
|
||||||
PRG="$0"
|
app_path=$0
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
# Need this for daisy-chained symlinks.
|
||||||
ls=`ls -ld "$PRG"`
|
while
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
[ -h "$app_path" ]
|
||||||
PRG="$link"
|
do
|
||||||
else
|
ls=$( ls -ld "$app_path" )
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
link=${ls#*' -> '}
|
||||||
fi
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
APP_NAME="Gradle"
|
||||||
APP_BASE_NAME=`basename "$0"`
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD=maximum
|
||||||
|
|
||||||
warn () {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
die () {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
nonstop=false
|
nonstop=false
|
||||||
case "`uname`" in
|
case "$( uname )" in #(
|
||||||
CYGWIN* )
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
cygwin=true
|
Darwin* ) darwin=true ;; #(
|
||||||
;;
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
Darwin* )
|
NONSTOP* ) nonstop=true ;;
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
else
|
else
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD="java"
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
@ -105,79 +140,95 @@ location of your Java installation."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
case $MAX_FD in #(
|
||||||
if [ $? -eq 0 ] ; then
|
max*)
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
warn "Could not query maximum file descriptor limit"
|
||||||
fi
|
esac
|
||||||
ulimit -n $MAX_FD
|
case $MAX_FD in #(
|
||||||
if [ $? -ne 0 ] ; then
|
'' | soft) :;; #(
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
*)
|
||||||
fi
|
ulimit -n "$MAX_FD" ||
|
||||||
else
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=`expr $i + 1`
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
0) set -- ;;
|
|
||||||
1) set -- "$args0" ;;
|
|
||||||
2) set -- "$args0" "$args1" ;;
|
|
||||||
3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Escape application args
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
save () {
|
# * args from the command line
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
# * the main class name
|
||||||
echo " "
|
# * -classpath
|
||||||
}
|
# * -D...appname settings
|
||||||
APP_ARGS=`save "$@"`
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
|
@ -1,6 +1,6 @@
|
||||||
rootProject.name = 'BlueWallet'
|
rootProject.name = 'BlueWallet'
|
||||||
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
|
||||||
include ':app'
|
include ':app'
|
||||||
|
includeBuild('../node_modules/react-native-gradle-plugin')
|
||||||
include ':detox'
|
include ':detox'
|
||||||
project(':detox').projectDir = new File(rootProject.projectDir, '../node_modules/detox/android/detox')
|
project(':detox').projectDir = new File(rootProject.projectDir, '../node_modules/detox/android/detox')
|
|
@ -820,9 +820,15 @@ module.exports.calcEstimateFeeFromFeeHistorgam = function (numberOfBlocks, feeHi
|
||||||
|
|
||||||
module.exports.estimateFees = async function () {
|
module.exports.estimateFees = async function () {
|
||||||
let histogram;
|
let histogram;
|
||||||
|
let timeoutId;
|
||||||
try {
|
try {
|
||||||
histogram = await Promise.race([mainClient.mempool_getFeeHistogram(), new Promise(resolve => setTimeout(resolve, 29000))]);
|
histogram = await Promise.race([
|
||||||
} catch (_) {}
|
mainClient.mempool_getFeeHistogram(),
|
||||||
|
new Promise(resolve => (timeoutId = setTimeout(resolve, 15000))),
|
||||||
|
]);
|
||||||
|
} finally {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
if (!histogram) throw new Error('timeout while getting mempool_getFeeHistogram');
|
if (!histogram) throw new Error('timeout while getting mempool_getFeeHistogram');
|
||||||
|
|
||||||
|
@ -832,7 +838,7 @@ module.exports.estimateFees = async function () {
|
||||||
const _slow = await module.exports.estimateFee(144);
|
const _slow = await module.exports.estimateFee(144);
|
||||||
|
|
||||||
// calculating fast fees from mempool:
|
// calculating fast fees from mempool:
|
||||||
const fast = module.exports.calcEstimateFeeFromFeeHistorgam(1, histogram);
|
const fast = Math.max(2, module.exports.calcEstimateFeeFromFeeHistorgam(1, histogram));
|
||||||
// recalculating medium and slow fees using bitcoincore estimations only like relative weights:
|
// recalculating medium and slow fees using bitcoincore estimations only like relative weights:
|
||||||
// (minimum 1 sat, just for any case)
|
// (minimum 1 sat, just for any case)
|
||||||
const medium = Math.max(1, Math.round((fast * _medium) / _fast));
|
const medium = Math.max(1, Math.round((fast * _medium) / _fast));
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import Obscure from 'react-native-obscure';
|
|
||||||
import { BlueStorageContext } from './storage-context';
|
|
||||||
const Privacy = () => {
|
|
||||||
const { isPrivacyBlurEnabled } = useContext(BlueStorageContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Privacy.disableBlur();
|
|
||||||
}, [isPrivacyBlurEnabled]);
|
|
||||||
|
|
||||||
Privacy.enableBlur = () => {
|
|
||||||
if (!isPrivacyBlurEnabled) return;
|
|
||||||
Obscure.activateObscure();
|
|
||||||
};
|
|
||||||
|
|
||||||
Privacy.disableBlur = () => {
|
|
||||||
Obscure.deactivateObscure();
|
|
||||||
};
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
export default Privacy;
|
|
29
blue_modules/Privacy.android.tsx
Normal file
29
blue_modules/Privacy.android.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
// @ts-ignore: react-native-obscure is not in the type definition
|
||||||
|
import Obscure from 'react-native-obscure';
|
||||||
|
import { BlueStorageContext } from './storage-context';
|
||||||
|
interface PrivacyComponent extends React.FC {
|
||||||
|
enableBlur: (isPrivacyBlurEnabled: boolean) => void;
|
||||||
|
disableBlur: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Privacy: PrivacyComponent = () => {
|
||||||
|
const { isPrivacyBlurEnabled } = useContext(BlueStorageContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Obscure.deactivateObscure();
|
||||||
|
}, [isPrivacyBlurEnabled]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Privacy.enableBlur = (isPrivacyBlurEnabled: boolean) => {
|
||||||
|
if (!isPrivacyBlurEnabled) return;
|
||||||
|
Obscure.activateObscure();
|
||||||
|
};
|
||||||
|
|
||||||
|
Privacy.disableBlur = () => {
|
||||||
|
Obscure.deactivateObscure();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Privacy;
|
|
@ -1,22 +0,0 @@
|
||||||
import { useContext, useEffect } from 'react';
|
|
||||||
import { enabled } from 'react-native-privacy-snapshot';
|
|
||||||
import { BlueStorageContext } from './storage-context';
|
|
||||||
const Privacy = () => {
|
|
||||||
const { isPrivacyBlurEnabled } = useContext(BlueStorageContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
Privacy.disableBlur();
|
|
||||||
}, [isPrivacyBlurEnabled]);
|
|
||||||
|
|
||||||
Privacy.enableBlur = () => {
|
|
||||||
if (!isPrivacyBlurEnabled) return;
|
|
||||||
enabled(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
Privacy.disableBlur = () => {
|
|
||||||
enabled(false);
|
|
||||||
};
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Privacy;
|
|
30
blue_modules/Privacy.ios.tsx
Normal file
30
blue_modules/Privacy.ios.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { useContext, useEffect } from 'react';
|
||||||
|
// @ts-ignore: react-native-obscure is not in the type definition
|
||||||
|
import { enabled } from 'react-native-privacy-snapshot';
|
||||||
|
import { BlueStorageContext } from './storage-context';
|
||||||
|
|
||||||
|
interface PrivacyComponent extends React.FC {
|
||||||
|
enableBlur: (isPrivacyBlurEnabled: boolean) => void;
|
||||||
|
disableBlur: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Privacy: PrivacyComponent = () => {
|
||||||
|
const { isPrivacyBlurEnabled } = useContext(BlueStorageContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Privacy.disableBlur();
|
||||||
|
}, [isPrivacyBlurEnabled]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Privacy.enableBlur = (isPrivacyBlurEnabled: boolean) => {
|
||||||
|
if (!isPrivacyBlurEnabled) return;
|
||||||
|
enabled(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
Privacy.disableBlur = () => {
|
||||||
|
enabled(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Privacy;
|
|
@ -1,5 +0,0 @@
|
||||||
export default class Privacy {
|
|
||||||
static enableBlur() {}
|
|
||||||
|
|
||||||
static disableBlur() {}
|
|
||||||
}
|
|
21
blue_modules/Privacy.tsx
Normal file
21
blue_modules/Privacy.tsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface PrivacyComponent extends React.FC {
|
||||||
|
enableBlur: () => void;
|
||||||
|
disableBlur: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Privacy: PrivacyComponent = () => {
|
||||||
|
// Define Privacy's behavior
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
Privacy.enableBlur = () => {
|
||||||
|
// Define the enableBlur behavior
|
||||||
|
};
|
||||||
|
|
||||||
|
Privacy.disableBlur = () => {
|
||||||
|
// Define the disableBlur behavior
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Privacy;
|
|
@ -42,7 +42,6 @@
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"react-native": {
|
"react-native": {
|
||||||
"path": "path-browserify",
|
"path": "path-browserify",
|
||||||
"fs": "react-native-level-fs",
|
|
||||||
"_stream_transform": "readable-stream/transform",
|
"_stream_transform": "readable-stream/transform",
|
||||||
"_stream_readable": "readable-stream/readable",
|
"_stream_readable": "readable-stream/readable",
|
||||||
"_stream_writable": "readable-stream/writable",
|
"_stream_writable": "readable-stream/writable",
|
||||||
|
@ -52,7 +51,6 @@
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"path": "path-browserify",
|
"path": "path-browserify",
|
||||||
"fs": "react-native-level-fs",
|
|
||||||
"_stream_transform": "readable-stream/transform",
|
"_stream_transform": "readable-stream/transform",
|
||||||
"_stream_readable": "readable-stream/readable",
|
"_stream_readable": "readable-stream/readable",
|
||||||
"_stream_writable": "readable-stream/writable",
|
"_stream_writable": "readable-stream/writable",
|
||||||
|
|
|
@ -59,7 +59,6 @@
|
||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"react-native": {
|
"react-native": {
|
||||||
"path": "path-browserify",
|
"path": "path-browserify",
|
||||||
"fs": "react-native-level-fs",
|
|
||||||
"_stream_transform": "readable-stream/transform",
|
"_stream_transform": "readable-stream/transform",
|
||||||
"_stream_readable": "readable-stream/readable",
|
"_stream_readable": "readable-stream/readable",
|
||||||
"_stream_writable": "readable-stream/writable",
|
"_stream_writable": "readable-stream/writable",
|
||||||
|
@ -69,7 +68,6 @@
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"path": "path-browserify",
|
"path": "path-browserify",
|
||||||
"fs": "react-native-level-fs",
|
|
||||||
"_stream_transform": "readable-stream/transform",
|
"_stream_transform": "readable-stream/transform",
|
||||||
"_stream_readable": "readable-stream/readable",
|
"_stream_readable": "readable-stream/readable",
|
||||||
"_stream_writable": "readable-stream/writable",
|
"_stream_writable": "readable-stream/writable",
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { useAsyncStorage } from '@react-native-async-storage/async-storage';
|
|
||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
|
||||||
|
|
||||||
function BlueClipboard() {
|
|
||||||
BlueClipboard.STORAGE_KEY = 'ClipboardReadAllowed';
|
|
||||||
const isClipboardAccessAllowed = useAsyncStorage(BlueClipboard.STORAGE_KEY).getItem;
|
|
||||||
const setIsClipboardAccessAllowed = useAsyncStorage(BlueClipboard.STORAGE_KEY).setItem;
|
|
||||||
|
|
||||||
BlueClipboard.isReadClipboardAllowed = async () => {
|
|
||||||
try {
|
|
||||||
const clipboardAccessAllowed = await isClipboardAccessAllowed();
|
|
||||||
if (clipboardAccessAllowed === null) {
|
|
||||||
await setIsClipboardAccessAllowed(JSON.stringify(true));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return !!JSON.parse(clipboardAccessAllowed);
|
|
||||||
} catch {
|
|
||||||
await setIsClipboardAccessAllowed(JSON.stringify(true));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BlueClipboard.setReadClipboardAllowed = value => {
|
|
||||||
setIsClipboardAccessAllowed(JSON.stringify(!!value));
|
|
||||||
};
|
|
||||||
|
|
||||||
BlueClipboard.getClipboardContent = async () => {
|
|
||||||
const isAllowed = await BlueClipboard.isReadClipboardAllowed();
|
|
||||||
if (isAllowed) {
|
|
||||||
return Clipboard.getString();
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
BlueClipboard.default = new BlueClipboard();
|
|
||||||
export default BlueClipboard;
|
|
42
blue_modules/clipboard.ts
Normal file
42
blue_modules/clipboard.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { useAsyncStorage } from '@react-native-async-storage/async-storage';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
|
|
||||||
|
const BlueClipboard = () => {
|
||||||
|
const STORAGE_KEY = 'ClipboardReadAllowed';
|
||||||
|
const { getItem, setItem } = useAsyncStorage(STORAGE_KEY);
|
||||||
|
|
||||||
|
const isReadClipboardAllowed = async () => {
|
||||||
|
try {
|
||||||
|
const clipboardAccessAllowed = await getItem();
|
||||||
|
if (clipboardAccessAllowed === null) {
|
||||||
|
await setItem(JSON.stringify(true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return !!JSON.parse(clipboardAccessAllowed);
|
||||||
|
} catch {
|
||||||
|
await setItem(JSON.stringify(true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setReadClipboardAllowed = (value: boolean) => {
|
||||||
|
setItem(JSON.stringify(!!value));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getClipboardContent = async () => {
|
||||||
|
const isAllowed = await isReadClipboardAllowed();
|
||||||
|
if (isAllowed) {
|
||||||
|
return Clipboard.getString();
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isReadClipboardAllowed,
|
||||||
|
setReadClipboardAllowed,
|
||||||
|
getClipboardContent,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BlueClipboard;
|
|
@ -53,6 +53,9 @@ async function _restoreSavedPreferredFiatCurrencyFromStorage() {
|
||||||
if (preferredFiatCurrency === null) {
|
if (preferredFiatCurrency === null) {
|
||||||
throw Error('No Preferred Fiat selected');
|
throw Error('No Preferred Fiat selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferredFiatCurrency = FiatUnit[preferredFiatCurrency.endPointKey] || preferredFiatCurrency;
|
||||||
|
// ^^^ in case configuration in json file changed (and is different from what we stored) we reload it
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
const deviceCurrencies = RNLocalize.getCurrencies();
|
const deviceCurrencies = RNLocalize.getCurrencies();
|
||||||
if (Object.keys(FiatUnit).some(unit => unit === deviceCurrencies[0])) {
|
if (Object.keys(FiatUnit).some(unit => unit === deviceCurrencies[0])) {
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
||||||
import { Platform } from 'react-native';
|
|
||||||
import { getSystemName, isTablet, getDeviceType } from 'react-native-device-info';
|
|
||||||
|
|
||||||
const isMacCatalina = getSystemName() === 'Mac OS X';
|
|
||||||
const isDesktop = getDeviceType() === 'Desktop';
|
|
||||||
const getIsTorCapable = () => {
|
|
||||||
let capable = true;
|
|
||||||
if (Platform.OS === 'android' && Platform.Version < 26) {
|
|
||||||
capable = false;
|
|
||||||
} else if (isDesktop) {
|
|
||||||
capable = false;
|
|
||||||
}
|
|
||||||
return capable;
|
|
||||||
};
|
|
||||||
|
|
||||||
const IS_TOR_DAEMON_DISABLED = 'is_tor_daemon_disabled';
|
|
||||||
export async function setIsTorDaemonDisabled(disabled = true) {
|
|
||||||
return AsyncStorage.setItem(IS_TOR_DAEMON_DISABLED, disabled ? '1' : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function isTorDaemonDisabled() {
|
|
||||||
let isTorDaemonDisabled;
|
|
||||||
try {
|
|
||||||
const savedValue = await AsyncStorage.getItem(IS_TOR_DAEMON_DISABLED);
|
|
||||||
if (savedValue === null) {
|
|
||||||
isTorDaemonDisabled = false;
|
|
||||||
} else {
|
|
||||||
isTorDaemonDisabled = savedValue;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
isTorDaemonDisabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!isTorDaemonDisabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const isHandset = getDeviceType() === 'Handset';
|
|
||||||
export const isTorCapable = getIsTorCapable();
|
|
||||||
export { isMacCatalina, isDesktop, isTablet };
|
|
41
blue_modules/environment.ts
Normal file
41
blue_modules/environment.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
import { isTablet, getDeviceType } from 'react-native-device-info';
|
||||||
|
|
||||||
|
const isDesktop: boolean = getDeviceType() === 'Desktop';
|
||||||
|
|
||||||
|
const getIsTorCapable = (): boolean => {
|
||||||
|
let capable = true;
|
||||||
|
if (Platform.OS === 'android' && Platform.Version < 26) {
|
||||||
|
capable = false;
|
||||||
|
} else if (isDesktop) {
|
||||||
|
capable = false;
|
||||||
|
}
|
||||||
|
return capable;
|
||||||
|
};
|
||||||
|
|
||||||
|
const IS_TOR_DAEMON_DISABLED: string = 'is_tor_daemon_disabled';
|
||||||
|
|
||||||
|
export async function setIsTorDaemonDisabled(disabled: boolean = true): Promise<void> {
|
||||||
|
return AsyncStorage.setItem(IS_TOR_DAEMON_DISABLED, disabled ? '1' : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function isTorDaemonDisabled(): Promise<boolean> {
|
||||||
|
let isTorDaemonDisabled: boolean;
|
||||||
|
try {
|
||||||
|
const savedValue = await AsyncStorage.getItem(IS_TOR_DAEMON_DISABLED);
|
||||||
|
if (savedValue === null) {
|
||||||
|
isTorDaemonDisabled = false;
|
||||||
|
} else {
|
||||||
|
isTorDaemonDisabled = savedValue === '1';
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
isTorDaemonDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isTorDaemonDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const isHandset: boolean = getDeviceType() === 'Handset';
|
||||||
|
export const isTorCapable: boolean = getIsTorCapable();
|
||||||
|
export { isDesktop, isTablet };
|
|
@ -6,8 +6,6 @@ import DocumentPicker from 'react-native-document-picker';
|
||||||
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
|
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
|
||||||
import { presentCameraNotAuthorizedAlert } from '../class/camera';
|
import { presentCameraNotAuthorizedAlert } from '../class/camera';
|
||||||
import { isDesktop } from '../blue_modules/environment';
|
import { isDesktop } from '../blue_modules/environment';
|
||||||
import ActionSheet from '../screen/ActionSheet';
|
|
||||||
import BlueClipboard from './clipboard';
|
|
||||||
import alert from '../components/Alert';
|
import alert from '../components/Alert';
|
||||||
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
|
||||||
|
|
||||||
|
@ -205,43 +203,8 @@ const showFilePickerAndReadFile = async function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Intended for macOS Catalina. Not for long press shortcut
|
|
||||||
const showActionSheet = async props => {
|
|
||||||
const isClipboardEmpty = (await BlueClipboard.getClipboardContent()).trim().length === 0;
|
|
||||||
let copyFromClipboardIndex;
|
|
||||||
const options = [loc._.cancel, loc.wallets.take_photo, loc.wallets.list_long_choose];
|
|
||||||
if (!isClipboardEmpty) {
|
|
||||||
options.push(loc.wallets.list_long_clipboard);
|
|
||||||
copyFromClipboardIndex = options.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
options.push(loc.wallets.import_file);
|
|
||||||
const importFileButtonIndex = options.length - 1;
|
|
||||||
|
|
||||||
return new Promise(resolve =>
|
|
||||||
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0, anchor: props.anchor }, async buttonIndex => {
|
|
||||||
if (buttonIndex === 1) {
|
|
||||||
takePhotoWithImagePickerAndReadPhoto().then(resolve);
|
|
||||||
} else if (buttonIndex === 2) {
|
|
||||||
showImagePickerAndReadImage()
|
|
||||||
.then(resolve)
|
|
||||||
.catch(error => alert(error.message));
|
|
||||||
} else if (buttonIndex === copyFromClipboardIndex) {
|
|
||||||
const clipboard = await BlueClipboard.getClipboardContent();
|
|
||||||
resolve(clipboard);
|
|
||||||
} else if (importFileButtonIndex) {
|
|
||||||
const { data } = await showFilePickerAndReadFile();
|
|
||||||
if (data) {
|
|
||||||
resolve(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports.writeFileAndExport = writeFileAndExport;
|
module.exports.writeFileAndExport = writeFileAndExport;
|
||||||
module.exports.openSignedTransaction = openSignedTransaction;
|
module.exports.openSignedTransaction = openSignedTransaction;
|
||||||
module.exports.showFilePickerAndReadFile = showFilePickerAndReadFile;
|
module.exports.showFilePickerAndReadFile = showFilePickerAndReadFile;
|
||||||
module.exports.showImagePickerAndReadImage = showImagePickerAndReadImage;
|
module.exports.showImagePickerAndReadImage = showImagePickerAndReadImage;
|
||||||
module.exports.takePhotoWithImagePickerAndReadPhoto = takePhotoWithImagePickerAndReadPhoto;
|
module.exports.takePhotoWithImagePickerAndReadPhoto = takePhotoWithImagePickerAndReadPhoto;
|
||||||
module.exports.showActionSheet = showActionSheet;
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ function Notifications(props) {
|
||||||
|
|
||||||
// if user is staring at the app when he receives the notification we process it instantly
|
// if user is staring at the app when he receives the notification we process it instantly
|
||||||
// so app refetches related wallet
|
// so app refetches related wallet
|
||||||
if (payload.foreground) props.onProcessNotifications();
|
if (payload.foreground) props.onProcessNotifications(); // eslint-disable-line react/prop-types
|
||||||
},
|
},
|
||||||
|
|
||||||
// (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
|
// (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { useAsyncStorage } from '@react-native-async-storage/async-storage';
|
||||||
import { FiatUnit } from '../models/fiatUnit';
|
import { FiatUnit } from '../models/fiatUnit';
|
||||||
import Notifications from '../blue_modules/notifications';
|
import Notifications from '../blue_modules/notifications';
|
||||||
import loc, { STORAGE_KEY as LOC_STORAGE_KEY } from '../loc';
|
import loc, { STORAGE_KEY as LOC_STORAGE_KEY } from '../loc';
|
||||||
import { LegacyWallet } from '../class';
|
import { LegacyWallet, WatchOnlyWallet } from '../class';
|
||||||
import { isTorDaemonDisabled, setIsTorDaemonDisabled } from './environment';
|
import { isTorDaemonDisabled, setIsTorDaemonDisabled } from './environment';
|
||||||
import alert from '../components/Alert';
|
import alert from '../components/Alert';
|
||||||
const BlueApp = require('../BlueApp');
|
const BlueApp = require('../BlueApp');
|
||||||
|
@ -120,6 +120,10 @@ export const BlueStorageProvider = ({ children }) => {
|
||||||
setWalletTransactionUpdateStatus(WalletTransactionsStatus.ALL);
|
setWalletTransactionUpdateStatus(WalletTransactionsStatus.ALL);
|
||||||
}
|
}
|
||||||
await BlueElectrum.waitTillConnected();
|
await BlueElectrum.waitTillConnected();
|
||||||
|
const paymentCodesStart = Date.now();
|
||||||
|
await fetchSenderPaymentCodes(lastSnappedTo);
|
||||||
|
const paymentCodesEnd = Date.now();
|
||||||
|
console.log('fetch payment codes took', (paymentCodesEnd - paymentCodesStart) / 1000, 'sec');
|
||||||
const balanceStart = +new Date();
|
const balanceStart = +new Date();
|
||||||
await fetchWalletBalances(lastSnappedTo);
|
await fetchWalletBalances(lastSnappedTo);
|
||||||
const balanceEnd = +new Date();
|
const balanceEnd = +new Date();
|
||||||
|
@ -190,7 +194,7 @@ export const BlueStorageProvider = ({ children }) => {
|
||||||
addWallet(w);
|
addWallet(w);
|
||||||
await saveToDisk();
|
await saveToDisk();
|
||||||
A(A.ENUM.CREATED_WALLET);
|
A(A.ENUM.CREATED_WALLET);
|
||||||
Alert.alert('', loc.wallets.import_success);
|
Alert.alert('', w.type === WatchOnlyWallet.type ? loc.wallets.import_success_watchonly : loc.wallets.import_success);
|
||||||
Notifications.majorTomToGroundControl(w.getAllExternalAddresses(), [], []);
|
Notifications.majorTomToGroundControl(w.getAllExternalAddresses(), [], []);
|
||||||
// start balance fetching at the background
|
// start balance fetching at the background
|
||||||
await w.fetchBalance();
|
await w.fetchBalance();
|
||||||
|
@ -199,8 +203,9 @@ export const BlueStorageProvider = ({ children }) => {
|
||||||
|
|
||||||
let txMetadata = BlueApp.tx_metadata || {};
|
let txMetadata = BlueApp.tx_metadata || {};
|
||||||
const getTransactions = BlueApp.getTransactions;
|
const getTransactions = BlueApp.getTransactions;
|
||||||
const isAdancedModeEnabled = BlueApp.isAdancedModeEnabled;
|
const isAdvancedModeEnabled = BlueApp.isAdvancedModeEnabled;
|
||||||
|
|
||||||
|
const fetchSenderPaymentCodes = BlueApp.fetchSenderPaymentCodes;
|
||||||
const fetchWalletBalances = BlueApp.fetchWalletBalances;
|
const fetchWalletBalances = BlueApp.fetchWalletBalances;
|
||||||
const fetchWalletTransactions = BlueApp.fetchWalletTransactions;
|
const fetchWalletTransactions = BlueApp.fetchWalletTransactions;
|
||||||
const getBalance = BlueApp.getBalance;
|
const getBalance = BlueApp.getBalance;
|
||||||
|
@ -214,7 +219,7 @@ export const BlueStorageProvider = ({ children }) => {
|
||||||
const decryptStorage = BlueApp.decryptStorage;
|
const decryptStorage = BlueApp.decryptStorage;
|
||||||
const isPasswordInUse = BlueApp.isPasswordInUse;
|
const isPasswordInUse = BlueApp.isPasswordInUse;
|
||||||
const cachedPassword = BlueApp.cachedPassword;
|
const cachedPassword = BlueApp.cachedPassword;
|
||||||
const setIsAdancedModeEnabled = BlueApp.setIsAdancedModeEnabled;
|
const setIsAdvancedModeEnabled = BlueApp.setIsAdvancedModeEnabled;
|
||||||
const getHodlHodlSignatureKey = BlueApp.getHodlHodlSignatureKey;
|
const getHodlHodlSignatureKey = BlueApp.getHodlHodlSignatureKey;
|
||||||
const addHodlHodlContract = BlueApp.addHodlHodlContract;
|
const addHodlHodlContract = BlueApp.addHodlHodlContract;
|
||||||
const getHodlHodlContracts = BlueApp.getHodlHodlContracts;
|
const getHodlHodlContracts = BlueApp.getHodlHodlContracts;
|
||||||
|
@ -239,7 +244,7 @@ export const BlueStorageProvider = ({ children }) => {
|
||||||
setItem,
|
setItem,
|
||||||
getItem,
|
getItem,
|
||||||
getHodlHodlContracts,
|
getHodlHodlContracts,
|
||||||
isAdancedModeEnabled,
|
isAdvancedModeEnabled,
|
||||||
fetchWalletBalances,
|
fetchWalletBalances,
|
||||||
fetchWalletTransactions,
|
fetchWalletTransactions,
|
||||||
fetchAndSaveWalletTransactions,
|
fetchAndSaveWalletTransactions,
|
||||||
|
@ -260,7 +265,7 @@ export const BlueStorageProvider = ({ children }) => {
|
||||||
getHodlHodlApiKey,
|
getHodlHodlApiKey,
|
||||||
decryptStorage,
|
decryptStorage,
|
||||||
isPasswordInUse,
|
isPasswordInUse,
|
||||||
setIsAdancedModeEnabled,
|
setIsAdvancedModeEnabled,
|
||||||
setPreferredFiatCurrency,
|
setPreferredFiatCurrency,
|
||||||
preferredFiatCurrency,
|
preferredFiatCurrency,
|
||||||
setLanguage,
|
setLanguage,
|
||||||
|
|
|
@ -67,7 +67,7 @@ export class AppStorage {
|
||||||
*/
|
*/
|
||||||
setItem = (key, value) => {
|
setItem = (key, value) => {
|
||||||
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {
|
||||||
return RNSecureKeyStore.set(key, value, { accessible: ACCESSIBLE.WHEN_UNLOCKED });
|
return RNSecureKeyStore.set(key, value, { accessible: ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY });
|
||||||
} else {
|
} else {
|
||||||
return AsyncStorage.setItem(key, value);
|
return AsyncStorage.setItem(key, value);
|
||||||
}
|
}
|
||||||
|
@ -289,8 +289,8 @@ export class AppStorage {
|
||||||
realmkeyValue.create(
|
realmkeyValue.create(
|
||||||
'KeyValue',
|
'KeyValue',
|
||||||
{
|
{
|
||||||
key: key,
|
key,
|
||||||
value: value,
|
value,
|
||||||
},
|
},
|
||||||
Realm.UpdateMode.Modified,
|
Realm.UpdateMode.Modified,
|
||||||
);
|
);
|
||||||
|
@ -602,6 +602,11 @@ export class AppStorage {
|
||||||
keyCloned._hdWalletInstance._txs_by_external_index = {};
|
keyCloned._hdWalletInstance._txs_by_external_index = {};
|
||||||
keyCloned._hdWalletInstance._txs_by_internal_index = {};
|
keyCloned._hdWalletInstance._txs_by_internal_index = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyCloned._bip47_instance) {
|
||||||
|
delete keyCloned._bip47_instance; // since it wont be restored into a proper class instance
|
||||||
|
}
|
||||||
|
|
||||||
walletsToSave.push(JSON.stringify({ ...keyCloned, type: keyCloned.type }));
|
walletsToSave.push(JSON.stringify({ ...keyCloned, type: keyCloned.type }));
|
||||||
}
|
}
|
||||||
if (realm) realm.close();
|
if (realm) realm.close();
|
||||||
|
@ -682,6 +687,7 @@ export class AppStorage {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const wallet of this.wallets) {
|
for (const wallet of this.wallets) {
|
||||||
|
console.log('fetching balance for', wallet.getLabel());
|
||||||
await wallet.fetchBalance();
|
await wallet.fetchBalance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -725,6 +731,27 @@ export class AppStorage {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fetchSenderPaymentCodes = async index => {
|
||||||
|
console.log('fetchSenderPaymentCodes for wallet#', typeof index === 'undefined' ? '(all)' : index);
|
||||||
|
if (index || index === 0) {
|
||||||
|
try {
|
||||||
|
if (!(this.wallets[index].allowBIP47() && this.wallets[index].isBIP47Enabled())) return;
|
||||||
|
await this.wallets[index].fetchBIP47SenderPaymentCodes();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch sender payment codes for wallet', index, error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const wallet of this.wallets) {
|
||||||
|
try {
|
||||||
|
if (!(wallet.allowBIP47() && wallet.isBIP47Enabled())) continue;
|
||||||
|
await wallet.fetchBIP47SenderPaymentCodes();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch sender payment codes for wallet', wallet.label, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @returns {Array.<AbstractWallet>}
|
* @returns {Array.<AbstractWallet>}
|
||||||
|
@ -789,14 +816,14 @@ export class AppStorage {
|
||||||
return finalBalance;
|
return finalBalance;
|
||||||
};
|
};
|
||||||
|
|
||||||
isAdancedModeEnabled = async () => {
|
isAdvancedModeEnabled = async () => {
|
||||||
try {
|
try {
|
||||||
return !!(await AsyncStorage.getItem(AppStorage.ADVANCED_MODE_ENABLED));
|
return !!(await AsyncStorage.getItem(AppStorage.ADVANCED_MODE_ENABLED));
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
setIsAdancedModeEnabled = async value => {
|
setIsAdvancedModeEnabled = async value => {
|
||||||
await AsyncStorage.setItem(AppStorage.ADVANCED_MODE_ENABLED, value ? '1' : '');
|
await AsyncStorage.setItem(AppStorage.ADVANCED_MODE_ENABLED, value ? '1' : '');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default class Azteco {
|
||||||
}
|
}
|
||||||
|
|
||||||
static getParamsFromUrl(u) {
|
static getParamsFromUrl(u) {
|
||||||
const urlObject = url.parse(u, true); // eslint-disable-line node/no-deprecated-api
|
const urlObject = url.parse(u, true); // eslint-disable-line n/no-deprecated-api
|
||||||
return {
|
return {
|
||||||
uri: u,
|
uri: u,
|
||||||
c1: urlObject.query.c1,
|
c1: urlObject.query.c1,
|
||||||
|
|
|
@ -184,7 +184,7 @@ class DeeplinkSchemaMatch {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
const urlObject = url.parse(event.url, true); // eslint-disable-line node/no-deprecated-api
|
const urlObject = url.parse(event.url, true); // eslint-disable-line n/no-deprecated-api
|
||||||
(async () => {
|
(async () => {
|
||||||
if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') {
|
if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') {
|
||||||
switch (urlObject.host) {
|
switch (urlObject.host) {
|
||||||
|
@ -390,7 +390,8 @@ class DeeplinkSchemaMatch {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (value.startsWith('lightning')) {
|
} else if (value.startsWith('lightning')) {
|
||||||
lndInvoice = `lightning:${txInfo[index + 1]}`;
|
const lnpart = txInfo[index + 1].split('&').find(el => el.toLowerCase().startsWith('ln'));
|
||||||
|
lndInvoice = `lightning:${lnpart}`;
|
||||||
if (!this.isLightningInvoice(lndInvoice)) {
|
if (!this.isLightningInvoice(lndInvoice)) {
|
||||||
lndInvoice = false;
|
lndInvoice = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -168,7 +168,7 @@ export class HDSegwitBech32Transaction {
|
||||||
value = new BigNumber(value).multipliedBy(100000000).toNumber();
|
value = new BigNumber(value).multipliedBy(100000000).toNumber();
|
||||||
wentIn += value;
|
wentIn += value;
|
||||||
const address = SegwitBech32Wallet.witnessToAddress(inp.witness[inp.witness.length - 1]);
|
const address = SegwitBech32Wallet.witnessToAddress(inp.witness[inp.witness.length - 1]);
|
||||||
utxos.push({ vout: inp.index, value: value, txId: reversedHash, address: address });
|
utxos.push({ vout: inp.index, value, txId: reversedHash, address });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ export class HDSegwitBech32Transaction {
|
||||||
changeAmount += value;
|
changeAmount += value;
|
||||||
} else {
|
} else {
|
||||||
// this is target
|
// this is target
|
||||||
targets.push({ value: value, address: address });
|
targets.push({ value, address });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,9 +205,9 @@ export class HDSegwitBech32Transaction {
|
||||||
if (this._wallet.weOwnAddress(address)) {
|
if (this._wallet.weOwnAddress(address)) {
|
||||||
unconfirmedUtxos.push({
|
unconfirmedUtxos.push({
|
||||||
vout: outp.n,
|
vout: outp.n,
|
||||||
value: value,
|
value,
|
||||||
txId: this._txid || this._txDecoded.getId(),
|
txId: this._txid || this._txDecoded.getId(),
|
||||||
address: address,
|
address,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { bech32 } from 'bech32';
|
import { bech32 } from 'bech32';
|
||||||
import bolt11 from 'bolt11';
|
import bolt11 from 'bolt11';
|
||||||
import { isTorDaemonDisabled } from '../blue_modules/environment';
|
import { isTorDaemonDisabled } from '../blue_modules/environment';
|
||||||
import { parse } from 'url'; // eslint-disable-line node/no-deprecated-api
|
import { parse } from 'url'; // eslint-disable-line n/no-deprecated-api
|
||||||
import { createHmac } from 'crypto';
|
import { createHmac } from 'crypto';
|
||||||
import secp256k1 from 'secp256k1';
|
import secp256k1 from 'secp256k1';
|
||||||
const CryptoJS = require('crypto-js');
|
const CryptoJS = require('crypto-js');
|
||||||
|
@ -289,11 +289,23 @@ export default class Lnurl {
|
||||||
return this?._lnurlPayServicePayload?.commentAllowed ? parseInt(this._lnurlPayServicePayload.commentAllowed) : false;
|
return this?._lnurlPayServicePayload?.commentAllowed ? parseInt(this._lnurlPayServicePayload.commentAllowed) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMin() {
|
||||||
|
return this?._lnurlPayServicePayload?.min ? parseInt(this._lnurlPayServicePayload.min) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMax() {
|
||||||
|
return this?._lnurlPayServicePayload?.max ? parseInt(this._lnurlPayServicePayload.max) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAmount() {
|
||||||
|
return this.getMin();
|
||||||
|
}
|
||||||
|
|
||||||
authenticate(secret) {
|
authenticate(secret) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!this._lnurl) throw new Error('this._lnurl is not set');
|
if (!this._lnurl) throw new Error('this._lnurl is not set');
|
||||||
|
|
||||||
const url = parse(Lnurl.getUrlFromLnurl(this._lnurl), true); // eslint-disable-line node/no-deprecated-api
|
const url = parse(Lnurl.getUrlFromLnurl(this._lnurl), true);
|
||||||
|
|
||||||
const hmac = createHmac('sha256', secret);
|
const hmac = createHmac('sha256', secret);
|
||||||
hmac.on('readable', async () => {
|
hmac.on('readable', async () => {
|
||||||
|
|
|
@ -140,9 +140,9 @@ export class MultisigCosigner {
|
||||||
|
|
||||||
static exportToJson(xfp, xpub, path) {
|
static exportToJson(xfp, xpub, path) {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
xfp: xfp,
|
xfp,
|
||||||
xpub: xpub,
|
xpub,
|
||||||
path: path,
|
path,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal
|
||||||
wallet.setDerivationPath(path);
|
wallet.setDerivationPath(path);
|
||||||
yield { progress: `bip39 ${i.script_type} ${path}` };
|
yield { progress: `bip39 ${i.script_type} ${path}` };
|
||||||
if (await wallet.wasEverUsed()) {
|
if (await wallet.wasEverUsed()) {
|
||||||
yield { wallet: wallet };
|
yield { wallet };
|
||||||
walletFound = true;
|
walletFound = true;
|
||||||
} else {
|
} else {
|
||||||
break; // don't check second account if first one is empty
|
break; // don't check second account if first one is empty
|
||||||
|
|
|
@ -4,22 +4,26 @@ import BigNumber from 'bignumber.js';
|
||||||
import b58 from 'bs58check';
|
import b58 from 'bs58check';
|
||||||
import BIP32Factory, { BIP32Interface } from 'bip32';
|
import BIP32Factory, { BIP32Interface } from 'bip32';
|
||||||
|
|
||||||
import { randomBytes } from '../rng';
|
|
||||||
import { AbstractHDWallet } from './abstract-hd-wallet';
|
|
||||||
import { ECPairFactory } from 'ecpair';
|
|
||||||
import { CreateTransactionResult, CreateTransactionUtxo, Transaction, Utxo } from './types';
|
|
||||||
import { ElectrumHistory } from '../../blue_modules/BlueElectrum';
|
|
||||||
import type BlueElectrumNs from '../../blue_modules/BlueElectrum';
|
|
||||||
import { ECPairInterface } from 'ecpair/src/ecpair';
|
import { ECPairInterface } from 'ecpair/src/ecpair';
|
||||||
import { Psbt, Transaction as BTransaction } from 'bitcoinjs-lib';
|
import { Psbt, Transaction as BTransaction } from 'bitcoinjs-lib';
|
||||||
import { CoinSelectReturnInput, CoinSelectTarget } from 'coinselect';
|
import { CoinSelectReturnInput, CoinSelectTarget } from 'coinselect';
|
||||||
import ecc from '../../blue_modules/noble_ecc';
|
import ecc from '../../blue_modules/noble_ecc';
|
||||||
|
|
||||||
|
import BIP47Factory, { BIP47Interface } from '@spsina/bip47';
|
||||||
|
import { ECPairFactory } from 'ecpair';
|
||||||
|
|
||||||
|
import { randomBytes } from '../rng';
|
||||||
|
import { AbstractHDWallet } from './abstract-hd-wallet';
|
||||||
|
import { CreateTransactionResult, CreateTransactionUtxo, Transaction, Utxo } from './types';
|
||||||
|
import { ElectrumHistory } from '../../blue_modules/BlueElectrum';
|
||||||
|
import type BlueElectrumNs from '../../blue_modules/BlueElectrum';
|
||||||
|
|
||||||
const ECPair = ECPairFactory(ecc);
|
const ECPair = ECPairFactory(ecc);
|
||||||
const bitcoin = require('bitcoinjs-lib');
|
const bitcoin = require('bitcoinjs-lib');
|
||||||
const BlueElectrum: typeof BlueElectrumNs = require('../../blue_modules/BlueElectrum');
|
const BlueElectrum: typeof BlueElectrumNs = require('../../blue_modules/BlueElectrum');
|
||||||
const reverse = require('buffer-reverse');
|
const reverse = require('buffer-reverse');
|
||||||
const bip32 = BIP32Factory(ecc);
|
const bip32 = BIP32Factory(ecc);
|
||||||
|
const bip47 = BIP47Factory(ecc);
|
||||||
|
|
||||||
type BalanceByIndex = {
|
type BalanceByIndex = {
|
||||||
c: number;
|
c: number;
|
||||||
|
@ -45,6 +49,16 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
|
|
||||||
_utxo: any[];
|
_utxo: any[];
|
||||||
|
|
||||||
|
// BIP47
|
||||||
|
_enable_BIP47: boolean;
|
||||||
|
_payment_code: string;
|
||||||
|
_sender_payment_codes: string[];
|
||||||
|
_addresses_by_payment_code: Record<string, string[]>;
|
||||||
|
_next_free_payment_code_address_index: Record<string, number>;
|
||||||
|
_txs_by_payment_code_index: Record<string, Transaction[][]>;
|
||||||
|
_balances_by_payment_code_index: Record<string, BalanceByIndex>;
|
||||||
|
_bip47_instance?: BIP47Interface;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this._balances_by_external_index = {}; // 0 => { c: 0, u: 0 } // confirmed/unconfirmed
|
this._balances_by_external_index = {}; // 0 => { c: 0, u: 0 } // confirmed/unconfirmed
|
||||||
|
@ -54,6 +68,15 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
this._txs_by_internal_index = {};
|
this._txs_by_internal_index = {};
|
||||||
|
|
||||||
this._utxo = [];
|
this._utxo = [];
|
||||||
|
|
||||||
|
// BIP47
|
||||||
|
this._enable_BIP47 = false;
|
||||||
|
this._payment_code = '';
|
||||||
|
this._sender_payment_codes = [];
|
||||||
|
this._next_free_payment_code_address_index = {};
|
||||||
|
this._txs_by_payment_code_index = {};
|
||||||
|
this._balances_by_payment_code_index = {};
|
||||||
|
this._addresses_by_payment_code = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,6 +90,9 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (const bal of Object.values(this._balances_by_internal_index)) {
|
for (const bal of Object.values(this._balances_by_internal_index)) {
|
||||||
ret += bal.c;
|
ret += bal.c;
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
ret += this._getBalancesByPaymentCodeIndex(pc).c;
|
||||||
|
}
|
||||||
return ret + (this.getUnconfirmedBalance() < 0 ? this.getUnconfirmedBalance() : 0);
|
return ret + (this.getUnconfirmedBalance() < 0 ? this.getUnconfirmedBalance() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +108,9 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (const bal of Object.values(this._balances_by_internal_index)) {
|
for (const bal of Object.values(this._balances_by_internal_index)) {
|
||||||
ret += bal.u;
|
ret += bal.u;
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
ret += this._getBalancesByPaymentCodeIndex(pc).u;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +150,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
return child.toWIF();
|
return child.toWIF();
|
||||||
}
|
}
|
||||||
|
|
||||||
_getNodeAddressByIndex(node: number, index: number) {
|
_getNodeAddressByIndex(node: number, index: number): string {
|
||||||
index = index * 1; // cast to int
|
index = index * 1; // cast to int
|
||||||
if (node === 0) {
|
if (node === 0) {
|
||||||
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
||||||
|
@ -143,22 +172,20 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
this._node1 = hdNode.derive(node);
|
this._node1 = hdNode.derive(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
let address;
|
let address: string;
|
||||||
if (node === 0) {
|
if (node === 0) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
address = this.constructor._nodeToBech32SegwitAddress(this._node0.derive(index));
|
address = this._hdNodeToAddress(this._node0.derive(index));
|
||||||
}
|
} else {
|
||||||
|
// tbh the only possible else is node === 1
|
||||||
if (node === 1) {
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
address = this.constructor._nodeToBech32SegwitAddress(this._node1.derive(index));
|
address = this._hdNodeToAddress(this._node1.derive(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node === 0) {
|
if (node === 0) {
|
||||||
return (this.external_addresses_cache[index] = address);
|
return (this.external_addresses_cache[index] = address);
|
||||||
}
|
} else {
|
||||||
|
// tbh the only possible else option is node === 1
|
||||||
if (node === 1) {
|
|
||||||
return (this.internal_addresses_cache[index] = address);
|
return (this.internal_addresses_cache[index] = address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,7 +216,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
throw new Error('Internal error: this._node0 or this._node1 is undefined');
|
throw new Error('Internal error: this._node0 or this._node1 is undefined');
|
||||||
}
|
}
|
||||||
|
|
||||||
_getExternalAddressByIndex(index: number) {
|
_getExternalAddressByIndex(index: number): string {
|
||||||
return this._getNodeAddressByIndex(0, index);
|
return this._getNodeAddressByIndex(0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +293,21 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// next, bip47 addresses
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
let hasUnconfirmed = false;
|
||||||
|
this._txs_by_payment_code_index[pc] = this._txs_by_payment_code_index[pc] || {};
|
||||||
|
this._txs_by_payment_code_index[pc][c] = this._txs_by_payment_code_index[pc][c] || [];
|
||||||
|
for (const tx of this._txs_by_payment_code_index[pc][c])
|
||||||
|
hasUnconfirmed = hasUnconfirmed || !tx.confirmations || tx.confirmations < 7;
|
||||||
|
|
||||||
|
if (hasUnconfirmed || this._txs_by_payment_code_index[pc][c].length === 0 || this._balances_by_payment_code_index[pc].u !== 0) {
|
||||||
|
addresses2fetch.push(this._getBIP47Address(pc, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// first: batch fetch for all addresses histories
|
// first: batch fetch for all addresses histories
|
||||||
const histories = await BlueElectrum.multiGetHistoryByAddress(addresses2fetch);
|
const histories = await BlueElectrum.multiGetHistoryByAddress(addresses2fetch);
|
||||||
const txs: Record<string, ElectrumHistory> = {};
|
const txs: Record<string, ElectrumHistory> = {};
|
||||||
|
@ -296,7 +338,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
const inpTxid = txdatas[txid].vin[inpNum].txid;
|
const inpTxid = txdatas[txid].vin[inpNum].txid;
|
||||||
const inpVout = txdatas[txid].vin[inpNum].vout;
|
const inpVout = txdatas[txid].vin[inpNum].vout;
|
||||||
// got txid and output number of _previous_ transaction we shoud look into
|
// got txid and output number of _previous_ transaction we shoud look into
|
||||||
if (vintxdatas[inpTxid] && vintxdatas[inpTxid].vout[inpVout]) {
|
if (vintxdatas[inpTxid]?.vout[inpVout]) {
|
||||||
// extracting amount & addresses from previous output and adding it to _our_ input:
|
// extracting amount & addresses from previous output and adding it to _our_ input:
|
||||||
txdatas[txid].vin[inpNum].addresses = vintxdatas[inpTxid].vout[inpVout].scriptPubKey.addresses;
|
txdatas[txid].vin[inpNum].addresses = vintxdatas[inpTxid].vout[inpVout].scriptPubKey.addresses;
|
||||||
txdatas[txid].vin[inpNum].value = vintxdatas[inpTxid].vout[inpVout].value;
|
txdatas[txid].vin[inpNum].value = vintxdatas[inpTxid].vout[inpVout].value;
|
||||||
|
@ -312,6 +354,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
this._txs_by_internal_index[c] = this._txs_by_internal_index[c].filter(tx => !!tx.confirmations);
|
this._txs_by_internal_index[c] = this._txs_by_internal_index[c].filter(tx => !!tx.confirmations);
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
this._txs_by_payment_code_index[pc][c] = this._txs_by_payment_code_index[pc][c].filter(tx => !!tx.confirmations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// now, we need to put transactions in all relevant `cells` of internal hashmaps: this._txs_by_internal_index && this._txs_by_external_index
|
// now, we need to put transactions in all relevant `cells` of internal hashmaps: this._txs_by_internal_index && this._txs_by_external_index
|
||||||
|
|
||||||
|
@ -397,6 +444,51 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
for (const tx of Object.values(txdatas)) {
|
||||||
|
for (const vin of tx.vin) {
|
||||||
|
if (vin.addresses && vin.addresses.indexOf(this._getBIP47Address(pc, c)) !== -1) {
|
||||||
|
// this TX is related to our address
|
||||||
|
this._txs_by_payment_code_index[pc] = this._txs_by_payment_code_index[pc] || {};
|
||||||
|
this._txs_by_payment_code_index[pc][c] = this._txs_by_payment_code_index[pc][c] || [];
|
||||||
|
const { vin: txVin, vout: txVout, ...txRest } = tx;
|
||||||
|
const clonedTx = { ...txRest, inputs: txVin.slice(0), outputs: txVout.slice(0) };
|
||||||
|
|
||||||
|
// trying to replace tx if it exists already (because it has lower confirmations, for example)
|
||||||
|
let replaced = false;
|
||||||
|
for (let cc = 0; cc < this._txs_by_payment_code_index[pc][c].length; cc++) {
|
||||||
|
if (this._txs_by_payment_code_index[pc][c][cc].txid === clonedTx.txid) {
|
||||||
|
replaced = true;
|
||||||
|
this._txs_by_payment_code_index[pc][c][cc] = clonedTx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!replaced) this._txs_by_payment_code_index[pc][c].push(clonedTx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const vout of tx.vout) {
|
||||||
|
if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses.indexOf(this._getBIP47Address(pc, c)) !== -1) {
|
||||||
|
// this TX is related to our address
|
||||||
|
this._txs_by_payment_code_index[pc] = this._txs_by_payment_code_index[pc] || {};
|
||||||
|
this._txs_by_payment_code_index[pc][c] = this._txs_by_payment_code_index[pc][c] || [];
|
||||||
|
const { vin: txVin, vout: txVout, ...txRest } = tx;
|
||||||
|
const clonedTx = { ...txRest, inputs: txVin.slice(0), outputs: txVout.slice(0) };
|
||||||
|
|
||||||
|
// trying to replace tx if it exists already (because it has lower confirmations, for example)
|
||||||
|
let replaced = false;
|
||||||
|
for (let cc = 0; cc < this._txs_by_internal_index[c].length; cc++) {
|
||||||
|
if (this._txs_by_internal_index[c][cc].txid === clonedTx.txid) {
|
||||||
|
replaced = true;
|
||||||
|
this._txs_by_internal_index[c][cc] = clonedTx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!replaced) this._txs_by_internal_index[c].push(clonedTx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this._lastTxFetch = +new Date();
|
this._lastTxFetch = +new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,6 +501,14 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (const addressTxs of Object.values(this._txs_by_internal_index)) {
|
for (const addressTxs of Object.values(this._txs_by_internal_index)) {
|
||||||
txs = txs.concat(addressTxs);
|
txs = txs.concat(addressTxs);
|
||||||
}
|
}
|
||||||
|
if (this._sender_payment_codes) {
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
if (this._txs_by_payment_code_index[pc])
|
||||||
|
for (const addressTxs of Object.values(this._txs_by_payment_code_index[pc])) {
|
||||||
|
txs = txs.concat(addressTxs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (txs.length === 0) return []; // guard clause; so we wont spend time calculating addresses
|
if (txs.length === 0) return []; // guard clause; so we wont spend time calculating addresses
|
||||||
|
|
||||||
|
@ -421,6 +521,12 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + 1; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + 1; c++) {
|
||||||
ownedAddressesHashmap[this._getInternalAddressByIndex(c)] = true;
|
ownedAddressesHashmap[this._getInternalAddressByIndex(c)] = true;
|
||||||
}
|
}
|
||||||
|
if (this._sender_payment_codes)
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + 1; c++) {
|
||||||
|
ownedAddressesHashmap[this._getBIP47Address(pc, c)] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
// hack: in case this code is called from LegacyWallet:
|
// hack: in case this code is called from LegacyWallet:
|
||||||
if (this.getAddress()) ownedAddressesHashmap[String(this.getAddress())] = true;
|
if (this.getAddress()) ownedAddressesHashmap[String(this.getAddress())] = true;
|
||||||
|
|
||||||
|
@ -434,17 +540,14 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
|
|
||||||
for (const vin of tx.inputs) {
|
for (const vin of tx.inputs) {
|
||||||
// if input (spending) goes from our address - we are loosing!
|
// if input (spending) goes from our address - we are loosing!
|
||||||
if (
|
if ((vin.address && ownedAddressesHashmap[vin.address]) || (vin.addresses?.[0] && ownedAddressesHashmap[vin.addresses[0]])) {
|
||||||
(vin.address && ownedAddressesHashmap[vin.address]) ||
|
|
||||||
(vin.addresses && vin.addresses[0] && ownedAddressesHashmap[vin.addresses[0]])
|
|
||||||
) {
|
|
||||||
tx.value -= new BigNumber(vin.value ?? 0).multipliedBy(100000000).toNumber();
|
tx.value -= new BigNumber(vin.value ?? 0).multipliedBy(100000000).toNumber();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const vout of tx.outputs) {
|
for (const vout of tx.outputs) {
|
||||||
// when output goes to our address - this means we are gaining!
|
// when output goes to our address - this means we are gaining!
|
||||||
if (vout.scriptPubKey.addresses && vout.scriptPubKey.addresses[0] && ownedAddressesHashmap[vout.scriptPubKey.addresses[0]]) {
|
if (vout.scriptPubKey.addresses?.[0] && ownedAddressesHashmap[vout.scriptPubKey.addresses[0]]) {
|
||||||
tx.value += new BigNumber(vout.value).multipliedBy(100000000).toNumber();
|
tx.value += new BigNumber(vout.value).multipliedBy(100000000).toNumber();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -499,7 +602,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
) {
|
) {
|
||||||
const address = this._getInternalAddressByIndex(c);
|
const address = this._getInternalAddressByIndex(c);
|
||||||
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
|
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
|
||||||
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unsued
|
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unused
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -542,7 +645,50 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
) {
|
) {
|
||||||
const address = this._getExternalAddressByIndex(c);
|
const address = this._getExternalAddressByIndex(c);
|
||||||
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
|
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
|
||||||
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unsued
|
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastUsedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _binarySearchIterationForBIP47Address(paymentCode: string, index: number) {
|
||||||
|
const generateChunkAddresses = (chunkNum: number) => {
|
||||||
|
const ret = [];
|
||||||
|
for (let c = this.gap_limit * chunkNum; c < this.gap_limit * (chunkNum + 1); c++) {
|
||||||
|
ret.push(this._getBIP47Address(paymentCode, c));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
let lastChunkWithUsedAddressesNum = null;
|
||||||
|
let lastHistoriesWithUsedAddresses = null;
|
||||||
|
for (let c = 0; c < Math.round(index / this.gap_limit); c++) {
|
||||||
|
const histories = await BlueElectrum.multiGetHistoryByAddress(generateChunkAddresses(c));
|
||||||
|
// @ts-ignore
|
||||||
|
if (this.constructor._getTransactionsFromHistories(histories).length > 0) {
|
||||||
|
// in this particular chunk we have used addresses
|
||||||
|
lastChunkWithUsedAddressesNum = c;
|
||||||
|
lastHistoriesWithUsedAddresses = histories;
|
||||||
|
} else {
|
||||||
|
// empty chunk. no sense searching more chunks
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastUsedIndex = 0;
|
||||||
|
|
||||||
|
if (lastHistoriesWithUsedAddresses) {
|
||||||
|
// now searching for last used address in batch lastChunkWithUsedAddressesNum
|
||||||
|
for (
|
||||||
|
let c = Number(lastChunkWithUsedAddressesNum) * this.gap_limit;
|
||||||
|
c < Number(lastChunkWithUsedAddressesNum) * this.gap_limit + this.gap_limit;
|
||||||
|
c++
|
||||||
|
) {
|
||||||
|
const address = this._getBIP47Address(paymentCode, c);
|
||||||
|
if (lastHistoriesWithUsedAddresses[address] && lastHistoriesWithUsedAddresses[address].length > 0) {
|
||||||
|
lastUsedIndex = Math.max(c, lastUsedIndex) + 1; // point to next, which is supposed to be unused
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,6 +702,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
// doing binary search for last used address:
|
// doing binary search for last used address:
|
||||||
this.next_free_change_address_index = await this._binarySearchIterationForInternalAddress(1000);
|
this.next_free_change_address_index = await this._binarySearchIterationForInternalAddress(1000);
|
||||||
this.next_free_address_index = await this._binarySearchIterationForExternalAddress(1000);
|
this.next_free_address_index = await this._binarySearchIterationForExternalAddress(1000);
|
||||||
|
if (this._sender_payment_codes) {
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
this._next_free_payment_code_address_index[pc] = await this._binarySearchIterationForBIP47Address(pc, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
} // end rescanning fresh wallet
|
} // end rescanning fresh wallet
|
||||||
|
|
||||||
// finally fetching balance
|
// finally fetching balance
|
||||||
|
@ -577,6 +728,15 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = this.next_free_change_address_index; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = this.next_free_change_address_index; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
lagAddressesToFetch.push(this._getInternalAddressByIndex(c));
|
lagAddressesToFetch.push(this._getInternalAddressByIndex(c));
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (
|
||||||
|
let c = this._next_free_payment_code_address_index[pc];
|
||||||
|
c < this._next_free_payment_code_address_index[pc] + this.gap_limit;
|
||||||
|
c++
|
||||||
|
) {
|
||||||
|
lagAddressesToFetch.push(this._getBIP47Address(pc, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const txs = await BlueElectrum.multiGetHistoryByAddress(lagAddressesToFetch); // <------ electrum call
|
const txs = await BlueElectrum.multiGetHistoryByAddress(lagAddressesToFetch); // <------ electrum call
|
||||||
|
|
||||||
|
@ -596,6 +756,20 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (
|
||||||
|
let c = this._next_free_payment_code_address_index[pc];
|
||||||
|
c < this._next_free_payment_code_address_index[pc] + this.gap_limit;
|
||||||
|
c++
|
||||||
|
) {
|
||||||
|
const address = this._getBIP47Address(pc, c);
|
||||||
|
if (txs[address] && Array.isArray(txs[address]) && txs[address].length > 0) {
|
||||||
|
// whoa, someone uses our wallet outside! better catch up
|
||||||
|
this._next_free_payment_code_address_index[pc] = c + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// next, business as usuall. fetch balances
|
// next, business as usuall. fetch balances
|
||||||
|
|
||||||
const addresses2fetch = [];
|
const addresses2fetch = [];
|
||||||
|
@ -614,6 +788,12 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
addresses2fetch.push(this._getInternalAddressByIndex(c));
|
addresses2fetch.push(this._getInternalAddressByIndex(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._next_free_payment_code_address_index[pc] + this.gap_limit; c++) {
|
||||||
|
addresses2fetch.push(this._getBIP47Address(pc, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const balances = await BlueElectrum.multiGetBalanceByAddress(addresses2fetch);
|
const balances = await BlueElectrum.multiGetBalanceByAddress(addresses2fetch);
|
||||||
|
|
||||||
// converting to a more compact internal format
|
// converting to a more compact internal format
|
||||||
|
@ -658,6 +838,22 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
let confirmed = 0;
|
||||||
|
let unconfirmed = 0;
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
const addr = this._getBIP47Address(pc, c);
|
||||||
|
if (balances.addresses[addr].confirmed || balances.addresses[addr].unconfirmed) {
|
||||||
|
confirmed = confirmed + balances.addresses[addr].confirmed;
|
||||||
|
unconfirmed = unconfirmed + balances.addresses[addr].unconfirmed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._balances_by_payment_code_index[pc] = {
|
||||||
|
c: confirmed,
|
||||||
|
u: unconfirmed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this._lastBalanceFetch = +new Date();
|
this._lastBalanceFetch = +new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,28 +863,44 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
|
|
||||||
// considering confirmed balance:
|
// considering confirmed balance:
|
||||||
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
|
||||||
if (this._balances_by_external_index[c] && this._balances_by_external_index[c].c && this._balances_by_external_index[c].c > 0) {
|
if (this._balances_by_external_index?.[c]?.c > 0) {
|
||||||
addressess.push(this._getExternalAddressByIndex(c));
|
addressess.push(this._getExternalAddressByIndex(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
if (this._balances_by_internal_index[c] && this._balances_by_internal_index[c].c && this._balances_by_internal_index[c].c > 0) {
|
if (this._balances_by_internal_index?.[c]?.c > 0) {
|
||||||
addressess.push(this._getInternalAddressByIndex(c));
|
addressess.push(this._getInternalAddressByIndex(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._next_free_payment_code_address_index[pc] + this.gap_limit; c++) {
|
||||||
|
if (this._balances_by_payment_code_index?.[pc]?.c > 0) {
|
||||||
|
addressess.push(this._getBIP47Address(pc, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// considering UNconfirmed balance:
|
// considering UNconfirmed balance:
|
||||||
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_address_index + this.gap_limit; c++) {
|
||||||
if (this._balances_by_external_index[c] && this._balances_by_external_index[c].u && this._balances_by_external_index[c].u > 0) {
|
if (this._balances_by_external_index?.[c]?.u > 0) {
|
||||||
addressess.push(this._getExternalAddressByIndex(c));
|
addressess.push(this._getExternalAddressByIndex(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
if (this._balances_by_internal_index[c] && this._balances_by_internal_index[c].u && this._balances_by_internal_index[c].u > 0) {
|
if (this._balances_by_internal_index?.[c]?.u > 0) {
|
||||||
addressess.push(this._getInternalAddressByIndex(c));
|
addressess.push(this._getInternalAddressByIndex(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._next_free_payment_code_address_index[pc] + this.gap_limit; c++) {
|
||||||
|
if (this._balances_by_payment_code_index?.[pc]?.u > 0) {
|
||||||
|
addressess.push(this._getBIP47Address(pc, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// note: we could remove checks `.c` and `.u` to simplify code, but the resulting `addressess` array would be bigger, thus bigger batch
|
// note: we could remove checks `.c` and `.u` to simplify code, but the resulting `addressess` array would be bigger, thus bigger batch
|
||||||
// to fetch (or maybe even several fetches), which is not critical but undesirable.
|
// to fetch (or maybe even several fetches), which is not critical but undesirable.
|
||||||
// anyway, result has `.confirmations` property for each utxo, so outside caller can easily filter out unconfirmed if he wants to
|
// anyway, result has `.confirmations` property for each utxo, so outside caller can easily filter out unconfirmed if he wants to
|
||||||
|
@ -756,6 +968,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + 1; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + 1; c++) {
|
||||||
ownedAddressesHashmap[this._getInternalAddressByIndex(c)] = true;
|
ownedAddressesHashmap[this._getInternalAddressByIndex(c)] = true;
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + 1; c++) {
|
||||||
|
ownedAddressesHashmap[this._getBIP47Address(pc, c)] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const tx of this.getTransactions()) {
|
for (const tx of this.getTransactions()) {
|
||||||
for (const output of tx.outputs) {
|
for (const output of tx.outputs) {
|
||||||
|
@ -811,6 +1028,12 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
if (this._getInternalAddressByIndex(c) === address) return path + '/1/' + c;
|
if (this._getInternalAddressByIndex(c) === address) return path + '/1/' + c;
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
// not technically correct but well, to have at least somethign in PSBT...
|
||||||
|
if (this._getBIP47Address(pc, c) === address) return "m/47'/0'/0'/" + c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -827,6 +1050,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
if (this._getInternalAddressByIndex(c) === address) return this._getNodePubkeyByIndex(1, c);
|
if (this._getInternalAddressByIndex(c) === address) return this._getNodePubkeyByIndex(1, c);
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
if (this._getBIP47Address(pc, c) === address) return this._getBIP47PubkeyByIndex(pc, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -844,6 +1072,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
if (this._getInternalAddressByIndex(c) === address) return this._getWIFByIndex(true, c);
|
if (this._getInternalAddressByIndex(c) === address) return this._getWIFByIndex(true, c);
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
if (this._getBIP47Address(pc, c) === address) return this._getBIP47WIF(pc, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -861,6 +1094,11 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
for (let c = 0; c < this.next_free_change_address_index + this.gap_limit; c++) {
|
||||||
if (this._getInternalAddressByIndex(c) === cleanAddress) return true;
|
if (this._getInternalAddressByIndex(c) === cleanAddress) return true;
|
||||||
}
|
}
|
||||||
|
for (const pc of this._sender_payment_codes) {
|
||||||
|
for (let c = 0; c < this._getNextFreePaymentCodeAddress(pc) + this.gap_limit; c++) {
|
||||||
|
if (this._getBIP47Address(pc, c) === address) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,22 +1290,29 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates Segwit Bech32 Bitcoin address
|
* Creates Segwit Bech32 Bitcoin address
|
||||||
*
|
|
||||||
* @param hdNode
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
*/
|
||||||
static _nodeToBech32SegwitAddress(hdNode: BIP32Interface) {
|
_nodeToBech32SegwitAddress(hdNode: BIP32Interface): string {
|
||||||
return bitcoin.payments.p2wpkh({
|
return bitcoin.payments.p2wpkh({
|
||||||
pubkey: hdNode.publicKey,
|
pubkey: hdNode.publicKey,
|
||||||
}).address;
|
}).address;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _nodeToLegacyAddress(hdNode: BIP32Interface) {
|
_nodeToLegacyAddress(hdNode: BIP32Interface): string {
|
||||||
return bitcoin.payments.p2pkh({
|
return bitcoin.payments.p2pkh({
|
||||||
pubkey: hdNode.publicKey,
|
pubkey: hdNode.publicKey,
|
||||||
}).address;
|
}).address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates Segwit P2SH Bitcoin address
|
||||||
|
*/
|
||||||
|
_nodeToP2shSegwitAddress(hdNode: BIP32Interface): string {
|
||||||
|
const { address } = bitcoin.payments.p2sh({
|
||||||
|
redeem: bitcoin.payments.p2wpkh({ pubkey: hdNode.publicKey }),
|
||||||
|
});
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
static _getTransactionsFromHistories(histories: Record<string, ElectrumHistory[]>) {
|
static _getTransactionsFromHistories(histories: Record<string, ElectrumHistory[]>) {
|
||||||
const txs = [];
|
const txs = [];
|
||||||
for (const history of Object.values(histories)) {
|
for (const history of Object.values(histories)) {
|
||||||
|
@ -1080,14 +1325,29 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Probes zero address in external hierarchy for transactions, if there are any returns TRUE.
|
* Probes zero address in external hierarchy for transactions, if there are any returns TRUE.
|
||||||
* Zero address is a pretty good indicator, since its a first one to fund the wallet. How can you use the wallet and
|
* Zero address is a pretty good indicator, since its a first one to fund the wallet.
|
||||||
* not fund it first?
|
* Q: How can you use the wallet and not fund it first?
|
||||||
|
* A: You can if it is a BIP47 wallet!
|
||||||
*
|
*
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
async wasEverUsed() {
|
async wasEverUsed(): Promise<boolean> {
|
||||||
const txs = await BlueElectrum.getTransactionsByAddress(this._getExternalAddressByIndex(0));
|
const txs1 = await BlueElectrum.getTransactionsByAddress(this._getExternalAddressByIndex(0));
|
||||||
return txs.length > 0;
|
if (txs1.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!this.allowBIP47()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// only check BIP47 if derivation path is regular, otherwise too many wallets will be found
|
||||||
|
if (!["m/84'/0'/0'", "m/44'/0'/0'", "m/49'/0'/0'"].includes(this.getDerivationPath() as string)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bip47_instance = this.getBIP47FromSeed();
|
||||||
|
const address = bip47_instance.getNotificationAddress();
|
||||||
|
const txs2 = await BlueElectrum.getTransactionsByAddress(address);
|
||||||
|
return txs2.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1192,4 +1452,114 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||||
const seed = this._getSeed();
|
const seed = this._getSeed();
|
||||||
return AbstractHDElectrumWallet.seedToFingerprint(seed);
|
return AbstractHDElectrumWallet.seedToFingerprint(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether BIP47 is enabled. This is per-wallet setting that can be changed, NOT a feature-flag
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
isBIP47Enabled(): boolean {
|
||||||
|
return this._enable_BIP47;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchBIP47(value: boolean): void {
|
||||||
|
this._enable_BIP47 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBIP47FromSeed(): BIP47Interface {
|
||||||
|
if (!this._bip47_instance || !this._bip47_instance.getNotificationAddress) {
|
||||||
|
this._bip47_instance = bip47.fromBip39Seed(this.secret, undefined, this.passphrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._bip47_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBIP47PaymentCode(): string {
|
||||||
|
if (!this._payment_code) {
|
||||||
|
this._payment_code = this.getBIP47FromSeed().getSerializedPaymentCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._payment_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
getBIP47NotificationAddress(): string {
|
||||||
|
const bip47 = this.getBIP47FromSeed();
|
||||||
|
return bip47.getNotificationAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchBIP47SenderPaymentCodes(): Promise<void> {
|
||||||
|
const bip47_instance = this.getBIP47FromSeed();
|
||||||
|
const address = bip47_instance.getNotificationAddress();
|
||||||
|
const histories = await BlueElectrum.multiGetHistoryByAddress([address]);
|
||||||
|
const txHashes = histories[address].map(({ tx_hash }) => tx_hash);
|
||||||
|
|
||||||
|
const txHexs = await BlueElectrum.multiGetTransactionByTxid(txHashes, 50, false);
|
||||||
|
for (const txHex of Object.values(txHexs)) {
|
||||||
|
try {
|
||||||
|
const paymentCode = bip47_instance.getPaymentCodeFromRawNotificationTransaction(txHex);
|
||||||
|
if (this._sender_payment_codes.includes(paymentCode)) continue; // already have it
|
||||||
|
|
||||||
|
// final check if PC is even valid (could've been constructed by a buggy code, and our code would crash with that):
|
||||||
|
try {
|
||||||
|
BIP47Factory(ecc).fromPaymentCode(paymentCode);
|
||||||
|
} catch (_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sender_payment_codes.push(paymentCode);
|
||||||
|
this._next_free_payment_code_address_index[paymentCode] = 0; // initialize
|
||||||
|
this._balances_by_payment_code_index[paymentCode] = { c: 0, u: 0 };
|
||||||
|
} catch (e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBIP47SenderPaymentCodes(): string[] {
|
||||||
|
return this._sender_payment_codes;
|
||||||
|
}
|
||||||
|
|
||||||
|
_hdNodeToAddress(hdNode: BIP32Interface): string {
|
||||||
|
return this._nodeToBech32SegwitAddress(hdNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getBIP47Address(paymentCode: string, index: number): string {
|
||||||
|
if (!this._addresses_by_payment_code[paymentCode]) this._addresses_by_payment_code[paymentCode] = [];
|
||||||
|
|
||||||
|
if (this._addresses_by_payment_code[paymentCode][index]) {
|
||||||
|
return this._addresses_by_payment_code[paymentCode][index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const bip47_instance = this.getBIP47FromSeed();
|
||||||
|
const senderBIP47_instance = bip47.fromPaymentCode(paymentCode);
|
||||||
|
const remotePaymentNode = senderBIP47_instance.getPaymentCodeNode();
|
||||||
|
const hdNode = bip47_instance.getPaymentWallet(remotePaymentNode, index);
|
||||||
|
const address = this._hdNodeToAddress(hdNode);
|
||||||
|
this._address_to_wif_cache[address] = hdNode.toWIF();
|
||||||
|
this._addresses_by_payment_code[paymentCode][index] = address;
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getNextFreePaymentCodeAddress(paymentCode: string) {
|
||||||
|
return this._next_free_payment_code_address_index[paymentCode] || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_getBalancesByPaymentCodeIndex(paymentCode: string): BalanceByIndex {
|
||||||
|
return this._balances_by_payment_code_index[paymentCode] || { c: 0, u: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
_getBIP47WIF(paymentCode: string, index: number): string {
|
||||||
|
const bip47_instance = this.getBIP47FromSeed();
|
||||||
|
const senderBIP47_instance = bip47.fromPaymentCode(paymentCode);
|
||||||
|
const remotePaymentNode = senderBIP47_instance.getPaymentCodeNode();
|
||||||
|
const hdNode = bip47_instance.getPaymentWallet(remotePaymentNode, index);
|
||||||
|
return hdNode.toWIF();
|
||||||
|
}
|
||||||
|
|
||||||
|
_getBIP47PubkeyByIndex(paymentCode: string, index: number): Buffer {
|
||||||
|
const bip47_instance = this.getBIP47FromSeed();
|
||||||
|
const senderBIP47_instance = bip47.fromPaymentCode(paymentCode);
|
||||||
|
const remotePaymentNode = senderBIP47_instance.getPaymentCodeNode();
|
||||||
|
const hdNode = bip47_instance.getPaymentWallet(remotePaymentNode, index);
|
||||||
|
return hdNode.publicKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,18 @@ export class AbstractWallet {
|
||||||
return BitcoinUnit.BTC;
|
return BitcoinUnit.BTC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async allowOnchainAddress(): Promise<boolean> {
|
||||||
|
throw new Error('allowOnchainAddress: Not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
|
allowBIP47(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switchBIP47(value: boolean): void {
|
||||||
|
throw new Error('switchBIP47: not implemented');
|
||||||
|
}
|
||||||
|
|
||||||
allowReceive(): boolean {
|
allowReceive(): boolean {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -223,6 +235,16 @@ export class AbstractWallet {
|
||||||
this._derivationPath = derivationPath;
|
this._derivationPath = derivationPath;
|
||||||
}
|
}
|
||||||
this.secret = m[2];
|
this.secret = m[2];
|
||||||
|
|
||||||
|
if (derivationPath.startsWith("m/84'/0'/") && this.secret.toLowerCase().startsWith('xpub')) {
|
||||||
|
// need to convert xpub to zpub
|
||||||
|
this.secret = this._xpubToZpub(this.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (derivationPath.startsWith("m/49'/0'/") && this.secret.toLowerCase().startsWith('xpub')) {
|
||||||
|
// need to convert xpub to ypub
|
||||||
|
this.secret = this._xpubToYpub(this.secret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -348,6 +370,10 @@ export class AbstractWallet {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isBIP47Enabled(): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async wasEverUsed(): Promise<boolean> {
|
async wasEverUsed(): Promise<boolean> {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
@ -390,6 +416,22 @@ export class AbstractWallet {
|
||||||
return b58.encode(data);
|
return b58.encode(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_xpubToZpub(xpub: string): string {
|
||||||
|
let data = b58.decode(xpub);
|
||||||
|
data = data.slice(4);
|
||||||
|
data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]);
|
||||||
|
|
||||||
|
return b58.encode(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_xpubToYpub(xpub: string): string {
|
||||||
|
let data = b58.decode(xpub);
|
||||||
|
data = data.slice(4);
|
||||||
|
data = Buffer.concat([Buffer.from('049d7cb2', 'hex'), data]);
|
||||||
|
|
||||||
|
return b58.encode(data);
|
||||||
|
}
|
||||||
|
|
||||||
prepareForSerialization(): void {}
|
prepareForSerialization(): void {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -23,6 +23,10 @@ export class HDLegacyElectrumSeedP2PKHWallet extends HDLegacyP2PKHWallet {
|
||||||
return mn.validateMnemonic(this.secret, PREFIX);
|
return mn.validateMnemonic(this.secret, PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowBIP47() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async generate() {
|
async generate() {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,10 @@ export class HDLegacyP2PKHWallet extends AbstractHDElectrumWallet {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowBIP47() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
getXpub() {
|
getXpub() {
|
||||||
if (this._xpub) {
|
if (this._xpub) {
|
||||||
return this._xpub; // cache hit
|
return this._xpub; // cache hit
|
||||||
|
@ -48,44 +52,8 @@ export class HDLegacyP2PKHWallet extends AbstractHDElectrumWallet {
|
||||||
return this._xpub;
|
return this._xpub;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getNodeAddressByIndex(node, index) {
|
_hdNodeToAddress(hdNode) {
|
||||||
index = index * 1; // cast to int
|
return this._nodeToLegacyAddress(hdNode);
|
||||||
if (node === 0) {
|
|
||||||
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1) {
|
|
||||||
if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 0 && !this._node0) {
|
|
||||||
const xpub = this.getXpub();
|
|
||||||
const hdNode = bip32.fromBase58(xpub);
|
|
||||||
this._node0 = hdNode.derive(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1 && !this._node1) {
|
|
||||||
const xpub = this.getXpub();
|
|
||||||
const hdNode = bip32.fromBase58(xpub);
|
|
||||||
this._node1 = hdNode.derive(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
let address;
|
|
||||||
if (node === 0) {
|
|
||||||
address = this.constructor._nodeToLegacyAddress(this._node0.derive(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1) {
|
|
||||||
address = this.constructor._nodeToLegacyAddress(this._node1.derive(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 0) {
|
|
||||||
return (this.external_addresses_cache[index] = address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1) {
|
|
||||||
return (this.internal_addresses_cache[index] = address);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchUtxo() {
|
async fetchUtxo() {
|
||||||
|
|
|
@ -46,4 +46,8 @@ export class HDSegwitBech32Wallet extends AbstractHDElectrumWallet {
|
||||||
allowXpub() {
|
allowXpub() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowBIP47() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,10 @@ export class HDSegwitElectrumSeedP2WPKHWallet extends HDSegwitBech32Wallet {
|
||||||
return mn.validateMnemonic(this.secret, PREFIX);
|
return mn.validateMnemonic(this.secret, PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowBIP47() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async generate() {
|
async generate() {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,44 +40,8 @@ export class HDSegwitP2SHWallet extends AbstractHDElectrumWallet {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_getNodeAddressByIndex(node, index) {
|
_hdNodeToAddress(hdNode) {
|
||||||
index = index * 1; // cast to int
|
return this._nodeToP2shSegwitAddress(hdNode);
|
||||||
if (node === 0) {
|
|
||||||
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1) {
|
|
||||||
if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 0 && !this._node0) {
|
|
||||||
const xpub = this.constructor._ypubToXpub(this.getXpub());
|
|
||||||
const hdNode = bip32.fromBase58(xpub);
|
|
||||||
this._node0 = hdNode.derive(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1 && !this._node1) {
|
|
||||||
const xpub = this.constructor._ypubToXpub(this.getXpub());
|
|
||||||
const hdNode = bip32.fromBase58(xpub);
|
|
||||||
this._node1 = hdNode.derive(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let address;
|
|
||||||
if (node === 0) {
|
|
||||||
address = this.constructor._nodeToP2shSegwitAddress(this._node0.derive(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1) {
|
|
||||||
address = this.constructor._nodeToP2shSegwitAddress(this._node1.derive(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 0) {
|
|
||||||
return (this.external_addresses_cache[index] = address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node === 1) {
|
|
||||||
return (this.internal_addresses_cache[index] = address);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,18 +98,6 @@ export class HDSegwitP2SHWallet extends AbstractHDElectrumWallet {
|
||||||
return psbt;
|
return psbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates Segwit P2SH Bitcoin address
|
|
||||||
* @param hdNode
|
|
||||||
* @returns {String}
|
|
||||||
*/
|
|
||||||
static _nodeToP2shSegwitAddress(hdNode) {
|
|
||||||
const { address } = bitcoin.payments.p2sh({
|
|
||||||
redeem: bitcoin.payments.p2wpkh({ pubkey: hdNode.publicKey }),
|
|
||||||
});
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
isSegwit() {
|
isSegwit() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ export class LightningCustodianWallet extends LegacyWallet {
|
||||||
|
|
||||||
async payInvoice(invoice, freeAmount = 0) {
|
async payInvoice(invoice, freeAmount = 0) {
|
||||||
const response = await this._api.post('/payinvoice', {
|
const response = await this._api.post('/payinvoice', {
|
||||||
body: { invoice: invoice, amount: freeAmount },
|
body: { invoice, amount: freeAmount },
|
||||||
headers: {
|
headers: {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@ -215,7 +215,7 @@ export class LightningCustodianWallet extends LegacyWallet {
|
||||||
|
|
||||||
async addInvoice(amt, memo) {
|
async addInvoice(amt, memo) {
|
||||||
const response = await this._api.post('/addinvoice', {
|
const response = await this._api.post('/addinvoice', {
|
||||||
body: { amt: amt + '', memo: memo },
|
body: { amt: amt + '', memo },
|
||||||
headers: {
|
headers: {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@ -254,7 +254,7 @@ export class LightningCustodianWallet extends LegacyWallet {
|
||||||
password = this.secret.replace('lndhub://', '').split(':')[1];
|
password = this.secret.replace('lndhub://', '').split(':')[1];
|
||||||
}
|
}
|
||||||
const response = await this._api.post('/auth?type=auth', {
|
const response = await this._api.post('/auth?type=auth', {
|
||||||
body: { login: login, password: password },
|
body: { login, password },
|
||||||
headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
|
headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -567,11 +567,11 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
|
||||||
}
|
}
|
||||||
if (secret.indexOf('sortedmulti(') !== -1 && json.descriptor) {
|
if (secret.indexOf('sortedmulti(') !== -1 && json.descriptor) {
|
||||||
if (json.label) this.setLabel(json.label);
|
if (json.label) this.setLabel(json.label);
|
||||||
if (json.descriptor.startsWith('wsh(')) {
|
if (json.descriptor.includes('sh(wsh(')) {
|
||||||
this.setNativeSegwit();
|
|
||||||
} else if (json.descriptor.startsWith('sh(wsh(')) {
|
|
||||||
this.setWrappedSegwit();
|
this.setWrappedSegwit();
|
||||||
} else if (json.descriptor.startsWith('sh(')) {
|
} else if (json.descriptor.includes('wsh(')) {
|
||||||
|
this.setNativeSegwit();
|
||||||
|
} else if (json.descriptor.includes('sh(')) {
|
||||||
this.setLegacy();
|
this.setLegacy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,8 +624,7 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
|
||||||
|
|
||||||
for (const pk of json.extendedPublicKeys) {
|
for (const pk of json.extendedPublicKeys) {
|
||||||
const path = this.constructor.isPathValid(json.bip32Path) ? json.bip32Path : "m/1'";
|
const path = this.constructor.isPathValid(json.bip32Path) ? json.bip32Path : "m/1'";
|
||||||
// wtf, where caravan stores fingerprints..?
|
this.addCosigner(pk.xpub, pk.xfp ?? '00000000', path);
|
||||||
this.addCosigner(pk.xpub, '00000000', path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,10 @@ export class SLIP39LegacyP2PKHWallet extends HDLegacyP2PKHWallet {
|
||||||
static type = 'SLIP39legacyP2PKH';
|
static type = 'SLIP39legacyP2PKH';
|
||||||
static typeReadable = 'SLIP39 Legacy (P2PKH)';
|
static typeReadable = 'SLIP39 Legacy (P2PKH)';
|
||||||
|
|
||||||
|
allowBIP47() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_getSeed = SLIP39Mixin._getSeed;
|
_getSeed = SLIP39Mixin._getSeed;
|
||||||
validateMnemonic = SLIP39Mixin.validateMnemonic;
|
validateMnemonic = SLIP39Mixin.validateMnemonic;
|
||||||
setSecret = SLIP39Mixin.setSecret;
|
setSecret = SLIP39Mixin.setSecret;
|
||||||
|
@ -87,6 +91,10 @@ export class SLIP39SegwitBech32Wallet extends HDSegwitBech32Wallet {
|
||||||
static type = 'SLIP39segwitBech32';
|
static type = 'SLIP39segwitBech32';
|
||||||
static typeReadable = 'SLIP39 SegWit (Bech32)';
|
static typeReadable = 'SLIP39 SegWit (Bech32)';
|
||||||
|
|
||||||
|
allowBIP47() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_getSeed = SLIP39Mixin._getSeed;
|
_getSeed = SLIP39Mixin._getSeed;
|
||||||
validateMnemonic = SLIP39Mixin.validateMnemonic;
|
validateMnemonic = SLIP39Mixin.validateMnemonic;
|
||||||
setSecret = SLIP39Mixin.setSecret;
|
setSecret = SLIP39Mixin.setSecret;
|
||||||
|
|
|
@ -100,6 +100,7 @@ export class WatchOnlyWallet extends LegacyWallet {
|
||||||
if (this._hdWalletInstance) {
|
if (this._hdWalletInstance) {
|
||||||
delete this._hdWalletInstance._node0;
|
delete this._hdWalletInstance._node0;
|
||||||
delete this._hdWalletInstance._node1;
|
delete this._hdWalletInstance._node1;
|
||||||
|
delete this._hdWalletInstance._bip47_instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,12 @@ class AmountInput extends Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableWithoutFeedback disabled={this.props.pointerEvents === 'none'} onPress={() => this.textInput.focus()}>
|
<TouchableWithoutFeedback
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc._.enter_amount}
|
||||||
|
disabled={this.props.pointerEvents === 'none'}
|
||||||
|
onPress={() => this.textInput.focus()}
|
||||||
|
>
|
||||||
<>
|
<>
|
||||||
<View style={styles.root}>
|
<View style={styles.root}>
|
||||||
{!disabled && <View style={[styles.center, stylesHook.center]} />}
|
{!disabled && <View style={[styles.center, stylesHook.center]} />}
|
||||||
|
@ -289,6 +294,7 @@ class AmountInput extends Component {
|
||||||
{!disabled && amount !== BitcoinUnit.MAX && (
|
{!disabled && amount !== BitcoinUnit.MAX && (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc._.change_input_currency}
|
||||||
testID="changeAmountUnitButton"
|
testID="changeAmountUnitButton"
|
||||||
style={styles.changeAmountUnit}
|
style={styles.changeAmountUnit}
|
||||||
onPress={this.changeAmountUnit}
|
onPress={this.changeAmountUnit}
|
||||||
|
@ -306,6 +312,8 @@ class AmountInput extends Component {
|
||||||
</BlueText>
|
</BlueText>
|
||||||
<View style={styles.spacing8} />
|
<View style={styles.spacing8} />
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc._.refresh}
|
||||||
onPress={this.updateRate}
|
onPress={this.updateRate}
|
||||||
disabled={this.state.isRateBeingUpdated}
|
disabled={this.state.isRateBeingUpdated}
|
||||||
style={this.state.isRateBeingUpdated ? styles.disabledButton : styles.enabledButon}
|
style={this.state.isRateBeingUpdated ? styles.disabledButton : styles.enabledButon}
|
||||||
|
|
|
@ -30,6 +30,8 @@ export const ArrowPicker = (props: ArrowPickerProps) => {
|
||||||
return (
|
return (
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<Pressable
|
<Pressable
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc.send.dynamic_prev}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
let newIndex = keyIndex;
|
let newIndex = keyIndex;
|
||||||
|
@ -48,12 +50,16 @@ export const ArrowPicker = (props: ArrowPickerProps) => {
|
||||||
styles.wrapperCustom,
|
styles.wrapperCustom,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
{/*
|
||||||
|
// @ts-ignore: Ignore */}
|
||||||
<Icon size={24} name="chevron-left" type="ionicons" tvParallaxProperties={undefined} />
|
<Icon size={24} name="chevron-left" type="ionicons" tvParallaxProperties={undefined} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
<View style={{ width: 200 }}>
|
<View style={{ width: 200 }}>
|
||||||
<Text style={[styles.text, stylesHook.text]}>{props.isItemUnknown ? loc.send.fee_custom : keys[keyIndex]}</Text>
|
<Text style={[styles.text, stylesHook.text]}>{props.isItemUnknown ? loc.send.fee_custom : keys[keyIndex]}</Text>
|
||||||
</View>
|
</View>
|
||||||
<Pressable
|
<Pressable
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc.send.dynamic_next}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
let newIndex = keyIndex;
|
let newIndex = keyIndex;
|
||||||
|
@ -72,6 +78,8 @@ export const ArrowPicker = (props: ArrowPickerProps) => {
|
||||||
styles.wrapperCustom,
|
styles.wrapperCustom,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
{/*
|
||||||
|
// @ts-ignore: Ignore */}
|
||||||
<Icon size={24} name="chevron-right" type="ionicons" tvParallaxProperties={undefined} />
|
<Icon size={24} name="chevron-right" type="ionicons" tvParallaxProperties={undefined} />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -38,7 +38,7 @@ const Button = props => {
|
||||||
const opacity = { opacity: disabled ? 0.5 : 1.0 };
|
const opacity = { opacity: disabled ? 0.5 : 1.0 };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={onPress} disabled={disabled} style={opacity}>
|
<TouchableOpacity accessibilityRole="button" onPress={onPress} disabled={disabled} style={opacity}>
|
||||||
<View style={[styles.buttonContainer, buttonStyles()]}>
|
<View style={[styles.buttonContainer, buttonStyles()]}>
|
||||||
<Text style={[styles.text, textStyles()]}>{text}</Text>
|
<Text style={[styles.text, textStyles()]}>{text}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import React from 'react';
|
||||||
export const LdkButton = props => {
|
export const LdkButton = props => {
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={props.onPress}>
|
<TouchableOpacity accessibilityRole="button" onPress={props.onPress}>
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
borderColor: (props.active && colors.lnborderColor) || colors.buttonDisabledBackgroundColor,
|
borderColor: (props.active && colors.lnborderColor) || colors.buttonDisabledBackgroundColor,
|
||||||
|
|
|
@ -133,7 +133,7 @@ const MultipleStepsListItem = props => {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{!showActivityIndicator && props.rightButton && checked && (
|
{!showActivityIndicator && props.rightButton && checked && (
|
||||||
<View style={styles.rightButtonContainer} accessibilityComponentType>
|
<View style={styles.rightButtonContainer}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
disabled={props.rightButton.disabled}
|
disabled={props.rightButton.disabled}
|
||||||
|
|
|
@ -4,12 +4,58 @@ import QRCode from 'react-native-qrcode-svg';
|
||||||
import ToolTipMenu from './TooltipMenu';
|
import ToolTipMenu from './TooltipMenu';
|
||||||
import Share from 'react-native-share';
|
import Share from 'react-native-share';
|
||||||
import loc from '../loc';
|
import loc from '../loc';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import { useTheme } from '@react-navigation/native';
|
import { useTheme } from '@react-navigation/native';
|
||||||
|
|
||||||
const QRCodeComponent = ({
|
interface QRCodeComponentProps {
|
||||||
value,
|
value: string;
|
||||||
|
isLogoRendered?: boolean;
|
||||||
|
isMenuAvailable?: boolean;
|
||||||
|
logoSize?: number;
|
||||||
|
size?: number;
|
||||||
|
ecl?: 'H' | 'Q' | 'M' | 'L';
|
||||||
|
onError?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ActionIcons {
|
||||||
|
iconType: 'SYSTEM';
|
||||||
|
iconValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ActionType {
|
||||||
|
Share: 'share';
|
||||||
|
Copy: 'copy';
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Action {
|
||||||
|
id: string;
|
||||||
|
text: string;
|
||||||
|
icon: ActionIcons;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionKeys: ActionType = {
|
||||||
|
Share: 'share',
|
||||||
|
Copy: 'copy',
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ActionIcons {
|
||||||
|
iconType: 'SYSTEM';
|
||||||
|
iconValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionIcons: { [key: string]: ActionIcons } = {
|
||||||
|
Share: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'square.and.arrow.up',
|
||||||
|
},
|
||||||
|
Copy: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'doc.on.doc',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const QRCodeComponent: React.FC<QRCodeComponentProps> = ({
|
||||||
|
value = '',
|
||||||
isLogoRendered = true,
|
isLogoRendered = true,
|
||||||
isMenuAvailable = true,
|
isMenuAvailable = true,
|
||||||
logoSize = 90,
|
logoSize = 90,
|
||||||
|
@ -17,39 +63,39 @@ const QRCodeComponent = ({
|
||||||
ecl = 'H',
|
ecl = 'H',
|
||||||
onError = () => {},
|
onError = () => {},
|
||||||
}) => {
|
}) => {
|
||||||
const qrCode = useRef();
|
const qrCode = useRef<any>();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const handleShareQRCode = () => {
|
const handleShareQRCode = () => {
|
||||||
qrCode.current.toDataURL(data => {
|
qrCode.current.toDataURL((data: string) => {
|
||||||
const shareImageBase64 = {
|
const shareImageBase64 = {
|
||||||
url: `data:image/png;base64,${data}`,
|
url: `data:image/png;base64,${data}`,
|
||||||
};
|
};
|
||||||
Share.open(shareImageBase64).catch(error => console.log(error));
|
Share.open(shareImageBase64).catch((error: any) => console.log(error));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPressMenuItem = id => {
|
const onPressMenuItem = (id: string) => {
|
||||||
if (id === QRCodeComponent.actionKeys.Share) {
|
if (id === actionKeys.Share) {
|
||||||
handleShareQRCode();
|
handleShareQRCode();
|
||||||
} else if (id === QRCodeComponent.actionKeys.Copy) {
|
} else if (id === actionKeys.Copy) {
|
||||||
qrCode.current.toDataURL(Clipboard.setImage);
|
qrCode.current.toDataURL(Clipboard.setImage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const menuActions = () => {
|
const menuActions = (): Action[] => {
|
||||||
const actions = [];
|
const actions: Action[] = [];
|
||||||
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
||||||
actions.push({
|
actions.push({
|
||||||
id: QRCodeComponent.actionKeys.Copy,
|
id: actionKeys.Copy,
|
||||||
text: loc.transactions.details_copy,
|
text: loc.transactions.details_copy,
|
||||||
icon: QRCodeComponent.actionIcons.Copy,
|
icon: actionIcons.Copy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
actions.push({
|
actions.push({
|
||||||
id: QRCodeComponent.actionKeys.Share,
|
id: actionKeys.Share,
|
||||||
text: loc.receive.details_share,
|
text: loc.receive.details_share,
|
||||||
icon: QRCodeComponent.actionIcons.Share,
|
icon: actionIcons.Share,
|
||||||
});
|
});
|
||||||
return actions;
|
return actions;
|
||||||
};
|
};
|
||||||
|
@ -61,10 +107,11 @@ const QRCodeComponent = ({
|
||||||
size={size}
|
size={size}
|
||||||
logoSize={logoSize}
|
logoSize={logoSize}
|
||||||
color="#000000"
|
color="#000000"
|
||||||
|
// @ts-ignore: logoBackgroundColor is not in the type definition
|
||||||
logoBackgroundColor={colors.brandingColor}
|
logoBackgroundColor={colors.brandingColor}
|
||||||
backgroundColor="#FFFFFF"
|
backgroundColor="#FFFFFF"
|
||||||
ecl={ecl}
|
ecl={ecl}
|
||||||
getRef={qrCode}
|
getRef={(c: any) => (qrCode.current = c)}
|
||||||
onError={onError}
|
onError={onError}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -87,29 +134,3 @@ export default QRCodeComponent;
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
qrCodeContainer: { borderWidth: 6, borderRadius: 8, borderColor: '#FFFFFF' },
|
qrCodeContainer: { borderWidth: 6, borderRadius: 8, borderColor: '#FFFFFF' },
|
||||||
});
|
});
|
||||||
|
|
||||||
QRCodeComponent.actionKeys = {
|
|
||||||
Share: 'share',
|
|
||||||
Copy: 'copy',
|
|
||||||
};
|
|
||||||
|
|
||||||
QRCodeComponent.actionIcons = {
|
|
||||||
Share: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'square.and.arrow.up',
|
|
||||||
},
|
|
||||||
Copy: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'doc.on.doc',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
QRCodeComponent.propTypes = {
|
|
||||||
value: PropTypes.string.isRequired,
|
|
||||||
isMenuAvailable: PropTypes.bool,
|
|
||||||
size: PropTypes.number,
|
|
||||||
ecl: PropTypes.string,
|
|
||||||
isLogoRendered: PropTypes.bool,
|
|
||||||
onError: PropTypes.func,
|
|
||||||
logoSize: PropTypes.number,
|
|
||||||
};
|
|
|
@ -19,7 +19,7 @@ export const SquareButton = forwardRef((props, ref) => {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
borderWidth: 0.7,
|
borderWidth: 0.7,
|
||||||
borderColor: 'transparent',
|
borderColor: 'transparent',
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor,
|
||||||
minHeight: 50,
|
minHeight: 50,
|
||||||
height: 50,
|
height: 50,
|
||||||
maxHeight: 50,
|
maxHeight: 50,
|
||||||
|
|
|
@ -59,11 +59,18 @@ const ToolTipMenu = (props, ref) => {
|
||||||
}}
|
}}
|
||||||
style={buttonStyle}
|
style={buttonStyle}
|
||||||
>
|
>
|
||||||
{props.onPress ? <TouchableOpacity onPress={props.onPress}>{props.children}</TouchableOpacity> : props.children}
|
{props.onPress ? (
|
||||||
|
<TouchableOpacity accessibilityRole="button" onPress={props.onPress}>
|
||||||
|
{props.children}
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
props.children
|
||||||
|
)}
|
||||||
</ContextMenuButton>
|
</ContextMenuButton>
|
||||||
) : (
|
) : (
|
||||||
<ContextMenuView
|
<ContextMenuView
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
internalCleanupMode="viewController"
|
||||||
onPressMenuItem={({ nativeEvent }) => {
|
onPressMenuItem={({ nativeEvent }) => {
|
||||||
props.onPressMenuItem(nativeEvent.actionKey);
|
props.onPressMenuItem(nativeEvent.actionKey);
|
||||||
}}
|
}}
|
||||||
|
@ -81,7 +88,13 @@ const ToolTipMenu = (props, ref) => {
|
||||||
}
|
}
|
||||||
: {})}
|
: {})}
|
||||||
>
|
>
|
||||||
{props.onPress ? <TouchableOpacity onPress={props.onPress}>{props.children}</TouchableOpacity> : props.children}
|
{props.onPress ? (
|
||||||
|
<TouchableOpacity accessibilityRole="button" onPress={props.onPress}>
|
||||||
|
{props.children}
|
||||||
|
</TouchableOpacity>
|
||||||
|
) : (
|
||||||
|
props.children
|
||||||
|
)}
|
||||||
</ContextMenuView>
|
</ContextMenuView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,305 +0,0 @@
|
||||||
import React, { Component } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Image, Text, TouchableOpacity, View, InteractionManager, I18nManager, StyleSheet } from 'react-native';
|
|
||||||
import Clipboard from '@react-native-clipboard/clipboard';
|
|
||||||
import LinearGradient from 'react-native-linear-gradient';
|
|
||||||
import { LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet } from '../class';
|
|
||||||
import { BitcoinUnit } from '../models/bitcoinUnits';
|
|
||||||
import WalletGradient from '../class/wallet-gradient';
|
|
||||||
import Biometric from '../class/biometrics';
|
|
||||||
import loc, { formatBalance } from '../loc';
|
|
||||||
import { BlueStorageContext } from '../blue_modules/storage-context';
|
|
||||||
import ToolTipMenu from './TooltipMenu';
|
|
||||||
import { BluePrivateBalance } from '../BlueComponents';
|
|
||||||
|
|
||||||
export default class TransactionsNavigationHeader extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
wallet: PropTypes.shape().isRequired,
|
|
||||||
onWalletUnitChange: PropTypes.func,
|
|
||||||
navigation: PropTypes.shape(),
|
|
||||||
onManageFundsPressed: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
static actionKeys = {
|
|
||||||
CopyToClipboard: 'copyToClipboard',
|
|
||||||
WalletBalanceVisibility: 'walletBalanceVisibility',
|
|
||||||
Refill: 'refill',
|
|
||||||
RefillWithExternalWallet: 'qrcode',
|
|
||||||
};
|
|
||||||
|
|
||||||
static actionIcons = {
|
|
||||||
Eye: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'eye',
|
|
||||||
},
|
|
||||||
EyeSlash: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'eye.slash',
|
|
||||||
},
|
|
||||||
Clipboard: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'doc.on.doc',
|
|
||||||
},
|
|
||||||
Refill: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'goforward.plus',
|
|
||||||
},
|
|
||||||
RefillWithExternalWallet: {
|
|
||||||
iconType: 'SYSTEM',
|
|
||||||
iconValue: 'qrcode',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static getDerivedStateFromProps(props) {
|
|
||||||
return { wallet: props.wallet, onWalletUnitChange: props.onWalletUnitChange };
|
|
||||||
}
|
|
||||||
|
|
||||||
static contextType = BlueStorageContext;
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
wallet: props.wallet,
|
|
||||||
walletPreviousPreferredUnit: props.wallet.getPreferredBalanceUnit(),
|
|
||||||
allowOnchainAddress: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
menuRef = React.createRef();
|
|
||||||
|
|
||||||
handleCopyPress = _item => {
|
|
||||||
Clipboard.setString(formatBalance(this.state.wallet.getBalance(), this.state.wallet.getPreferredBalanceUnit()).toString());
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidUpdate(prevState) {
|
|
||||||
InteractionManager.runAfterInteractions(() => {
|
|
||||||
if (prevState.wallet.getID() !== this.state.wallet.getID() && this.state.wallet.type === LightningCustodianWallet.type) {
|
|
||||||
this.verifyIfWalletAllowsOnchainAddress();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
verifyIfWalletAllowsOnchainAddress = () => {
|
|
||||||
if (this.state.wallet.type === LightningCustodianWallet.type) {
|
|
||||||
this.state.wallet
|
|
||||||
.allowOnchainAddress()
|
|
||||||
.then(value => this.setState({ allowOnchainAddress: value }))
|
|
||||||
.catch(e => {
|
|
||||||
console.log('This Lndhub wallet does not have an onchain address API.');
|
|
||||||
this.setState({ allowOnchainAddress: false });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.verifyIfWalletAllowsOnchainAddress();
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBalanceVisibility = async _item => {
|
|
||||||
const wallet = this.state.wallet;
|
|
||||||
|
|
||||||
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
|
|
||||||
|
|
||||||
if (isBiometricsEnabled && wallet.hideBalance) {
|
|
||||||
if (!(await Biometric.unlockWithBiometrics())) {
|
|
||||||
return this.props.navigation.goBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wallet.hideBalance = !wallet.hideBalance;
|
|
||||||
this.setState({ wallet });
|
|
||||||
await this.context.saveToDisk();
|
|
||||||
};
|
|
||||||
|
|
||||||
changeWalletBalanceUnit = () => {
|
|
||||||
this.menuRef.current?.dismissMenu();
|
|
||||||
let walletPreviousPreferredUnit = this.state.wallet.getPreferredBalanceUnit();
|
|
||||||
const wallet = this.state.wallet;
|
|
||||||
if (walletPreviousPreferredUnit === BitcoinUnit.BTC) {
|
|
||||||
wallet.preferredBalanceUnit = BitcoinUnit.SATS;
|
|
||||||
walletPreviousPreferredUnit = BitcoinUnit.BTC;
|
|
||||||
} else if (walletPreviousPreferredUnit === BitcoinUnit.SATS) {
|
|
||||||
wallet.preferredBalanceUnit = BitcoinUnit.LOCAL_CURRENCY;
|
|
||||||
walletPreviousPreferredUnit = BitcoinUnit.SATS;
|
|
||||||
} else if (walletPreviousPreferredUnit === BitcoinUnit.LOCAL_CURRENCY) {
|
|
||||||
wallet.preferredBalanceUnit = BitcoinUnit.BTC;
|
|
||||||
walletPreviousPreferredUnit = BitcoinUnit.BTC;
|
|
||||||
} else {
|
|
||||||
wallet.preferredBalanceUnit = BitcoinUnit.BTC;
|
|
||||||
walletPreviousPreferredUnit = BitcoinUnit.BTC;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ wallet, walletPreviousPreferredUnit: walletPreviousPreferredUnit }, () => {
|
|
||||||
this.props.onWalletUnitChange(wallet);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
manageFundsPressed = id => {
|
|
||||||
this.props.onManageFundsPressed(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
onPressMenuItem = id => {
|
|
||||||
if (id === TransactionsNavigationHeader.actionKeys.WalletBalanceVisibility) {
|
|
||||||
this.handleBalanceVisibility();
|
|
||||||
} else if (id === TransactionsNavigationHeader.actionKeys.CopyToClipboard) {
|
|
||||||
this.handleCopyPress();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
toolTipMenuActions = [
|
|
||||||
{
|
|
||||||
id: TransactionsNavigationHeader.actionKeys.Refill,
|
|
||||||
text: loc.lnd.refill,
|
|
||||||
icon: TransactionsNavigationHeader.actionIcons.Refill,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TransactionsNavigationHeader.actionKeys.RefillWithExternalWallet,
|
|
||||||
text: loc.lnd.refill_external,
|
|
||||||
icon: TransactionsNavigationHeader.actionIcons.RefillWithExternalWallet,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const balance =
|
|
||||||
!this.state.wallet.hideBalance &&
|
|
||||||
formatBalance(this.state.wallet.getBalance(), this.state.wallet.getPreferredBalanceUnit(), true).toString();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LinearGradient
|
|
||||||
colors={WalletGradient.gradientsFor(this.state.wallet.type)}
|
|
||||||
style={styles.lineaderGradient}
|
|
||||||
{...WalletGradient.linearGradientProps(this.state.wallet.type)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
source={(() => {
|
|
||||||
switch (this.state.wallet.type) {
|
|
||||||
case LightningLdkWallet.type:
|
|
||||||
case LightningCustodianWallet.type:
|
|
||||||
return I18nManager.isRTL ? require('../img/lnd-shape-rtl.png') : require('../img/lnd-shape.png');
|
|
||||||
case MultisigHDWallet.type:
|
|
||||||
return I18nManager.isRTL ? require('../img/vault-shape-rtl.png') : require('../img/vault-shape.png');
|
|
||||||
default:
|
|
||||||
return I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png');
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
style={styles.chainIcon}
|
|
||||||
/>
|
|
||||||
<Text testID="WalletLabel" numberOfLines={1} style={styles.walletLabel}>
|
|
||||||
{this.state.wallet.getLabel()}
|
|
||||||
</Text>
|
|
||||||
<ToolTipMenu
|
|
||||||
onPress={this.changeWalletBalanceUnit}
|
|
||||||
ref={this.menuRef}
|
|
||||||
title={loc.wallets.balance}
|
|
||||||
onPressMenuItem={this.onPressMenuItem}
|
|
||||||
actions={
|
|
||||||
this.state.wallet.hideBalance
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
id: TransactionsNavigationHeader.actionKeys.WalletBalanceVisibility,
|
|
||||||
text: loc.transactions.details_balance_show,
|
|
||||||
icon: TransactionsNavigationHeader.actionIcons.Eye,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
id: TransactionsNavigationHeader.actionKeys.WalletBalanceVisibility,
|
|
||||||
text: loc.transactions.details_balance_hide,
|
|
||||||
icon: TransactionsNavigationHeader.actionIcons.EyeSlash,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: TransactionsNavigationHeader.actionKeys.CopyToClipboard,
|
|
||||||
text: loc.transactions.details_copy,
|
|
||||||
icon: TransactionsNavigationHeader.actionIcons.Clipboard,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<View style={styles.balance}>
|
|
||||||
{this.state.wallet.hideBalance ? (
|
|
||||||
<BluePrivateBalance />
|
|
||||||
) : (
|
|
||||||
<Text
|
|
||||||
testID="WalletBalance"
|
|
||||||
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
|
||||||
numberOfLines={1}
|
|
||||||
adjustsFontSizeToFit
|
|
||||||
style={styles.walletBalance}
|
|
||||||
>
|
|
||||||
{balance}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</ToolTipMenu>
|
|
||||||
{this.state.wallet.type === LightningCustodianWallet.type && this.state.allowOnchainAddress && (
|
|
||||||
<ToolTipMenu
|
|
||||||
isMenuPrimaryAction
|
|
||||||
isButton
|
|
||||||
onPressMenuItem={this.manageFundsPressed}
|
|
||||||
actions={this.toolTipMenuActions}
|
|
||||||
buttonStyle={styles.manageFundsButton}
|
|
||||||
>
|
|
||||||
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
|
||||||
</ToolTipMenu>
|
|
||||||
)}
|
|
||||||
{this.state.wallet.type === LightningLdkWallet.type && (
|
|
||||||
<TouchableOpacity accessibilityRole="button" onPress={this.manageFundsPressed}>
|
|
||||||
<View style={styles.manageFundsButton}>
|
|
||||||
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)}
|
|
||||||
{this.state.wallet.type === MultisigHDWallet.type && (
|
|
||||||
<TouchableOpacity accessibilityRole="button" onPress={this.manageFundsPressed}>
|
|
||||||
<View style={styles.manageFundsButton}>
|
|
||||||
<Text style={styles.manageFundsButtonText}>{loc.multisig.manage_keys}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)}
|
|
||||||
</LinearGradient>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
lineaderGradient: {
|
|
||||||
padding: 15,
|
|
||||||
minHeight: 140,
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
chainIcon: {
|
|
||||||
width: 99,
|
|
||||||
height: 94,
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 0,
|
|
||||||
right: 0,
|
|
||||||
},
|
|
||||||
walletLabel: {
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
fontSize: 19,
|
|
||||||
color: '#fff',
|
|
||||||
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
|
||||||
},
|
|
||||||
walletBalance: {
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontSize: 36,
|
|
||||||
color: '#fff',
|
|
||||||
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
|
||||||
},
|
|
||||||
manageFundsButton: {
|
|
||||||
marginTop: 14,
|
|
||||||
marginBottom: 10,
|
|
||||||
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
||||||
borderRadius: 9,
|
|
||||||
minHeight: 39,
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
manageFundsButtonText: {
|
|
||||||
fontWeight: '500',
|
|
||||||
fontSize: 14,
|
|
||||||
color: '#FFFFFF',
|
|
||||||
padding: 12,
|
|
||||||
},
|
|
||||||
});
|
|
315
components/TransactionsNavigationHeader.tsx
Normal file
315
components/TransactionsNavigationHeader.tsx
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
import React, { useState, useEffect, useRef, useContext, useCallback, useMemo } from 'react';
|
||||||
|
import { Image, Text, TouchableOpacity, View, I18nManager, StyleSheet } from 'react-native';
|
||||||
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
|
import { AbstractWallet, LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet } from '../class';
|
||||||
|
import { BitcoinUnit } from '../models/bitcoinUnits';
|
||||||
|
import WalletGradient from '../class/wallet-gradient';
|
||||||
|
import Biometric from '../class/biometrics';
|
||||||
|
import loc, { formatBalance } from '../loc';
|
||||||
|
import { BlueStorageContext } from '../blue_modules/storage-context';
|
||||||
|
import ToolTipMenu from './TooltipMenu';
|
||||||
|
import { BluePrivateBalance } from '../BlueComponents';
|
||||||
|
|
||||||
|
interface TransactionsNavigationHeaderProps {
|
||||||
|
wallet: AbstractWallet;
|
||||||
|
onWalletUnitChange?: (wallet: any) => void;
|
||||||
|
navigation: {
|
||||||
|
navigate: (route: string, params?: any) => void;
|
||||||
|
goBack: () => void;
|
||||||
|
};
|
||||||
|
onManageFundsPressed?: (id: string) => void; // Add a type definition for this prop
|
||||||
|
actionKeys: {
|
||||||
|
CopyToClipboard: 'copyToClipboard';
|
||||||
|
WalletBalanceVisibility: 'walletBalanceVisibility';
|
||||||
|
Refill: 'refill';
|
||||||
|
RefillWithExternalWallet: 'qrcode';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps> = ({
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
wallet: initialWallet,
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
onWalletUnitChange,
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
navigation,
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
onManageFundsPressed,
|
||||||
|
}) => {
|
||||||
|
const [wallet, setWallet] = useState(initialWallet);
|
||||||
|
const [allowOnchainAddress, setAllowOnchainAddress] = useState(false);
|
||||||
|
|
||||||
|
const context = useContext(BlueStorageContext);
|
||||||
|
const menuRef = useRef(null);
|
||||||
|
|
||||||
|
const verifyIfWalletAllowsOnchainAddress = useCallback(() => {
|
||||||
|
if (wallet.type === LightningCustodianWallet.type) {
|
||||||
|
wallet
|
||||||
|
.allowOnchainAddress()
|
||||||
|
.then((value: boolean) => setAllowOnchainAddress(value))
|
||||||
|
.catch((e: any) => {
|
||||||
|
console.log('This Lndhub wallet does not have an onchain address API.');
|
||||||
|
setAllowOnchainAddress(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [wallet]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
verifyIfWalletAllowsOnchainAddress();
|
||||||
|
}, [wallet, verifyIfWalletAllowsOnchainAddress]);
|
||||||
|
|
||||||
|
const handleCopyPress = () => {
|
||||||
|
Clipboard.setString(formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit()).toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateWalletVisibility = (wallet: AbstractWallet, newHideBalance: boolean) => {
|
||||||
|
wallet.hideBalance = newHideBalance;
|
||||||
|
return wallet;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBalanceVisibility = async () => {
|
||||||
|
// @ts-ignore: Gotta update this class
|
||||||
|
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
|
||||||
|
|
||||||
|
if (isBiometricsEnabled && wallet.hideBalance) {
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
if (!(await Biometric.unlockWithBiometrics())) {
|
||||||
|
return navigation.goBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedWallet = updateWalletVisibility(wallet, !wallet.hideBalance);
|
||||||
|
setWallet(updatedWallet);
|
||||||
|
context.saveToDisk();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateWalletWithNewUnit = (wallet: AbstractWallet, newPreferredUnit: BitcoinUnit) => {
|
||||||
|
wallet.preferredBalanceUnit = newPreferredUnit;
|
||||||
|
return wallet;
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeWalletBalanceUnit = () => {
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
menuRef.current?.dismissMenu();
|
||||||
|
let newWalletPreferredUnit = wallet.getPreferredBalanceUnit();
|
||||||
|
|
||||||
|
if (newWalletPreferredUnit === BitcoinUnit.BTC) {
|
||||||
|
newWalletPreferredUnit = BitcoinUnit.SATS;
|
||||||
|
} else if (newWalletPreferredUnit === BitcoinUnit.SATS) {
|
||||||
|
newWalletPreferredUnit = BitcoinUnit.LOCAL_CURRENCY;
|
||||||
|
} else {
|
||||||
|
newWalletPreferredUnit = BitcoinUnit.BTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedWallet = updateWalletWithNewUnit(wallet, newWalletPreferredUnit);
|
||||||
|
setWallet(updatedWallet);
|
||||||
|
onWalletUnitChange?.(updatedWallet);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleManageFundsPressed = () => {
|
||||||
|
onManageFundsPressed?.(actionKeys.Refill);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onPressMenuItem = (id: string) => {
|
||||||
|
if (id === 'walletBalanceVisibility') {
|
||||||
|
handleBalanceVisibility();
|
||||||
|
} else if (id === 'copyToClipboard') {
|
||||||
|
handleCopyPress();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const balance = useMemo(() => {
|
||||||
|
const hideBalance = wallet.hideBalance;
|
||||||
|
const balanceUnit = wallet.getPreferredBalanceUnit();
|
||||||
|
const balanceFormatted = formatBalance(wallet.getBalance(), balanceUnit, true).toString();
|
||||||
|
return !hideBalance && balanceFormatted;
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LinearGradient
|
||||||
|
colors={WalletGradient.gradientsFor(wallet.type)}
|
||||||
|
style={styles.lineaderGradient}
|
||||||
|
// @ts-ignore: Ugh
|
||||||
|
{...WalletGradient.linearGradientProps(wallet.type)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
source={(() => {
|
||||||
|
switch (wallet.type) {
|
||||||
|
case LightningLdkWallet.type:
|
||||||
|
case LightningCustodianWallet.type:
|
||||||
|
return I18nManager.isRTL ? require('../img/lnd-shape-rtl.png') : require('../img/lnd-shape.png');
|
||||||
|
case MultisigHDWallet.type:
|
||||||
|
return I18nManager.isRTL ? require('../img/vault-shape-rtl.png') : require('../img/vault-shape.png');
|
||||||
|
default:
|
||||||
|
return I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png');
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
style={styles.chainIcon}
|
||||||
|
/>
|
||||||
|
<Text testID="WalletLabel" numberOfLines={1} style={styles.walletLabel}>
|
||||||
|
{wallet.getLabel()}
|
||||||
|
</Text>
|
||||||
|
<ToolTipMenu
|
||||||
|
onPress={changeWalletBalanceUnit}
|
||||||
|
ref={menuRef}
|
||||||
|
title={loc.wallets.balance}
|
||||||
|
onPressMenuItem={onPressMenuItem}
|
||||||
|
actions={
|
||||||
|
wallet.hideBalance
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: 'walletBalanceVisibility',
|
||||||
|
text: loc.transactions.details_balance_show,
|
||||||
|
icon: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'eye',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
id: 'walletBalanceVisibility',
|
||||||
|
text: loc.transactions.details_balance_hide,
|
||||||
|
icon: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'eye.slash',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'copyToClipboard',
|
||||||
|
text: loc.transactions.details_copy,
|
||||||
|
icon: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'doc.on.doc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View style={styles.walletBalance}>
|
||||||
|
{wallet.hideBalance ? (
|
||||||
|
<BluePrivateBalance />
|
||||||
|
) : (
|
||||||
|
<Text
|
||||||
|
testID="WalletBalance"
|
||||||
|
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||||
|
numberOfLines={1}
|
||||||
|
adjustsFontSizeToFit
|
||||||
|
style={styles.walletBalance}
|
||||||
|
>
|
||||||
|
{balance}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</ToolTipMenu>
|
||||||
|
{wallet.type === LightningCustodianWallet.type && allowOnchainAddress && (
|
||||||
|
<ToolTipMenu
|
||||||
|
isMenuPrimaryAction
|
||||||
|
isButton
|
||||||
|
onPressMenuItem={handleManageFundsPressed}
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
id: actionKeys.Refill,
|
||||||
|
text: loc.lnd.refill,
|
||||||
|
icon: actionIcons.Refill,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: actionKeys.RefillWithExternalWallet,
|
||||||
|
text: loc.lnd.refill_external,
|
||||||
|
icon: actionIcons.RefillWithExternalWallet,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
buttonStyle={styles.manageFundsButton}
|
||||||
|
>
|
||||||
|
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
||||||
|
</ToolTipMenu>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{wallet.type === MultisigHDWallet.type && (
|
||||||
|
<TouchableOpacity accessibilityRole="button" onPress={handleManageFundsPressed}>
|
||||||
|
<View style={styles.manageFundsButton}>
|
||||||
|
<Text style={styles.manageFundsButtonText}>{loc.multisig.manage_keys}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
</LinearGradient>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
lineaderGradient: {
|
||||||
|
padding: 15,
|
||||||
|
minHeight: 140,
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
chainIcon: {
|
||||||
|
width: 99,
|
||||||
|
height: 94,
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
},
|
||||||
|
walletLabel: {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
fontSize: 19,
|
||||||
|
color: '#fff',
|
||||||
|
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
||||||
|
},
|
||||||
|
walletBalance: {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
fontSize: 36,
|
||||||
|
color: '#fff',
|
||||||
|
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
||||||
|
},
|
||||||
|
manageFundsButton: {
|
||||||
|
marginTop: 14,
|
||||||
|
marginBottom: 10,
|
||||||
|
backgroundColor: 'rgba(255,255,255,0.2)',
|
||||||
|
borderRadius: 9,
|
||||||
|
minHeight: 39,
|
||||||
|
alignSelf: 'flex-start',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
manageFundsButtonText: {
|
||||||
|
fontWeight: '500',
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#FFFFFF',
|
||||||
|
padding: 12,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const actionKeys = {
|
||||||
|
CopyToClipboard: 'copyToClipboard',
|
||||||
|
WalletBalanceVisibility: 'walletBalanceVisibility',
|
||||||
|
Refill: 'refill',
|
||||||
|
RefillWithExternalWallet: 'qrcode',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actionIcons = {
|
||||||
|
Eye: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'eye',
|
||||||
|
},
|
||||||
|
EyeSlash: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'eye.slash',
|
||||||
|
},
|
||||||
|
Clipboard: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'doc.on.doc',
|
||||||
|
},
|
||||||
|
Refill: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'goforward.plus',
|
||||||
|
},
|
||||||
|
RefillWithExternalWallet: {
|
||||||
|
iconType: 'SYSTEM',
|
||||||
|
iconValue: 'qrcode',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TransactionsNavigationHeader;
|
|
@ -203,6 +203,7 @@ const WalletCarouselItem = ({ item, index, onPress, handleLongPress, isSelectedW
|
||||||
shadowRadius={8}
|
shadowRadius={8}
|
||||||
>
|
>
|
||||||
<TouchableWithoutFeedback
|
<TouchableWithoutFeedback
|
||||||
|
accessibilityRole="button"
|
||||||
testID={item.getLabel()}
|
testID={item.getLabel()}
|
||||||
onPressIn={onPressedIn}
|
onPressIn={onPressedIn}
|
||||||
onPressOut={onPressedOut}
|
onPressOut={onPressedOut}
|
||||||
|
@ -311,7 +312,7 @@ const WalletsCarousel = forwardRef((props, ref) => {
|
||||||
const { width } = useWindowDimensions();
|
const { width } = useWindowDimensions();
|
||||||
const sliderHeight = 195;
|
const sliderHeight = 195;
|
||||||
const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82;
|
const itemWidth = width * 0.82 > 375 ? 375 : width * 0.82;
|
||||||
return (
|
return isHandset ? (
|
||||||
<FlatList
|
<FlatList
|
||||||
ref={flatListRef}
|
ref={flatListRef}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
|
@ -331,6 +332,19 @@ const WalletsCarousel = forwardRef((props, ref) => {
|
||||||
onScrollToIndexFailed={onScrollToIndexFailed}
|
onScrollToIndexFailed={onScrollToIndexFailed}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<View style={cStyles.contentLargeScreen}>
|
||||||
|
{props.data.map((item, index) => (
|
||||||
|
<WalletCarouselItem
|
||||||
|
isSelectedWallet={!props.horizontal && props.selectedWallet && item ? props.selectedWallet === item.getID() : undefined}
|
||||||
|
item={item}
|
||||||
|
index={index}
|
||||||
|
handleLongPress={props.handleLongPress}
|
||||||
|
onPress={props.onPress}
|
||||||
|
key={index}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import React, { useContext } from 'react';
|
|
||||||
import Handoff from 'react-native-handoff';
|
|
||||||
import { BlueStorageContext } from '../blue_modules/storage-context';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const HandoffComponent = props => {
|
|
||||||
const { isHandOffUseEnabled } = useContext(BlueStorageContext);
|
|
||||||
|
|
||||||
return isHandOffUseEnabled ? <Handoff {...props} /> : null;
|
|
||||||
};
|
|
||||||
export default HandoffComponent;
|
|
||||||
|
|
||||||
HandoffComponent.propTypes = {
|
|
||||||
url: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
HandoffComponent.activityTypes = {
|
|
||||||
ReceiveOnchain: 'io.bluewallet.bluewallet.receiveonchain',
|
|
||||||
Xpub: 'io.bluewallet.bluewallet.xpub',
|
|
||||||
ViewInBlockExplorer: 'io.bluewallet.bluewallet.blockexplorer',
|
|
||||||
};
|
|
35
components/handoff.tsx
Normal file
35
components/handoff.tsx
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import React, { useContext } from 'react';
|
||||||
|
// @ts-ignore: react-native-handoff is not in the type definition
|
||||||
|
import Handoff from 'react-native-handoff';
|
||||||
|
import { BlueStorageContext } from '../blue_modules/storage-context';
|
||||||
|
|
||||||
|
interface HandoffComponentProps {
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HandoffComponentWithActivityTypes extends React.FC<HandoffComponentProps> {
|
||||||
|
activityTypes: {
|
||||||
|
ReceiveOnchain: string;
|
||||||
|
Xpub: string;
|
||||||
|
ViewInBlockExplorer: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const HandoffComponent: HandoffComponentWithActivityTypes = props => {
|
||||||
|
const { isHandOffUseEnabled } = useContext(BlueStorageContext);
|
||||||
|
|
||||||
|
if (isHandOffUseEnabled) {
|
||||||
|
return <Handoff {...props} />;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const activityTypes = {
|
||||||
|
ReceiveOnchain: 'io.bluewallet.bluewallet.receiveonchain',
|
||||||
|
Xpub: 'io.bluewallet.bluewallet.xpub',
|
||||||
|
ViewInBlockExplorer: 'io.bluewallet.bluewallet.blockexplorer',
|
||||||
|
};
|
||||||
|
|
||||||
|
HandoffComponent.activityTypes = activityTypes;
|
||||||
|
|
||||||
|
export default HandoffComponent;
|
|
@ -2,6 +2,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Image, Keyboard, TouchableOpacity, StyleSheet } from 'react-native';
|
import { Image, Keyboard, TouchableOpacity, StyleSheet } from 'react-native';
|
||||||
import { Theme } from './themes';
|
import { Theme } from './themes';
|
||||||
|
import loc from '../loc';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
|
@ -41,6 +42,7 @@ const navigationStyle = (
|
||||||
...opts
|
...opts
|
||||||
}: NavigationOptions & {
|
}: NavigationOptions & {
|
||||||
closeButton?: boolean;
|
closeButton?: boolean;
|
||||||
|
|
||||||
closeButtonFunc?: (deps: { navigation: any; route: any }) => React.ReactElement;
|
closeButtonFunc?: (deps: { navigation: any; route: any }) => React.ReactElement;
|
||||||
},
|
},
|
||||||
formatter: OptionsFormatter,
|
formatter: OptionsFormatter,
|
||||||
|
@ -56,7 +58,13 @@ const navigationStyle = (
|
||||||
navigation.goBack(null);
|
navigation.goBack(null);
|
||||||
};
|
};
|
||||||
headerRight = () => (
|
headerRight = () => (
|
||||||
<TouchableOpacity accessibilityRole="button" style={styles.button} onPress={handleClose} testID="NavigationCloseButton">
|
<TouchableOpacity
|
||||||
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc._.close}
|
||||||
|
style={styles.button}
|
||||||
|
onPress={handleClose}
|
||||||
|
testID="NavigationCloseButton"
|
||||||
|
>
|
||||||
<Image source={theme.closeImage} />
|
<Image source={theme.closeImage} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
@ -73,7 +81,7 @@ const navigationStyle = (
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
color: theme.colors.foregroundColor,
|
color: theme.colors.foregroundColor,
|
||||||
},
|
},
|
||||||
headerRight: headerRight,
|
headerRight,
|
||||||
headerBackTitleVisible: false,
|
headerBackTitleVisible: false,
|
||||||
headerTintColor: theme.colors.foregroundColor,
|
headerTintColor: theme.colors.foregroundColor,
|
||||||
...opts,
|
...opts,
|
||||||
|
@ -108,6 +116,7 @@ export const navigationStyleTx = (opts: NavigationOptions, formatter: OptionsFor
|
||||||
headerLeft: () => (
|
headerLeft: () => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
|
accessibilityLabel={loc._.close}
|
||||||
style={styles.button}
|
style={styles.button}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
|
|
|
@ -47,7 +47,7 @@ module.exports = (
|
||||||
];
|
];
|
||||||
|
|
||||||
prompt(title, text, buttons, {
|
prompt(title, text, buttons, {
|
||||||
type: type,
|
type,
|
||||||
cancelable: isCancelable,
|
cancelable: isCancelable,
|
||||||
// @ts-ignore suppressed because its supported only on ios and is absent from type definitions
|
// @ts-ignore suppressed because its supported only on ios and is absent from type definitions
|
||||||
keyboardType,
|
keyboardType,
|
||||||
|
|
1
ios/.xcode.env
Normal file
1
ios/.xcode.env
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export NODE_BINARY=$(command -v node)
|
|
@ -7,7 +7,6 @@
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
|
||||||
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||||
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||||
32002D9D236FAA9F00B93396 /* TodayDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32002D9C236FAA9F00B93396 /* TodayDataStore.swift */; };
|
32002D9D236FAA9F00B93396 /* TodayDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32002D9C236FAA9F00B93396 /* TodayDataStore.swift */; };
|
||||||
|
@ -56,7 +55,6 @@
|
||||||
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B9D9B3A7B2CB4255876B67AF /* libz.tbd */; };
|
782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B9D9B3A7B2CB4255876B67AF /* libz.tbd */; };
|
||||||
849047CA2702A32A008EE567 /* Handoff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849047C92702A32A008EE567 /* Handoff.swift */; };
|
849047CA2702A32A008EE567 /* Handoff.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849047C92702A32A008EE567 /* Handoff.swift */; };
|
||||||
84E05A842721191B001A0D3A /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 84E05A832721191B001A0D3A /* Settings.bundle */; };
|
84E05A842721191B001A0D3A /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 84E05A832721191B001A0D3A /* Settings.bundle */; };
|
||||||
8CBB9CC9ACE4B44B45C28DF8 /* libPods-WidgetsExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E45F9A25C15BEA362225C9B /* libPods-WidgetsExtension.a */; };
|
|
||||||
906451CAD44154C2950030EC /* libPods-BlueWallet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 731973BA0AC6EA78962CE5B6 /* libPods-BlueWallet.a */; };
|
906451CAD44154C2950030EC /* libPods-BlueWallet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 731973BA0AC6EA78962CE5B6 /* libPods-BlueWallet.a */; };
|
||||||
B40D4E34225841EC00428FCC /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E32225841EC00428FCC /* Interface.storyboard */; };
|
B40D4E34225841EC00428FCC /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E32225841EC00428FCC /* Interface.storyboard */; };
|
||||||
B40D4E36225841ED00428FCC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
B40D4E36225841ED00428FCC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
||||||
|
@ -70,12 +68,14 @@
|
||||||
B40D4E632258425500428FCC /* ReceiveInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D4E5B2258425500428FCC /* ReceiveInterfaceController.swift */; };
|
B40D4E632258425500428FCC /* ReceiveInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D4E5B2258425500428FCC /* ReceiveInterfaceController.swift */; };
|
||||||
B40D4E642258425500428FCC /* WalletDetailsInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D4E5C2258425500428FCC /* WalletDetailsInterfaceController.swift */; };
|
B40D4E642258425500428FCC /* WalletDetailsInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D4E5C2258425500428FCC /* WalletDetailsInterfaceController.swift */; };
|
||||||
B40D4E682258426B00428FCC /* KeychainSwiftDistrib.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D4E672258426B00428FCC /* KeychainSwiftDistrib.swift */; };
|
B40D4E682258426B00428FCC /* KeychainSwiftDistrib.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40D4E672258426B00428FCC /* KeychainSwiftDistrib.swift */; };
|
||||||
|
B40FC3FA29CCD1D00007EBAC /* SwiftTCPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40FC3F829CCD1AC0007EBAC /* SwiftTCPClient.swift */; };
|
||||||
B43D0378225847C500FBAA95 /* WalletGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0372225847C500FBAA95 /* WalletGradient.swift */; };
|
B43D0378225847C500FBAA95 /* WalletGradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0372225847C500FBAA95 /* WalletGradient.swift */; };
|
||||||
B43D0379225847C500FBAA95 /* WatchDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0373225847C500FBAA95 /* WatchDataSource.swift */; };
|
B43D0379225847C500FBAA95 /* WatchDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0373225847C500FBAA95 /* WatchDataSource.swift */; };
|
||||||
B43D037A225847C500FBAA95 /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0374225847C500FBAA95 /* Transaction.swift */; };
|
B43D037A225847C500FBAA95 /* Transaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0374225847C500FBAA95 /* Transaction.swift */; };
|
||||||
B43D037B225847C500FBAA95 /* TransactionTableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0375225847C500FBAA95 /* TransactionTableRow.swift */; };
|
B43D037B225847C500FBAA95 /* TransactionTableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0375225847C500FBAA95 /* TransactionTableRow.swift */; };
|
||||||
B43D037C225847C500FBAA95 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0376225847C500FBAA95 /* Wallet.swift */; };
|
B43D037C225847C500FBAA95 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0376225847C500FBAA95 /* Wallet.swift */; };
|
||||||
B43D037D225847C500FBAA95 /* WalletInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0377225847C500FBAA95 /* WalletInformation.swift */; };
|
B43D037D225847C500FBAA95 /* WalletInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0377225847C500FBAA95 /* WalletInformation.swift */; };
|
||||||
|
B461B852299599F800E431AA /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = B461B851299599F800E431AA /* AppDelegate.mm */; };
|
||||||
B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
||||||
E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
||||||
E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
||||||
|
@ -170,8 +170,6 @@
|
||||||
00E356F21AD99517003FC87E /* BlueWalletTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlueWalletTests.m; sourceTree = "<group>"; };
|
00E356F21AD99517003FC87E /* BlueWalletTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlueWalletTests.m; sourceTree = "<group>"; };
|
||||||
04466491BA2D4876A71222FC /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
|
04466491BA2D4876A71222FC /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
|
||||||
13B07F961A680F5B00A75B9A /* BlueWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BlueWallet.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
13B07F961A680F5B00A75B9A /* BlueWallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BlueWallet.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = BlueWallet/AppDelegate.h; sourceTree = "<group>"; };
|
|
||||||
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = BlueWallet/AppDelegate.m; sourceTree = "<group>"; };
|
|
||||||
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = BlueWallet/Images.xcassets; sourceTree = "<group>"; };
|
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = BlueWallet/Images.xcassets; sourceTree = "<group>"; };
|
||||||
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BlueWallet/Info.plist; sourceTree = "<group>"; };
|
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BlueWallet/Info.plist; sourceTree = "<group>"; };
|
||||||
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = BlueWallet/main.m; sourceTree = "<group>"; };
|
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = BlueWallet/main.m; sourceTree = "<group>"; };
|
||||||
|
@ -290,12 +288,10 @@
|
||||||
78A87E7251D94144A71A2F67 /* FontAwesome5_Solid.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Solid.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf"; sourceTree = "<group>"; };
|
78A87E7251D94144A71A2F67 /* FontAwesome5_Solid.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = FontAwesome5_Solid.ttf; path = "../node_modules/react-native-vector-icons/Fonts/FontAwesome5_Solid.ttf"; sourceTree = "<group>"; };
|
||||||
7B468CC34D5B41F3950078EF /* libsqlite3.0.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
|
7B468CC34D5B41F3950078EF /* libsqlite3.0.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
|
||||||
7BAA8F97E61B677D33CF1944 /* Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-WalletInformationAndMarketWidgetExtension/Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig"; sourceTree = "<group>"; };
|
7BAA8F97E61B677D33CF1944 /* Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-WalletInformationAndMarketWidgetExtension/Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
7E45F9A25C15BEA362225C9B /* libPods-WidgetsExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-WidgetsExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
8448882949434D41A054C0B2 /* ToolTipMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = ToolTipMenuTests.xctest; sourceTree = "<group>"; };
|
8448882949434D41A054C0B2 /* ToolTipMenuTests.xctest */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = ToolTipMenuTests.xctest; sourceTree = "<group>"; };
|
||||||
849047C92702A32A008EE567 /* Handoff.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Handoff.swift; sourceTree = "<group>"; };
|
849047C92702A32A008EE567 /* Handoff.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Handoff.swift; sourceTree = "<group>"; };
|
||||||
84E05A832721191B001A0D3A /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
84E05A832721191B001A0D3A /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
|
||||||
8637D4B5E14D443A9031DA95 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
8637D4B5E14D443A9031DA95 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
||||||
8C30FBCA42C6BF0B45757763 /* Pods-WidgetsExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WidgetsExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WidgetsExtension/Pods-WidgetsExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
90F86BC5194548CA87D729A9 /* libToolTipMenu.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libToolTipMenu.a; sourceTree = "<group>"; };
|
90F86BC5194548CA87D729A9 /* libToolTipMenu.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libToolTipMenu.a; sourceTree = "<group>"; };
|
||||||
94565BFC6A0C4235B3EC7B01 /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSVG.a; sourceTree = "<group>"; };
|
94565BFC6A0C4235B3EC7B01 /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSVG.a; sourceTree = "<group>"; };
|
||||||
95208B2A05884A76B5BB99C0 /* libRCTGoogleAnalyticsBridge.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTGoogleAnalyticsBridge.a; sourceTree = "<group>"; };
|
95208B2A05884A76B5BB99C0 /* libRCTGoogleAnalyticsBridge.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTGoogleAnalyticsBridge.a; sourceTree = "<group>"; };
|
||||||
|
@ -322,6 +318,7 @@
|
||||||
B40D4E5B2258425500428FCC /* ReceiveInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveInterfaceController.swift; sourceTree = "<group>"; };
|
B40D4E5B2258425500428FCC /* ReceiveInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveInterfaceController.swift; sourceTree = "<group>"; };
|
||||||
B40D4E5C2258425500428FCC /* WalletDetailsInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletDetailsInterfaceController.swift; sourceTree = "<group>"; };
|
B40D4E5C2258425500428FCC /* WalletDetailsInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletDetailsInterfaceController.swift; sourceTree = "<group>"; };
|
||||||
B40D4E672258426B00428FCC /* KeychainSwiftDistrib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainSwiftDistrib.swift; sourceTree = SOURCE_ROOT; };
|
B40D4E672258426B00428FCC /* KeychainSwiftDistrib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainSwiftDistrib.swift; sourceTree = SOURCE_ROOT; };
|
||||||
|
B40FC3F829CCD1AC0007EBAC /* SwiftTCPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTCPClient.swift; sourceTree = "<group>"; };
|
||||||
B43B69B8225C462E00925B1E /* libPods-RCTLinking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-RCTLinking.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
B43B69B8225C462E00925B1E /* libPods-RCTLinking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-RCTLinking.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B43B69BA225C46D800925B1E /* libRCTLinking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRCTLinking.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
B43B69BA225C46D800925B1E /* libRCTLinking.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRCTLinking.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B43D0372225847C500FBAA95 /* WalletGradient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletGradient.swift; sourceTree = "<group>"; };
|
B43D0372225847C500FBAA95 /* WalletGradient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletGradient.swift; sourceTree = "<group>"; };
|
||||||
|
@ -332,6 +329,8 @@
|
||||||
B43D0377225847C500FBAA95 /* WalletInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletInformation.swift; sourceTree = "<group>"; };
|
B43D0377225847C500FBAA95 /* WalletInformation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletInformation.swift; sourceTree = "<group>"; };
|
||||||
B43D046E22584C1B00FBAA95 /* libRNWatch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRNWatch.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
B43D046E22584C1B00FBAA95 /* libRNWatch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libRNWatch.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B459EE96941AE09BCB547DC0 /* Pods-BlueWallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWallet.release.xcconfig"; path = "Pods/Target Support Files/Pods-BlueWallet/Pods-BlueWallet.release.xcconfig"; sourceTree = "<group>"; };
|
B459EE96941AE09BCB547DC0 /* Pods-BlueWallet.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BlueWallet.release.xcconfig"; path = "Pods/Target Support Files/Pods-BlueWallet/Pods-BlueWallet.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
B461B850299599F800E431AA /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = BlueWallet/AppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
B461B851299599F800E431AA /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = BlueWallet/AppDelegate.mm; sourceTree = "<group>"; };
|
||||||
B4D3235A177F4580BA52F2F9 /* libRNCSlider.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCSlider.a; sourceTree = "<group>"; };
|
B4D3235A177F4580BA52F2F9 /* libRNCSlider.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNCSlider.a; sourceTree = "<group>"; };
|
||||||
B642AFB13483418CAB6FF25E /* libRCTQRCodeLocalImage.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTQRCodeLocalImage.a; sourceTree = "<group>"; };
|
B642AFB13483418CAB6FF25E /* libRCTQRCodeLocalImage.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTQRCodeLocalImage.a; sourceTree = "<group>"; };
|
||||||
B9D9B3A7B2CB4255876B67AF /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
B9D9B3A7B2CB4255876B67AF /* libz.tbd */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
|
||||||
|
@ -340,7 +339,6 @@
|
||||||
CA741BA794714D3F80251AC9 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
|
CA741BA794714D3F80251AC9 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
|
||||||
CD746B955C55410793BB72C0 /* libRNGestureHandler.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNGestureHandler.a; sourceTree = "<group>"; };
|
CD746B955C55410793BB72C0 /* libRNGestureHandler.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNGestureHandler.a; sourceTree = "<group>"; };
|
||||||
CF4A4D7AAD974D67A2D62B3E /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
|
CF4A4D7AAD974D67A2D62B3E /* MaterialIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialIcons.ttf"; sourceTree = "<group>"; };
|
||||||
E0A230940404CA7C51FBED37 /* Pods-WidgetsExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WidgetsExtension.release.xcconfig"; path = "Pods/Target Support Files/Pods-WidgetsExtension/Pods-WidgetsExtension.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
E6B44173A8854B6D85D7F933 /* libRNVectorIcons-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNVectorIcons-tvOS.a"; sourceTree = "<group>"; };
|
E6B44173A8854B6D85D7F933 /* libRNVectorIcons-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNVectorIcons-tvOS.a"; sourceTree = "<group>"; };
|
||||||
E8E8CE89B3D142C6A8A56C34 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = "<group>"; };
|
E8E8CE89B3D142C6A8A56C34 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = "<group>"; };
|
||||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||||
|
@ -384,7 +382,6 @@
|
||||||
files = (
|
files = (
|
||||||
6DD4109E266CADF10087DE03 /* SwiftUI.framework in Frameworks */,
|
6DD4109E266CADF10087DE03 /* SwiftUI.framework in Frameworks */,
|
||||||
6DD4109D266CADF10087DE03 /* WidgetKit.framework in Frameworks */,
|
6DD4109D266CADF10087DE03 /* WidgetKit.framework in Frameworks */,
|
||||||
8CBB9CC9ACE4B44B45C28DF8 /* libPods-WidgetsExtension.a in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -426,11 +423,11 @@
|
||||||
13B07FAE1A68108700A75B9A /* BlueWallet */ = {
|
13B07FAE1A68108700A75B9A /* BlueWallet */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
B461B850299599F800E431AA /* AppDelegate.h */,
|
||||||
|
B461B851299599F800E431AA /* AppDelegate.mm */,
|
||||||
32C7944323B8879D00BE2AFA /* BlueWalletRelease.entitlements */,
|
32C7944323B8879D00BE2AFA /* BlueWalletRelease.entitlements */,
|
||||||
32F0A2502310B0910095C559 /* BlueWallet.entitlements */,
|
32F0A2502310B0910095C559 /* BlueWallet.entitlements */,
|
||||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
|
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
|
||||||
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
|
|
||||||
13B07FB01A68108700A75B9A /* AppDelegate.m */,
|
|
||||||
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
13B07FB51A68108700A75B9A /* Images.xcassets */,
|
||||||
13B07FB61A68108700A75B9A /* Info.plist */,
|
13B07FB61A68108700A75B9A /* Info.plist */,
|
||||||
13B07FB71A68108700A75B9A /* main.m */,
|
13B07FB71A68108700A75B9A /* main.m */,
|
||||||
|
@ -463,7 +460,6 @@
|
||||||
6D333B3C252FE1A3004D72DF /* SwiftUI.framework */,
|
6D333B3C252FE1A3004D72DF /* SwiftUI.framework */,
|
||||||
98455D960744E4E5DD50BA87 /* libPods-WalletInformationAndMarketWidgetExtension.a */,
|
98455D960744E4E5DD50BA87 /* libPods-WalletInformationAndMarketWidgetExtension.a */,
|
||||||
41BD3AC9FD81723B68A63C12 /* libPods-MarketWidgetExtension.a */,
|
41BD3AC9FD81723B68A63C12 /* libPods-MarketWidgetExtension.a */,
|
||||||
7E45F9A25C15BEA362225C9B /* libPods-WidgetsExtension.a */,
|
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -583,6 +579,7 @@
|
||||||
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */,
|
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */,
|
||||||
6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */,
|
6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */,
|
||||||
6D4AF18225D215D0009DD853 /* BlueWalletWatch-Bridging-Header.h */,
|
6D4AF18225D215D0009DD853 /* BlueWalletWatch-Bridging-Header.h */,
|
||||||
|
B40FC3F829CCD1AC0007EBAC /* SwiftTCPClient.swift */,
|
||||||
);
|
);
|
||||||
path = Shared;
|
path = Shared;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -641,8 +638,6 @@
|
||||||
FF45EB303C9601ED114589A4 /* Pods-MarketWidgetExtension.release.xcconfig */,
|
FF45EB303C9601ED114589A4 /* Pods-MarketWidgetExtension.release.xcconfig */,
|
||||||
AA7DCFB2C7887DF26EDB5710 /* Pods-WalletInformationAndMarketWidgetExtension.debug.xcconfig */,
|
AA7DCFB2C7887DF26EDB5710 /* Pods-WalletInformationAndMarketWidgetExtension.debug.xcconfig */,
|
||||||
7BAA8F97E61B677D33CF1944 /* Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig */,
|
7BAA8F97E61B677D33CF1944 /* Pods-WalletInformationAndMarketWidgetExtension.release.xcconfig */,
|
||||||
8C30FBCA42C6BF0B45757763 /* Pods-WidgetsExtension.debug.xcconfig */,
|
|
||||||
E0A230940404CA7C51FBED37 /* Pods-WidgetsExtension.release.xcconfig */,
|
|
||||||
);
|
);
|
||||||
name = Pods;
|
name = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -794,7 +789,6 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 6DD410A9266CADF40087DE03 /* Build configuration list for PBXNativeTarget "WidgetsExtension" */;
|
buildConfigurationList = 6DD410A9266CADF40087DE03 /* Build configuration list for PBXNativeTarget "WidgetsExtension" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
0CD668CB2F65F36C4CADD5AB /* [CP] Check Pods Manifest.lock */,
|
|
||||||
6DD41098266CADF10087DE03 /* Sources */,
|
6DD41098266CADF10087DE03 /* Sources */,
|
||||||
6DD41099266CADF10087DE03 /* Frameworks */,
|
6DD41099266CADF10087DE03 /* Frameworks */,
|
||||||
6DD4109A266CADF10087DE03 /* Resources */,
|
6DD4109A266CADF10087DE03 /* Resources */,
|
||||||
|
@ -1013,28 +1007,6 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "export EXTRA_PACKAGER_ARGS=\"--sourcemap-output $TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\"\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
shellScript = "export EXTRA_PACKAGER_ARGS=\"--sourcemap-output $TMPDIR/$(md5 -qs \"$CONFIGURATION_BUILD_DIR\")-main.jsbundle.map\"\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
|
||||||
};
|
};
|
||||||
0CD668CB2F65F36C4CADD5AB /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-WidgetsExtension-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
4B36CFF6FE55027DCA5CB6E1 /* Upload Bugsnag dSYM */ = {
|
4B36CFF6FE55027DCA5CB6E1 /* Upload Bugsnag dSYM */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -1063,12 +1035,12 @@
|
||||||
);
|
);
|
||||||
inputPaths = (
|
inputPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks.sh",
|
"${PODS_ROOT}/Target Support Files/Pods-BlueWallet/Pods-BlueWallet-frameworks.sh",
|
||||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL/OpenSSL.framework/OpenSSL",
|
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
|
||||||
"${PODS_XCFRAMEWORKS_BUILD_DIR}/LDKFramework/LDKFramework.framework/LDKFramework",
|
"${PODS_XCFRAMEWORKS_BUILD_DIR}/rn-ldk/LDKFramework.framework/LDKFramework",
|
||||||
);
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputPaths = (
|
outputPaths = (
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LDKFramework.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LDKFramework.framework",
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -1190,9 +1162,9 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
|
|
||||||
6D32C5C62596CE3A008C077C /* EventEmitter.m in Sources */,
|
6D32C5C62596CE3A008C077C /* EventEmitter.m in Sources */,
|
||||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||||
|
B461B852299599F800E431AA /* AppDelegate.mm in Sources */,
|
||||||
32B5A32A2334450100F8D608 /* Bridge.swift in Sources */,
|
32B5A32A2334450100F8D608 /* Bridge.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -1214,6 +1186,7 @@
|
||||||
files = (
|
files = (
|
||||||
6DD410BE266CAF5C0087DE03 /* SendReceiveButtons.swift in Sources */,
|
6DD410BE266CAF5C0087DE03 /* SendReceiveButtons.swift in Sources */,
|
||||||
6DD410B4266CAF5C0087DE03 /* WidgetAPI.swift in Sources */,
|
6DD410B4266CAF5C0087DE03 /* WidgetAPI.swift in Sources */,
|
||||||
|
B40FC3FA29CCD1D00007EBAC /* SwiftTCPClient.swift in Sources */,
|
||||||
6DD410A1266CADF10087DE03 /* Widgets.swift in Sources */,
|
6DD410A1266CADF10087DE03 /* Widgets.swift in Sources */,
|
||||||
6DD410AC266CAE470087DE03 /* PriceWidget.swift in Sources */,
|
6DD410AC266CAE470087DE03 /* PriceWidget.swift in Sources */,
|
||||||
6DD410B2266CAF5C0087DE03 /* WalletInformationView.swift in Sources */,
|
6DD410B2266CAF5C0087DE03 /* WalletInformationView.swift in Sources */,
|
||||||
|
@ -1390,10 +1363,11 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(SDKROOT)/usr/lib/swift",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)",
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"-ObjC",
|
"-ObjC",
|
||||||
|
@ -1433,10 +1407,11 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
LIBRARY_SEARCH_PATHS = (
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"$(SDKROOT)/usr/lib/swift",
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)",
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
OTHER_LDFLAGS = (
|
OTHER_LDFLAGS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"-ObjC",
|
"-ObjC",
|
||||||
|
@ -1477,7 +1452,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.TodayExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.TodayExtension;
|
||||||
|
@ -1516,7 +1491,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.TodayExtension;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.TodayExtension;
|
||||||
PRODUCT_NAME = "BlueWallet - Bitcoin Price";
|
PRODUCT_NAME = "BlueWallet - Bitcoin Price";
|
||||||
|
@ -1548,7 +1523,7 @@
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
INFOPLIST_FILE = Stickers/Info.plist;
|
INFOPLIST_FILE = Stickers/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
|
||||||
|
@ -1580,7 +1555,7 @@
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
INFOPLIST_FILE = Stickers/Info.plist;
|
INFOPLIST_FILE = Stickers/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.Stickers;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
@ -1592,7 +1567,6 @@
|
||||||
};
|
};
|
||||||
6DD410AA266CADF40087DE03 /* Debug */ = {
|
6DD410AA266CADF40087DE03 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 8C30FBCA42C6BF0B45757763 /* Pods-WidgetsExtension.debug.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
@ -1618,7 +1592,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
|
||||||
|
@ -1636,7 +1610,6 @@
|
||||||
};
|
};
|
||||||
6DD410AB266CADF40087DE03 /* Release */ = {
|
6DD410AB266CADF40087DE03 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = E0A230940404CA7C51FBED37 /* Pods-WidgetsExtension.release.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
@ -1663,7 +1636,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.MarketWidget;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
@ -1682,7 +1655,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
@ -1709,7 +1682,7 @@
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
ENABLE_TESTABILITY = YES;
|
ENABLE_TESTABILITY = YES;
|
||||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
@ -1726,9 +1699,10 @@
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
|
||||||
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
|
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_VERSION = 4.2;
|
SWIFT_VERSION = 4.2;
|
||||||
};
|
};
|
||||||
|
@ -1739,7 +1713,7 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CLANG_ENABLE_OBJC_ARC = YES;
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
@ -1766,7 +1740,7 @@
|
||||||
COPY_PHASE_STRIP = YES;
|
COPY_PHASE_STRIP = YES;
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
|
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_NO_COMMON_BLOCKS = YES;
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
@ -1776,8 +1750,9 @@
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
|
||||||
LIBRARY_SEARCH_PATHS = "\"$(inherited)\"";
|
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
SWIFT_VERSION = 4.2;
|
SWIFT_VERSION = 4.2;
|
||||||
|
@ -1808,7 +1783,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
|
||||||
|
@ -1848,7 +1823,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
"@executable_path/../../Frameworks",
|
"@executable_path/../../Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension;
|
||||||
PRODUCT_NAME = "${TARGET_NAME}";
|
PRODUCT_NAME = "${TARGET_NAME}";
|
||||||
|
@ -1883,7 +1858,7 @@
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
IBSC_MODULE = BlueWalletWatch_Extension;
|
IBSC_MODULE = BlueWalletWatch_Extension;
|
||||||
INFOPLIST_FILE = BlueWalletWatch/Info.plist;
|
INFOPLIST_FILE = BlueWalletWatch/Info.plist;
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
|
||||||
|
@ -1921,7 +1896,7 @@
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
IBSC_MODULE = BlueWalletWatch_Extension;
|
IBSC_MODULE = BlueWalletWatch_Extension;
|
||||||
INFOPLIST_FILE = BlueWalletWatch/Info.plist;
|
INFOPLIST_FILE = BlueWalletWatch/Info.plist;
|
||||||
MARKETING_VERSION = 6.3.2;
|
MARKETING_VERSION = 6.4.0;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
|
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
@ -2011,7 +1986,7 @@
|
||||||
repositoryURL = "https://github.com/EFPrefix/EFQRCode.git";
|
repositoryURL = "https://github.com/EFPrefix/EFQRCode.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = exactVersion;
|
kind = exactVersion;
|
||||||
version = 5.1.8;
|
version = 6.2.2;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
|
@ -39,6 +39,21 @@
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>2</integer>
|
<integer>2</integer>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>Stickers.xcscheme_^#shared#^_</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>4</integer>
|
||||||
|
</dict>
|
||||||
|
<key>TodayExtension.xcscheme_^#shared#^_</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>5</integer>
|
||||||
|
</dict>
|
||||||
|
<key>WidgetsExtension.xcscheme_^#shared#^_</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>88</integer>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>SuppressBuildableAutocreation</key>
|
<key>SuppressBuildableAutocreation</key>
|
||||||
<dict>
|
<dict>
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/EFPrefix/EFQRCode.git",
|
"location" : "https://github.com/EFPrefix/EFQRCode.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "62eff300b439d0088007b4e2e2e8c600f4b2e515",
|
"revision" : "2991c2f318ad9529d93b2a73a382a3f9c72c64ce",
|
||||||
"version" : "5.1.8"
|
"version" : "6.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -14,8 +14,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/ApolloZhu/swift_qrcodejs.git",
|
"location" : "https://github.com/ApolloZhu/swift_qrcodejs.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "f3fe9fdd39fa48e45b501000194b43a3883f732f",
|
"revision" : "374dc7f7b9e76c6aeb393f6a84590c6d387e1ecb",
|
||||||
"version" : "1.1.4"
|
"version" : "2.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
/**
|
#import <RCTAppDelegate.h>
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import <UserNotifications/UNUserNotificationCenter.h>
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>
|
@interface AppDelegate : RCTAppDelegate
|
||||||
|
|
||||||
@property (nonatomic, strong) UIWindow *window;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,41 +1,20 @@
|
||||||
#import <Bugsnag/Bugsnag.h>
|
#import <Bugsnag/Bugsnag.h>
|
||||||
/**
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
#import <React/RCTLinkingManager.h>
|
#import <React/RCTLinkingManager.h>
|
||||||
#import <React/RCTBundleURLProvider.h>
|
#import <React/RCTBundleURLProvider.h>
|
||||||
#import <React/RCTI18nUtil.h>
|
#import <React/RCTI18nUtil.h>
|
||||||
#import <React/RCTRootView.h>
|
#import <React/RCTBundleURLProvider.h>
|
||||||
#import "RNQuickActionManager.h"
|
#import "RNQuickActionManager.h"
|
||||||
#import <UserNotifications/UserNotifications.h>
|
#import <UserNotifications/UserNotifications.h>
|
||||||
#import <RNCPushNotificationIOS.h>
|
#import <RNCPushNotificationIOS.h>
|
||||||
#import "EventEmitter.h"
|
#import "EventEmitter.h"
|
||||||
@import WatchConnectivity;
|
#import <React/RCTRootView.h>
|
||||||
#if !TARGET_OS_MACCATALYST
|
#import <WatchConnectivity/WatchConnectivity.h>
|
||||||
#ifdef FB_SONARKIT_ENABLED
|
|
||||||
#import <FlipperKit/FlipperClient.h>
|
|
||||||
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
|
|
||||||
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
|
|
||||||
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
|
|
||||||
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
|
|
||||||
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
|
|
||||||
|
|
||||||
static void InitializeFlipper(UIApplication *application) {
|
@interface AppDelegate() <UNUserNotificationCenterDelegate>
|
||||||
FlipperClient *client = [FlipperClient sharedClient];
|
|
||||||
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
|
@end
|
||||||
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
|
|
||||||
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
|
|
||||||
[client addPlugin:[FlipperKitReactPlugin new]];
|
|
||||||
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
|
|
||||||
[client start];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
@ -51,43 +30,39 @@ static void InitializeFlipper(UIApplication *application) {
|
||||||
forKeyPath:@"deviceUIDCopy"
|
forKeyPath:@"deviceUIDCopy"
|
||||||
options:NSKeyValueObservingOptionNew
|
options:NSKeyValueObservingOptionNew
|
||||||
context:NULL];
|
context:NULL];
|
||||||
|
self.moduleName = @"BlueWallet";
|
||||||
#if !TARGET_OS_MACCATALYST
|
// You can add your custom initial props in the dictionary below.
|
||||||
#ifdef FB_SONARKIT_ENABLED
|
// They will be passed down to the ViewController used by React Native.
|
||||||
InitializeFlipper(application);
|
self.initialProps = @{};
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
|
||||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
|
|
||||||
moduleName:@"BlueWallet"
|
|
||||||
initialProperties:nil];
|
|
||||||
|
|
||||||
if (@available(iOS 13.0, *)) {
|
|
||||||
rootView.backgroundColor = [UIColor systemBackgroundColor];
|
|
||||||
} else {
|
|
||||||
rootView.backgroundColor = [UIColor clearColor];
|
|
||||||
}
|
|
||||||
[[RCTI18nUtil sharedInstance] allowRTL:YES];
|
[[RCTI18nUtil sharedInstance] allowRTL:YES];
|
||||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
||||||
UIViewController *rootViewController = [UIViewController new];
|
|
||||||
rootViewController.view = rootView;
|
|
||||||
self.window.rootViewController = rootViewController;
|
|
||||||
[self.window makeKeyAndVisible];
|
|
||||||
UIView* launchScreenView = [[UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil] instantiateInitialViewController].view;
|
|
||||||
launchScreenView.frame = self.window.bounds;
|
|
||||||
rootView.loadingView = launchScreenView;
|
|
||||||
// Define UNUserNotificationCenter
|
|
||||||
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
|
||||||
center.delegate = self;
|
center.delegate = self;
|
||||||
|
|
||||||
|
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
||||||
/* For debugging purposes since iOS Simulator does not support handoff
|
|
||||||
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.io.bluewallet.bluewallet"];
|
|
||||||
[defaults setValue:@{@"activityType": @"io.bluewallet.bluewallet.receiveonchain", @"userInfo": @{@"address": @""}} forKey:@"onUserActivityOpen"];
|
|
||||||
*/
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
||||||
|
#else
|
||||||
|
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
|
||||||
|
///
|
||||||
|
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
|
||||||
|
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
|
||||||
|
/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`.
|
||||||
|
- (BOOL)concurrentRootEnabled
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *) context
|
- (void)observeValueForKeyPath:(NSString *) keyPath ofObject:(id) object change:(NSDictionary *) change context:(void *) context
|
||||||
{
|
{
|
||||||
if([keyPath isEqual:@"deviceUID"] || [keyPath isEqual:@"deviceUIDCopy"])
|
if([keyPath isEqual:@"deviceUID"] || [keyPath isEqual:@"deviceUIDCopy"])
|
||||||
|
@ -103,15 +78,6 @@ static void InitializeFlipper(UIApplication *application) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
|
||||||
#else
|
|
||||||
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
|
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
|
||||||
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
|
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
|
||||||
{
|
{
|
||||||
|
@ -154,46 +120,6 @@ static void InitializeFlipper(UIApplication *application) {
|
||||||
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
|
completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Required to register for notifications
|
|
||||||
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
|
|
||||||
{
|
|
||||||
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required for the register event.
|
|
||||||
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
|
||||||
{
|
|
||||||
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required for the notification event. You must call the completion handler after handling the remote notification.
|
|
||||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
|
|
||||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
|
||||||
{
|
|
||||||
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required for the registrationError event.
|
|
||||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
|
|
||||||
{
|
|
||||||
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
|
|
||||||
}
|
|
||||||
|
|
||||||
// IOS 10+ Required for localNotification event
|
|
||||||
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
|
||||||
didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|
||||||
withCompletionHandler:(void (^)(void))completionHandler
|
|
||||||
{
|
|
||||||
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
|
|
||||||
completionHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
// IOS 4-10 Required for the localNotification event.
|
|
||||||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
|
|
||||||
{
|
|
||||||
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)openPreferences {
|
- (void)openPreferences {
|
||||||
[EventEmitter.sharedInstance openSettings];
|
[EventEmitter.sharedInstance openSettings];
|
||||||
}
|
}
|
||||||
|
@ -225,4 +151,28 @@ didReceiveNotificationResponse:(UNNotificationResponse *)response
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Required for the register event.
|
||||||
|
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
|
||||||
|
{
|
||||||
|
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
|
||||||
|
}
|
||||||
|
// Required for the notification event. You must call the completion handler after handling the remote notification.
|
||||||
|
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||||
|
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
|
||||||
|
{
|
||||||
|
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||||
|
}
|
||||||
|
// Required for the registrationError event.
|
||||||
|
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
|
||||||
|
{
|
||||||
|
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
|
||||||
|
}
|
||||||
|
// Required for localNotification event
|
||||||
|
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
||||||
|
didReceiveNotificationResponse:(UNNotificationResponse *)response
|
||||||
|
withCompletionHandler:(void (^)(void))completionHandler
|
||||||
|
{
|
||||||
|
[RNCPushNotificationIOS didReceiveNotificationResponse:response];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
|
@ -101,8 +101,6 @@
|
||||||
<array>
|
<array>
|
||||||
<string>https</string>
|
<string>https</string>
|
||||||
<string>http</string>
|
<string>http</string>
|
||||||
<string>bankid</string>
|
|
||||||
<string>swish</string>
|
|
||||||
</array>
|
</array>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
@ -133,6 +131,13 @@
|
||||||
<key>NSIncludesSubdomains</key>
|
<key>NSIncludesSubdomains</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>ts.net</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSIncludesSubdomains</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSAppleMusicUsageDescription</key>
|
<key>NSAppleMusicUsageDescription</key>
|
||||||
|
|
|
@ -15,7 +15,7 @@ static EventEmitter *sharedInstance;
|
||||||
RCT_EXPORT_MODULE();
|
RCT_EXPORT_MODULE();
|
||||||
|
|
||||||
+ (BOOL)requiresMainQueueSetup {
|
+ (BOOL)requiresMainQueueSetup {
|
||||||
return YES;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (EventEmitter *)sharedInstance {
|
+ (EventEmitter *)sharedInstance {
|
||||||
|
|
62
ios/Podfile
62
ios/Podfile
|
@ -1,26 +1,59 @@
|
||||||
platform :ios, '13.0'
|
|
||||||
workspace 'BlueWallet'
|
|
||||||
require_relative '../node_modules/react-native/scripts/react_native_pods'
|
require_relative '../node_modules/react-native/scripts/react_native_pods'
|
||||||
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
||||||
|
|
||||||
|
workspace 'BlueWallet'
|
||||||
|
platform :ios, '13.0'
|
||||||
|
prepare_react_native_project!
|
||||||
|
|
||||||
|
# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
|
||||||
|
# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
|
||||||
|
#
|
||||||
|
# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
|
||||||
|
# ```js
|
||||||
|
# module.exports = {
|
||||||
|
# dependencies: {
|
||||||
|
# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
|
||||||
|
# ```
|
||||||
|
# flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
|
||||||
|
|
||||||
|
flipper_config = FlipperConfiguration.disabled
|
||||||
|
linkage = ENV['USE_FRAMEWORKS']
|
||||||
|
if linkage != nil
|
||||||
|
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
|
||||||
|
use_frameworks! :linkage => linkage.to_sym
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
target 'BlueWallet' do
|
target 'BlueWallet' do
|
||||||
config = use_native_modules!
|
config = use_native_modules!
|
||||||
|
|
||||||
|
# Flags change depending on the env values.
|
||||||
|
flags = get_default_flags()
|
||||||
|
|
||||||
use_react_native!(
|
use_react_native!(
|
||||||
:path => config[:reactNativePath],
|
:path => config[:reactNativePath],
|
||||||
# to enable hermes on iOS, change `false` to `true` and then install pods
|
# Hermes is now enabled by default. Disable by setting this flag to false.
|
||||||
:hermes_enabled => false
|
# Upcoming versions of React Native may rely on get_default_flags(), but
|
||||||
|
# we make it explicit here to aid in the React Native upgrade process.
|
||||||
|
:hermes_enabled => true,
|
||||||
|
:fabric_enabled => flags[:fabric_enabled],
|
||||||
|
# Enables Flipper.
|
||||||
|
#
|
||||||
|
# Note that if you have use_frameworks! enabled, Flipper will not work and
|
||||||
|
# you should disable the next line.
|
||||||
|
#:flipper_configuration => flipper_config,
|
||||||
|
# An absolute path to your application root.
|
||||||
|
:app_path => "#{Pod::Config.instance.installation_root}/.."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Enables Flipper.
|
|
||||||
#
|
|
||||||
# Note that if you have use_frameworks! enabled, Flipper will not work and
|
|
||||||
# you should disable these next few lines.
|
|
||||||
use_flipper!({ "Flipper-DoubleConversion" => "1.1.7" })
|
|
||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
react_native_post_install(installer)
|
react_native_post_install(
|
||||||
__apply_Xcode_12_5_M1_post_install_workaround(installer)
|
installer,
|
||||||
pod 'Bugsnag'
|
# Set `mac_catalyst_enabled` to `true` in order to apply patches
|
||||||
|
# necessary for Mac Catalyst builds
|
||||||
|
:mac_catalyst_enabled => false
|
||||||
|
)
|
||||||
|
pod 'Bugsnag'
|
||||||
plugin 'cocoapods-bugsnag'
|
plugin 'cocoapods-bugsnag'
|
||||||
installer.pods_project.targets.each do |target|
|
installer.pods_project.targets.each do |target|
|
||||||
target.build_configurations.each do |config|
|
target.build_configurations.each do |config|
|
||||||
|
@ -31,12 +64,9 @@ target 'BlueWallet' do
|
||||||
config.build_settings['DEVELOPMENT_TEAM'] = "A7W54YZ4WU"
|
config.build_settings['DEVELOPMENT_TEAM'] = "A7W54YZ4WU"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
__apply_Xcode_12_5_M1_post_install_workaround(installer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
target 'WidgetsExtension' do
|
|
||||||
pod 'SwiftSocket', :git => 'https://github.com/swiftsocket/SwiftSocket.git', :branch => 'master'
|
|
||||||
end
|
|
||||||
|
|
821
ios/Podfile.lock
821
ios/Podfile.lock
File diff suppressed because it is too large
Load diff
101
ios/Widgets/Shared/SwiftTCPClient.swift
Normal file
101
ios/Widgets/Shared/SwiftTCPClient.swift
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
//
|
||||||
|
// File.swift
|
||||||
|
// BlueWallet
|
||||||
|
//
|
||||||
|
// Created by Marcos Rodriguez on 3/23/23.
|
||||||
|
// Copyright © 2023 BlueWallet. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class SwiftTCPClient: NSObject {
|
||||||
|
private var inputStream: InputStream?
|
||||||
|
private var outputStream: OutputStream?
|
||||||
|
private let bufferSize = 1024
|
||||||
|
|
||||||
|
// Define the completion block type
|
||||||
|
typealias ReceiveCompletion = (Result<Data, Error>) -> Void
|
||||||
|
|
||||||
|
// Add a completion block property
|
||||||
|
var receiveCompletion: ReceiveCompletion?
|
||||||
|
|
||||||
|
func connect(to host: String, port: UInt32) -> Bool {
|
||||||
|
var readStream: Unmanaged<CFReadStream>?
|
||||||
|
var writeStream: Unmanaged<CFWriteStream>?
|
||||||
|
|
||||||
|
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host as CFString, port, &readStream, &writeStream)
|
||||||
|
|
||||||
|
guard let read = readStream?.takeRetainedValue(), let write = writeStream?.takeRetainedValue() else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
inputStream = read as InputStream
|
||||||
|
outputStream = write as OutputStream
|
||||||
|
|
||||||
|
inputStream?.delegate = self
|
||||||
|
outputStream?.delegate = self
|
||||||
|
|
||||||
|
inputStream?.schedule(in: .current, forMode: .default)
|
||||||
|
outputStream?.schedule(in: .current, forMode: .default)
|
||||||
|
|
||||||
|
inputStream?.open()
|
||||||
|
outputStream?.open()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(data: Data) -> Bool {
|
||||||
|
guard let outputStream = outputStream else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytesWritten = data.withUnsafeBytes { bufferPointer -> Int in
|
||||||
|
guard let baseAddress = bufferPointer.baseAddress else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return outputStream.write(baseAddress.assumingMemoryBound(to: UInt8.self), maxLength: data.count)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesWritten == data.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func receive() -> Data? {
|
||||||
|
let data = NSMutableData()
|
||||||
|
return data as Data
|
||||||
|
}
|
||||||
|
|
||||||
|
func close() {
|
||||||
|
inputStream?.close()
|
||||||
|
outputStream?.close()
|
||||||
|
inputStream?.remove(from: .current, forMode: .default)
|
||||||
|
outputStream?.remove(from: .current, forMode: .default)
|
||||||
|
inputStream = nil
|
||||||
|
outputStream = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SwiftTCPClient: StreamDelegate {
|
||||||
|
func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
|
||||||
|
switch eventCode {
|
||||||
|
case .hasBytesAvailable:
|
||||||
|
if let inputStream = aStream as? InputStream {
|
||||||
|
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
|
||||||
|
defer {
|
||||||
|
buffer.deallocate()
|
||||||
|
}
|
||||||
|
|
||||||
|
while inputStream.hasBytesAvailable {
|
||||||
|
let bytesRead = inputStream.read(buffer, maxLength: bufferSize)
|
||||||
|
if bytesRead > 0 {
|
||||||
|
let data = Data(bytes: buffer, count: bytesRead)
|
||||||
|
receiveCompletion?(.success(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .hasSpaceAvailable, .openCompleted, .endEncountered, .errorOccurred:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,8 +6,7 @@
|
||||||
// Copyright © 2020 BlueWallet. All rights reserved.
|
// Copyright © 2020 BlueWallet. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
import SwiftSocket
|
|
||||||
|
|
||||||
struct APIError: LocalizedError {
|
struct APIError: LocalizedError {
|
||||||
var errorDescription: String = "Failed to fetch Electrum data..."
|
var errorDescription: String = "Failed to fetch Electrum data..."
|
||||||
|
@ -21,13 +20,12 @@ extension WidgetAPI {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
DispatchQueue.global(qos: .background).async {
|
DispatchQueue.global(qos: .background).async {
|
||||||
let client = TCPClient(address: host, port: port)
|
let client = SwiftTCPClient()
|
||||||
let send = "{\"id\": 1, \"method\": \"blockchain.estimatefee\", \"params\": [1]}\n"
|
client.receiveCompletion = { result in
|
||||||
switch client.connect(timeout: 1) {
|
switch result {
|
||||||
case .success:
|
case .success(let data):
|
||||||
switch client.send(string: send) {
|
print("Received: \(data)")
|
||||||
case .success:
|
guard let response = String(bytes: data, encoding: .utf8)?.data(using: .utf8) else {
|
||||||
guard let data = client.read(1024*10, timeout: 1), let response = String(bytes: data, encoding: .utf8)?.data(using: .utf8) else {
|
|
||||||
client.close()
|
client.close()
|
||||||
completion(nil, APIError())
|
completion(nil, APIError())
|
||||||
return
|
return
|
||||||
|
@ -45,12 +43,21 @@ extension WidgetAPI {
|
||||||
completion(nil, APIError())
|
completion(nil, APIError())
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
print(error)
|
print("Error: \(error.localizedDescription)")
|
||||||
client.close()
|
client.close()
|
||||||
completion(nil, APIError())
|
completion(nil, APIError())
|
||||||
}
|
}
|
||||||
case .failure(let error):
|
}
|
||||||
print(error)
|
|
||||||
|
if client.connect(to: host, port: UInt32(exactly: port)!) {
|
||||||
|
let message = "{\"id\": 1, \"method\": \"blockchain.estimatefee\", \"params\": [1]}\n"
|
||||||
|
if let data = message.data(using: .utf8), client.send(data: data) {
|
||||||
|
print("Message sent!")
|
||||||
|
RunLoop.current.run(until: Date(timeIntervalSinceNow: 5))
|
||||||
|
}
|
||||||
|
client.close()
|
||||||
|
} else {
|
||||||
|
print("Connection failed")
|
||||||
client.close()
|
client.close()
|
||||||
if userElectrumSettings.host == DefaultElectrumPeers.last?.host {
|
if userElectrumSettings.host == DefaultElectrumPeers.last?.host {
|
||||||
completion(nil, APIError())
|
completion(nil, APIError())
|
||||||
|
|
|
@ -35,6 +35,10 @@ class WidgetAPI {
|
||||||
urlString = "https://api.exir.io/v1/ticker?symbol=btc-irt"
|
urlString = "https://api.exir.io/v1/ticker?symbol=btc-irt"
|
||||||
case "wazirx":
|
case "wazirx":
|
||||||
urlString = "https://api.wazirx.com/api/v2/tickers/btcinr"
|
urlString = "https://api.wazirx.com/api/v2/tickers/btcinr"
|
||||||
|
case "Bitstamp":
|
||||||
|
urlString = "https://www.bitstamp.net/api/v2/ticker/btc\(endPointKey.lowercased())"
|
||||||
|
case "CoinGecko":
|
||||||
|
urlString = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=\(endPointKey.lowercased())"
|
||||||
default:
|
default:
|
||||||
urlString = "https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json"
|
urlString = "https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json"
|
||||||
}
|
}
|
||||||
|
@ -61,6 +65,12 @@ class WidgetAPI {
|
||||||
let unix = Double(lastUpdated / 1_000)
|
let unix = Double(lastUpdated / 1_000)
|
||||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix))
|
let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix))
|
||||||
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||||
|
case "CoinGecko":
|
||||||
|
guard let rateDict = json["bitcoin"] as? [String: Any],
|
||||||
|
let rateDouble = rateDict[endPointKey.lowercased()] as? Double
|
||||||
|
else { break }
|
||||||
|
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||||
|
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||||
case "YadioConvert":
|
case "YadioConvert":
|
||||||
guard let rateDict = json as? [String: Any],
|
guard let rateDict = json as? [String: Any],
|
||||||
let rateDouble = rateDict["rate"] as? Double,
|
let rateDouble = rateDict["rate"] as? Double,
|
||||||
|
@ -74,6 +84,10 @@ class WidgetAPI {
|
||||||
let rateString = String(rateDouble)
|
let rateString = String(rateDouble)
|
||||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||||
|
case "Bitstamp":
|
||||||
|
guard let rateString = json["last"] as? String, let rateDouble = Double(rateString) else { break }
|
||||||
|
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||||
|
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||||
case "wazirx":
|
case "wazirx":
|
||||||
guard let tickerDict = json["ticker"] as? [String: Any],
|
guard let tickerDict = json["ticker"] as? [String: Any],
|
||||||
let rateString = tickerDict["buy"] as? String,
|
let rateString = tickerDict["buy"] as? String,
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
محفظة Bitcoin تتيح لك تخزين عملات Bitcoin وإرسالها واستلامها وشراءها، مع التركيز على الأمان والبساطة.
|
محفظة بتكوين تتيح لك تخزين البتكوين، ارساله واستقباله مع اهتمام خاص بالأمان العالي والبساطة المتناهية.
|
||||||
|
|
||||||
في BlueWallet ستمتلك المفاتيح الخاصة لعملات Bitcoin. محفظة الـ Bitcoin هذه أنشأها مستخدمو Bitcoin من أجل المجتمع.
|
في BlueWallet ستمتلك المفاتيح الخاصة للبتكوين الذي تقرر الاحتفاظ به فيها. هذه المحفظة أنشأها مستخدمو البتكوين من أجل المجتمع.
|
||||||
|
|
||||||
يمكنك إجراء المعاملات مع أي شخص في العالم على الفور، وتغيير النظام المالي من جيبك مباشرةً.
|
يمكنك إجراء المعاملات مع أي شخص في العالم على الفور والمشاركة في تطوير النظام المالي العالمي من جيبك مباشرةً.
|
||||||
|
|
||||||
يمكنك إنشاء عدد غير محدود من محافظ Bitcoin مجانًا أو استيراد محفظتك الحالية. الأمر بسيط وسريع.
|
يمكنك إنشاء عدد غير محدود من محافظ البتكوين مجانًا أو استيراد محفظتك الحالية. الأمر سريع بسيط.
|
||||||
|
|
||||||
_____
|
_____
|
||||||
|
|
||||||
إليك ما تحصل عليه:
|
إليك ما ستحصل عليه:
|
||||||
|
|
||||||
|
|
||||||
1 - الأمان من خلال التصميم
|
1 - الأمان من خلال التصميم
|
||||||
|
@ -22,32 +22,25 @@ _____
|
||||||
التشفير الكامل
|
التشفير الكامل
|
||||||
علاوةً على التشفير متعدد الطبقات لنظام iOS، فإننا نقوم بتشفير كل شيء بكلمات مرور مضافة
|
علاوةً على التشفير متعدد الطبقات لنظام iOS، فإننا نقوم بتشفير كل شيء بكلمات مرور مضافة
|
||||||
|
|
||||||
العقدة الكاملة
|
النود التام
|
||||||
اتصل بمحفظة Bitcoin باستخدام العقدة الكاملة عن طريق برنامج Electrum
|
اربط محفظة البتكوين بنود تام خاص بك عن طريق برنامج Electrum
|
||||||
|
|
||||||
التخزين البارد
|
التخزين البارد
|
||||||
اتصل بمحفظة جهاز واحتفظ بعملاتك في وحدة "التخزين البارد"
|
اتصل بمحفظة خارجية لتخزين البتكوين في وحدة تخزين بارد
|
||||||
|
|
||||||
2 - التركيز على تجربتك
|
2 - التركيز على تجربتك
|
||||||
|
|
||||||
كن متحكمًا
|
كن متحكمًا
|
||||||
لا تغادر المفاتيح الخاصة جهازك أبدًا.
|
Private keys never leave your device.You control your private keys
|
||||||
أنت من يتحكم في مفاتيحك الخاصة
|
|
||||||
|
|
||||||
مرونة الرسوم
|
رسوم مرنة
|
||||||
بدايةً من ساتوشي واحد. تحددها أنت؛ أي المستخدم بنفسك
|
بدايةً من ساتوشي واحد. تحددها أنت أيها المستخدم بنفسك
|
||||||
|
|
||||||
الاستبدال بالرسوم (RBF)
|
الاستبدال بالرسوم (RBF)
|
||||||
(RBF) عزز سرعة معاملاتك بزيادة الرسوم (BIP125)
|
(RBF) عزز سرعة معاملاتك بزيادة الرسوم (BIP125)
|
||||||
|
|
||||||
محافظ للتحقق من الرصيد فقط
|
محافظ لمراقبة الرصيد فقط
|
||||||
تتيح لك محافظ التحقق من الرصيد متابعة وحدة التخزين البارد دون لمس الجهاز.
|
تتيح لك محافظ مراقبة الرصيد من متابعة وحدة التخزين البارد دون الحاجة للمس المحفظة الخارجية.
|
||||||
|
|
||||||
شبكة Lightning
|
شبكة البرق
|
||||||
محفظة Lightning دون الحاجة إلى إعدادها. معاملات رخيصة جدًا وسريعة مع توفير أفضل تجربة لمستخدمي Bitcoin.
|
محفظة البرق دون الحاجة إلى إعدادها. معاملات رخيصة جدًا وسريعة مع توفير أفضل تجربة لمستخدمي البتكوين.
|
||||||
|
|
||||||
شراء Bitcoin
|
|
||||||
ادخل في أغوار الثورة المالية المفتوحة مع القدرة على شراء Bitcoin مباشرة من محفظتك.
|
|
||||||
|
|
||||||
متداول محلي
|
|
||||||
منصة تداول Bitcoin من نظير إلى نظير، والتي تتيح لك شراء عملات Bitcoin وبيعها مباشرةً إلى المستخدمين الآخرين دون الاستعانة بأطراف خارجية.
|
|
46
ios/fastlane/metadata/ja/description.txt
Normal file
46
ios/fastlane/metadata/ja/description.txt
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
ビットコインを送る・受け取る・保存することができる、セキュリティとシンプルさを重視したウォレットです。
|
||||||
|
|
||||||
|
BlueWalletは、秘密鍵をあなたが所有するビットコインウォレット。ビットコインユーザーが作った、コミュニティのためのビットコインウォレット。
|
||||||
|
|
||||||
|
世界中の誰とでもすぐに取引ができ、あなたのポケットからファイナンスの仕組みを変革します。
|
||||||
|
|
||||||
|
無料で数の制限なくビットコインウォレットを作ることも、お持ちのウォレットをインポートすることもできます。シンプルでスピーディです。
|
||||||
|
|
||||||
|
_____
|
||||||
|
|
||||||
|
特長:
|
||||||
|
|
||||||
|
|
||||||
|
1 - デザインによるセキュリティ
|
||||||
|
|
||||||
|
オープンソース
|
||||||
|
MITライセンスにより、あなた自身でビルド・実行可能! ReactNative製。
|
||||||
|
|
||||||
|
もっともらしい否認
|
||||||
|
アクセスの開示を強要された時でも、フェイクのビットコインウォレットを復号できるパスワード
|
||||||
|
|
||||||
|
完全な暗号化
|
||||||
|
iOSのマルチレイヤー暗号化に加え、追加のパスワードですべてを暗号化
|
||||||
|
|
||||||
|
フルノード
|
||||||
|
Electrumを通じてビットコインフルノードに接続
|
||||||
|
|
||||||
|
コールドストレージ
|
||||||
|
ハードウェアウォレットに接続し、コインをコールドストレージに保存
|
||||||
|
|
||||||
|
2 - ユーザーエクスペリエンス重視
|
||||||
|
|
||||||
|
思いのままに
|
||||||
|
秘密鍵はずっとあなたのデバイスの中に。あなたが秘密鍵をコントロールします
|
||||||
|
|
||||||
|
柔軟な手数料
|
||||||
|
1 Satoshiから。ユーザーのあなた自身が決定します
|
||||||
|
|
||||||
|
Replace-By-Fee
|
||||||
|
(RBF) 手数料を増やして取引をスピードアップ (BIP125)
|
||||||
|
|
||||||
|
閲覧専用ウォレット
|
||||||
|
閲覧専用ウォレットにより、ハードウェアに触れることなくコールドストレージを監視できます。
|
||||||
|
|
||||||
|
ライトニングネットワーク
|
||||||
|
設定の要らないライトニングウォレット。有り得ないほど安く、速い取引で最高のビットコイン体験を。
|
1
ios/fastlane/metadata/ja/keywords.txt
Normal file
1
ios/fastlane/metadata/ja/keywords.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ビットコイン,ウォレット,ビットコインウォレット,ブロックチェーン,btc,仮想通貨,暗号通貨,electrum,イーサリアム
|
1
ios/fastlane/metadata/ja/name.txt
Normal file
1
ios/fastlane/metadata/ja/name.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
BlueWallet - ビットコインウォレット
|
10
ios/fastlane/metadata/ja/promotional_text.txt
Normal file
10
ios/fastlane/metadata/ja/promotional_text.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
特長
|
||||||
|
|
||||||
|
* オープンソース
|
||||||
|
* 完全な暗号化
|
||||||
|
* もっともらしい否認
|
||||||
|
* 柔軟な手数料
|
||||||
|
* Replace-By-Fee (RBF)
|
||||||
|
* SegWit
|
||||||
|
* 閲覧専用(Sentinel)ウォレット
|
||||||
|
* ライトニングネットワーク
|
|
@ -2,7 +2,7 @@ Uma carteira Bitcoin que permite armazenar, enviar e receber Bitcoins. Focada em
|
||||||
|
|
||||||
BlueWallet, uma carteira de bitcoin onde você detém a posse das chaves privadas. Uma carteira Bitcoin criada para a comunidade por usuários do Bitcoin.
|
BlueWallet, uma carteira de bitcoin onde você detém a posse das chaves privadas. Uma carteira Bitcoin criada para a comunidade por usuários do Bitcoin.
|
||||||
|
|
||||||
Você pode fazer transações instantaneamente com qualquer pessoa no mundo e transformar o sistema financeiro direto do seu bolso.
|
Você pode fazer transações instantaneamente com qualquer pessoa no mundo e transformar o sistema financeiro direto do seu bolso.
|
||||||
|
|
||||||
Crie um número ilimitado de carteiras de Bitcoin gratuitamente ou importe sua carteira existente. É simples e rápido.
|
Crie um número ilimitado de carteiras de Bitcoin gratuitamente ou importe sua carteira existente. É simples e rápido.
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ Entenda o que oferecemos:
|
||||||
|
|
||||||
1 - Designada para ser segura
|
1 - Designada para ser segura
|
||||||
|
|
||||||
De Código Aberto
|
Código Aberto
|
||||||
Licenciado pelo MIT, você pode compilar e rodar a sua própria versão! Feita com ReactNative
|
Licenciado pelo MIT, você pode compilar e rodar a sua própria versão! Feita com ReactNative
|
||||||
|
|
||||||
Negação plausível
|
Negação plausível
|
||||||
|
@ -26,21 +26,21 @@ Nó completo
|
||||||
Conecte-se ao seu nó completo Bitcoin através da Electrum
|
Conecte-se ao seu nó completo Bitcoin através da Electrum
|
||||||
|
|
||||||
Armazenamento Frio
|
Armazenamento Frio
|
||||||
Conecte com sua carteira hardware e mantenha suas moedas em armazenamento frio
|
Conecte-se a sua carteira hardware e mantenha suas moedas em armazenamento frio
|
||||||
|
|
||||||
2 - Foco na sua experiência
|
2 - Focada na sua experiência
|
||||||
|
|
||||||
Tenha o controle
|
Tenha o controle
|
||||||
Chaves privadas nunca saem do seu dispositivo. Você detém o controle delas.
|
Chaves privadas nunca saem do seu dispositivo. Você detém o controle delas.
|
||||||
|
|
||||||
Taxas flexíveis
|
Taxas flexíveis
|
||||||
A partir de 1 satoshi. Você decide
|
A partir de 1 Satoshi. Definidas por você, o usuário
|
||||||
|
|
||||||
Replace-By-Fee
|
Replace-By-Fee
|
||||||
(RBF) Acelere suas transações aumentando a taxa depois de enviar (BIP125)
|
(RBF) Acelere suas transações aumentando a taxa depois de enviar (BIP125)
|
||||||
|
|
||||||
Carteiras somente leitura
|
Carteiras somente leitura
|
||||||
Carteiras somente leitura permitem a você ficar de olho no seu armazenamento frio sem tocar na hardwallet.
|
Carteiras somente leitura permitem a você ficar de olho no seu armazenamento frio sem tocar na sua carteira hardware.
|
||||||
|
|
||||||
Lightning Network
|
Rede Lightning
|
||||||
Carteira Lightning sem precisar configurar nada. Transações muito baratas e rápidas para ter a melhor experiência com o Bitcoin.
|
Carteira Lightning sem precisar configurar nada. Transações muito baratas e rápidas para ter a melhor experiência com o Bitcoin.
|
150
loc/ar.json
150
loc/ar.json
|
@ -9,30 +9,31 @@
|
||||||
"disabled": "معطّل",
|
"disabled": "معطّل",
|
||||||
"of": "{number} من {total}",
|
"of": "{number} من {total}",
|
||||||
"ok": "موافق",
|
"ok": "موافق",
|
||||||
"storage_is_encrypted": "وحدة التخزين الخاصة بك مشفرة. أنت بحاجة إلى كلمة المرور لفك تشفيرها",
|
"storage_is_encrypted": "وحدة التخزين مشفرة. أنت بحاجة إلى كلمة المرور لفك تشفيرها",
|
||||||
"allow": "السماح",
|
|
||||||
"dont_allow": "عدم السماح",
|
|
||||||
"yes": "نعم",
|
"yes": "نعم",
|
||||||
"no": "لا",
|
"no": "لا",
|
||||||
"save": "حفظ",
|
"save": "حفظ",
|
||||||
"seed": "عبارة الاسترداد",
|
"seed": "عبارة الاسترداد",
|
||||||
"success": "نجاح",
|
"success": "نجاح",
|
||||||
"wallet_key": "مفتاح المحفظة",
|
"wallet_key": "مفتاح المحفظة",
|
||||||
"invalid_animated_qr_code_fragment" : "قطعة من رمز الـ QRcode المتحرك غير صحيحة، حاول مرة اخرى.",
|
"invalid_animated_qr_code_fragment": "قطعة من رمز الـ QRcode المتحرك غير صحيحة، حاول مرة اخرى.",
|
||||||
"file_saved": "تم حفظ الملف {filePath} في {destination}.",
|
"file_saved": "تم حفظ الملف {filePath} في {destination}.",
|
||||||
"file_save_title": "احفظ الملف",
|
|
||||||
"file_save_location": "حدد مكان حفظ {filePath}",
|
|
||||||
"downloads_folder": "مجلد التنزيلات",
|
"downloads_folder": "مجلد التنزيلات",
|
||||||
"external_storage": "التخزين خارجيًا",
|
"close": "اغلاق",
|
||||||
"discard_changes": "تجاهل التغييرات؟",
|
"change_input_currency": "تغيير عملة الادخال",
|
||||||
"discard_changes_detail": "يوجد تغييرات غير محفوظة. هل أنت متأكد من الخروج من الشاشة وتجاهلها؟"
|
"refresh": "تحديث",
|
||||||
|
"more": "المزيد",
|
||||||
|
"pick_image": "اختر صورة من الصور",
|
||||||
|
"pick_file": "اختر ملف",
|
||||||
|
"enter_amount": "أدخل القيمة",
|
||||||
|
"qr_custom_input_button": "أنقر ١٠ مرات لإدخال قيمة مخصصة"
|
||||||
},
|
},
|
||||||
"alert": {
|
"alert": {
|
||||||
"default": "تنبيه"
|
"default": "تنبيه"
|
||||||
},
|
},
|
||||||
"azteco": {
|
"azteco": {
|
||||||
"codeIs": "رمز القسيمة الخاص بك هو",
|
"codeIs": "رمز القسيمة الخاص بك هو",
|
||||||
"errorBeforeRefeem": "يجب عليك إضافة محفظة Bitcoin أولًا قبل الاسترداد.",
|
"errorBeforeRefeem": "يجب عليك إضافة محفظة بتكوين أولًا قبل الاسترداد.",
|
||||||
"errorSomething": "حدث خطأ. هل ما زالت هذه القسيمة صالحة؟",
|
"errorSomething": "حدث خطأ. هل ما زالت هذه القسيمة صالحة؟",
|
||||||
"redeem": "الاسترداد إلى المحفظة",
|
"redeem": "الاسترداد إلى المحفظة",
|
||||||
"redeemButton": "الاسترداد",
|
"redeemButton": "الاسترداد",
|
||||||
|
@ -50,39 +51,32 @@
|
||||||
"network": "خطأ في الشبكة"
|
"network": "خطأ في الشبكة"
|
||||||
},
|
},
|
||||||
"lnd": {
|
"lnd": {
|
||||||
"active":"نشط",
|
"active": "نشط",
|
||||||
"inactive":"غير نشط",
|
"inactive": "غير نشط",
|
||||||
"channels": "القنوات",
|
"channels": "القنوات",
|
||||||
"no_channels": "لا يوجد قنوات",
|
"no_channels": "لا يوجد قنوات",
|
||||||
"claim_balance": "المطالبة برصيد {balance}",
|
"claim_balance": "المطالبة برصيد {balance}",
|
||||||
"close_channel": "اغلق القناة",
|
"close_channel": "اغلق القناة",
|
||||||
"new_channel" : "قناة جديدة",
|
"new_channel": "قناة جديدة",
|
||||||
"errorInvoiceExpired": "انتهت صلاحية الفاتورة",
|
"errorInvoiceExpired": "انتهت صلاحية الفاتورة",
|
||||||
"force_close_channel": "هل تود فرض اغلاق القناة؟",
|
"force_close_channel": "هل تود فرض اغلاق القناة؟",
|
||||||
"expired": "منتهية الصلاحية",
|
"expired": "منتهية الصلاحية",
|
||||||
"node_alias": "الاسم المستعار للعقدة",
|
"node_alias": "الاسم المستعار للعقدة",
|
||||||
"expiredLow": "انتهت صلاحيتها",
|
|
||||||
"expiresIn": "تنتهي بعد {time} دقيقة",
|
"expiresIn": "تنتهي بعد {time} دقيقة",
|
||||||
"payButton": "دفع",
|
"payButton": "دفع",
|
||||||
"placeholder": "فاتورة",
|
"placeholder": "برقية",
|
||||||
"open_channel": "فتح قناة",
|
"open_channel": "فتح قناة",
|
||||||
"funding_amount_placeholder": "مبلغ التمويل، على سبيل المثال 0.001",
|
"funding_amount_placeholder": "مبلغ التمويل، على سبيل المثال 0.001",
|
||||||
"opening_channnel_for_from":"جارِ فتح قناة للمحفظة {forWalletLabel} بتمويل من {fromWalletLabel}",
|
"opening_channnel_for_from": "جارِ فتح قناة للمحفظة {forWalletLabel} بتمويل من {fromWalletLabel}",
|
||||||
"are_you_sure_open_channel": "هل أنت متأكد أنك تريد فتح هذه القناة؟",
|
"are_you_sure_open_channel": "هل أنت متأكد أنك تريد فتح هذه القناة؟",
|
||||||
"are_you_sure_exit_without_new_channel": "هل أنت متأكد أنك تريد الخروج دون فتح قناة؟",
|
|
||||||
"public": "علني",
|
|
||||||
"public_description": "قابلة للرؤية في الشبكة: من الممكن أن تكون عقدة توجيه وتكسب رسوم.",
|
|
||||||
"private": "خاص",
|
|
||||||
"private_description": "غير قابلة للرؤية في الشبكة: ستحافظ على خصوصية مدفوعاتك.",
|
|
||||||
"local_reserve": "الاحتياطي المحلي",
|
|
||||||
"potentialFee": "الرسوم المحتملة: {fee}",
|
"potentialFee": "الرسوم المحتملة: {fee}",
|
||||||
"remote_host": "المضيف البعيد",
|
"remote_host": "المضيف البعيد",
|
||||||
"refill": "إعادة التعبئة",
|
"refill": "إعادة التعبئة",
|
||||||
"reconnect_peer": "إعادة الاتصال بالأقران",
|
"reconnect_peer": "إعادة الاتصال بالأقران",
|
||||||
"refill_create": "للمتابعة، يُرجى إنشاء محفظة Bitcoin لإعادة التعبئة باستخدامها.",
|
"refill_create": "للمتابعة، يُرجى إنشاء محفظة بتكوين لإعادة التعبئة باستخدامها.",
|
||||||
"refill_external": "إعادة التعبئة باستخدام محفظة خارجية",
|
"refill_external": "إعادة التعبئة باستخدام محفظة خارجية",
|
||||||
"refill_lnd_balance": "إعادة تعبئة رصيد محفظة البرق (Lightning)",
|
"refill_lnd_balance": "إعادة تعبئة رصيد محفظة البرق (Lightning)",
|
||||||
"sameWalletAsInvoiceError": "لا يمكنك دفع فاتورة بنفس المحفظة المستخدمة لإنشائها.",
|
"sameWalletAsInvoiceError": "لايمكنك دفع البرقية من نفس المحفظة",
|
||||||
"title": "إدارة الأموال",
|
"title": "إدارة الأموال",
|
||||||
"can_send": "يمكن أن ترسل",
|
"can_send": "يمكن أن ترسل",
|
||||||
"can_receive": "يمكن ان تستقبل",
|
"can_receive": "يمكن ان تستقبل",
|
||||||
|
@ -92,13 +86,12 @@
|
||||||
"additional_info": "معلومة إضافية",
|
"additional_info": "معلومة إضافية",
|
||||||
"for": "إلى:",
|
"for": "إلى:",
|
||||||
"lightning_invoice": "فاتورة برق (Lightning)",
|
"lightning_invoice": "فاتورة برق (Lightning)",
|
||||||
"has_been_paid": "تم دفع هذه الفاتورة إلى",
|
"open_direct_channel": "فتح قناة مباشرة مع هذه النود:",
|
||||||
"open_direct_channel": "فتح قناة مباشرة مع هذه العقدة:",
|
|
||||||
"please_pay_between_and": "يرجى دفع ما بين {min} و{max}",
|
"please_pay_between_and": "يرجى دفع ما بين {min} و{max}",
|
||||||
"please_pay": "يُرجى الدفع",
|
"please_pay": "يُرجى الدفع",
|
||||||
"preimage": "الصورة الأصلية",
|
"preimage": "الصورة الأصلية",
|
||||||
"sats": "بالساتوشي",
|
"sats": "بالساتوشي",
|
||||||
"wasnt_paid_and_expired": "لم يتم دفع هذه الفاتورة وانتهت صلاحيتها"
|
"wasnt_paid_and_expired": "لم يتم دفع هذه البرقية وانتهت صلاحيتها"
|
||||||
},
|
},
|
||||||
"plausibledeniability": {
|
"plausibledeniability": {
|
||||||
"create_fake_storage": "إنشاء وحدة تخزين مشفرة",
|
"create_fake_storage": "إنشاء وحدة تخزين مشفرة",
|
||||||
|
@ -108,7 +101,7 @@
|
||||||
"help2": "ستعمل وحدة التخزين الجديدة بكامل طاقتها، ويمكنك تخزين بعض المبالغ البسيطة هناك بحيث تبدو أكثر مصداقية ومنطقية.",
|
"help2": "ستعمل وحدة التخزين الجديدة بكامل طاقتها، ويمكنك تخزين بعض المبالغ البسيطة هناك بحيث تبدو أكثر مصداقية ومنطقية.",
|
||||||
"password_should_not_match": "كلمة المرور قيد الاستخدام حاليًا. يُرجى تجربة كلمة مرور مختلفة.",
|
"password_should_not_match": "كلمة المرور قيد الاستخدام حاليًا. يُرجى تجربة كلمة مرور مختلفة.",
|
||||||
"passwords_do_not_match": "كلمات المرور غير متطابقة، حاول مرة أخرى.",
|
"passwords_do_not_match": "كلمات المرور غير متطابقة، حاول مرة أخرى.",
|
||||||
"retype_password": "إعادة إدخال كلمة المرور",
|
"retype_password": "أعد إدخال كلمة المرور",
|
||||||
"success": "نجحت العملية",
|
"success": "نجحت العملية",
|
||||||
"title": "الإنكار المقبول"
|
"title": "الإنكار المقبول"
|
||||||
},
|
},
|
||||||
|
@ -120,13 +113,12 @@
|
||||||
"ok_lnd": "حسنًا، لقد حفظتها.",
|
"ok_lnd": "حسنًا، لقد حفظتها.",
|
||||||
"text": "يُرجى أخذ لحظة من وقتك لكتابة هذه العبارة التذكيرية على ورقة. إنها وسيلتك الاحتياطية لاستعادة المحفظة على جهاز آخر.",
|
"text": "يُرجى أخذ لحظة من وقتك لكتابة هذه العبارة التذكيرية على ورقة. إنها وسيلتك الاحتياطية لاستعادة المحفظة على جهاز آخر.",
|
||||||
"text_lnd": "يُرجى حفظ هذه النسخة الاحتياطية للمحفظة. لكي تتتمكن من استعادة المحفظة في حالة فقدها.",
|
"text_lnd": "يُرجى حفظ هذه النسخة الاحتياطية للمحفظة. لكي تتتمكن من استعادة المحفظة في حالة فقدها.",
|
||||||
"text_lnd2": "هذه المحفظة يتم استضافتها بواسطة BlueWallet.",
|
|
||||||
"title": "تم إنشاء محفظتك"
|
"title": "تم إنشاء محفظتك"
|
||||||
},
|
},
|
||||||
"receive": {
|
"receive": {
|
||||||
"details_create": "إنشاء",
|
"details_create": "إنشاء",
|
||||||
"details_label": "الوصف",
|
"details_label": "الوصف",
|
||||||
"details_setAmount": "استلام مبلغ",
|
"details_setAmount": "استلام مبلغ محدد",
|
||||||
"details_share": "مشاركة",
|
"details_share": "مشاركة",
|
||||||
"header": "استلام",
|
"header": "استلام",
|
||||||
"maxSats": "الحد الأقصى للمبلغ هو {min} ساتوشي",
|
"maxSats": "الحد الأقصى للمبلغ هو {min} ساتوشي",
|
||||||
|
@ -150,23 +142,23 @@
|
||||||
"create_fee": "الرسوم",
|
"create_fee": "الرسوم",
|
||||||
"create_memo": "مذكرة",
|
"create_memo": "مذكرة",
|
||||||
"create_satoshi_per_vbyte": "ساتوشي لكل ف بايت",
|
"create_satoshi_per_vbyte": "ساتوشي لكل ف بايت",
|
||||||
"create_this_is_hex": "هذا هو التنسيق السداسي لمعاملتك، موقَّع وجاهز للبث على الشبكة.",
|
"create_this_is_hex": "هذا هو رقم العملية بصيغة ست عشرية (Hex) ، موقَّع وجاهز للبث على الشبكة.",
|
||||||
"create_to": "إلى",
|
"create_to": "إلى",
|
||||||
"create_tx_size": "حجم المعاملة",
|
"create_tx_size": "حجم المعاملة",
|
||||||
"create_verify": "التحقق على coinb.in",
|
"create_verify": "التحقق على coinb.in",
|
||||||
"details_add_rec_add": "إضافة المستلم",
|
"details_add_rec_add": "إضافة المستلم",
|
||||||
"details_add_rec_rem": "إزالة المستلم",
|
"details_add_rec_rem": "إزالة المستلم",
|
||||||
"details_address": "العنوان",
|
"details_address": "العنوان",
|
||||||
"details_address_field_is_not_valid": "حقل العنوان غير صالح",
|
"details_address_field_is_not_valid": "العنوان غير صالح",
|
||||||
"details_adv_fee_bump": "السماح بزيادة الرسوم",
|
"details_adv_fee_bump": "السماح بزيادة الرسوم",
|
||||||
"details_adv_full": "استخدام الرصيد الكامل",
|
"details_adv_full": "استخدام الرصيد الكامل",
|
||||||
"details_adv_full_sure": "هل أنت متأكد أنك تريد استخدام الرصيد الكامل لمحفظتك لهذه المعاملة؟",
|
"details_adv_full_sure": "هل أنت متأكد أنك تريد استخدام الرصيد الكامل لمحفظتك لهذه المعاملة؟",
|
||||||
"details_adv_full_sure_frozen": "هل أنت متأكد انك ترغب بإستخدام الرصيد الكامل لمحفظتك لهذة المعاملة؟ يرجى ملاحظة انه تم استبعاد العملات المجمدة.",
|
"details_adv_full_sure_frozen": "هل أنت متأكد انك ترغب بإستخدام الرصيد الكامل لمحفظتك لهذة المعاملة؟ يرجى ملاحظة انه تم استبعاد العملات المجمدة.",
|
||||||
"details_adv_import": "استيراد المعاملة",
|
"details_adv_import": "استيراد العملية",
|
||||||
"details_adv_import_qr": "استيراد معاملة (QR)",
|
"details_adv_import_qr": "استيراد معاملة (QR)",
|
||||||
"details_amount_field_is_not_valid": "حقل المبلغ غير صالح",
|
"details_amount_field_is_not_valid": "المبلغ غير صالح",
|
||||||
"details_amount_field_is_less_than_minimum_amount_sat": "المبلغ المحدد صغير جدًا. الرجاء إدخال مبلغ أكبر من 500 ساتوشي.",
|
"details_amount_field_is_less_than_minimum_amount_sat": "المبلغ المحدد صغير جدًا. الرجاء إدخال مبلغ أكبر من 500 ساتوشي.",
|
||||||
"details_create": "إنشاء فاتورة",
|
"details_create": "إنشاء برقية",
|
||||||
"details_error_decode": "يتعذَّر فك تشفير عنوان Bitcoin",
|
"details_error_decode": "يتعذَّر فك تشفير عنوان Bitcoin",
|
||||||
"details_fee_field_is_not_valid": "حقل الرسوم غير صالح",
|
"details_fee_field_is_not_valid": "حقل الرسوم غير صالح",
|
||||||
"details_frozen": "{amount} بتكوين تم تجميدها",
|
"details_frozen": "{amount} بتكوين تم تجميدها",
|
||||||
|
@ -178,7 +170,7 @@
|
||||||
"details_total_exceeds_balance": "مبلغ الإرسال يتجاوز الرصيد المتاح.",
|
"details_total_exceeds_balance": "مبلغ الإرسال يتجاوز الرصيد المتاح.",
|
||||||
"details_total_exceeds_balance_frozen": "مبلغ الإرسال يتجاوز الرصيد المتاح، يرجى ملاحظة انه تم استبعاد العملات المجمدة.",
|
"details_total_exceeds_balance_frozen": "مبلغ الإرسال يتجاوز الرصيد المتاح، يرجى ملاحظة انه تم استبعاد العملات المجمدة.",
|
||||||
"details_unrecognized_file_format": "تنسيق ملف غير معروف",
|
"details_unrecognized_file_format": "تنسيق ملف غير معروف",
|
||||||
"details_wallet_before_tx": "يجب عليك إضافة محفظة Bitcoin أولًا قبل إنشاء معاملة.",
|
"details_wallet_before_tx": "يجب عليك إضافة محفظة بتكوين أولًا قبل إنشاء معاملة.",
|
||||||
"dynamic_init": "جارٍ التهيئة...",
|
"dynamic_init": "جارٍ التهيئة...",
|
||||||
"dynamic_next": "التالي",
|
"dynamic_next": "التالي",
|
||||||
"dynamic_prev": "السابق",
|
"dynamic_prev": "السابق",
|
||||||
|
@ -199,7 +191,6 @@
|
||||||
"input_paste": "اللصق",
|
"input_paste": "اللصق",
|
||||||
"input_total": "الإجمالي:",
|
"input_total": "الإجمالي:",
|
||||||
"permission_camera_message": "نحتاج إلى إذنك لاستخدام الكاميرا الخاصة بك",
|
"permission_camera_message": "نحتاج إلى إذنك لاستخدام الكاميرا الخاصة بك",
|
||||||
"permission_camera_title": "إذن باستخدام الكاميرا",
|
|
||||||
"psbt_sign": "وقّع معاملة",
|
"psbt_sign": "وقّع معاملة",
|
||||||
"open_settings": "فتح الإعدادات",
|
"open_settings": "فتح الإعدادات",
|
||||||
"permission_storage_later": "اسألني لاحقًا",
|
"permission_storage_later": "اسألني لاحقًا",
|
||||||
|
@ -207,14 +198,13 @@
|
||||||
"permission_storage_denied_message": "BlueWallet غير قادر على حفظ هذا الملف. يرجى فتح إعدادات جهازك وتمكين إذن التخزين.",
|
"permission_storage_denied_message": "BlueWallet غير قادر على حفظ هذا الملف. يرجى فتح إعدادات جهازك وتمكين إذن التخزين.",
|
||||||
"permission_storage_title": "إذن وصول BlueWallet إلى وحدة التخزين",
|
"permission_storage_title": "إذن وصول BlueWallet إلى وحدة التخزين",
|
||||||
"psbt_clipboard": "النسخ إلى الحافظة",
|
"psbt_clipboard": "النسخ إلى الحافظة",
|
||||||
"psbt_this_is_psbt": "هذه معاملة Bitcoin موقَّعة جزئيًا (PSBT). يُرجى الانتهاء من توقيعها باستخدام محفظة الجهاز الخاصة بك.",
|
"psbt_this_is_psbt": "هذه معاملة بتكوين موقَّعة جزئيًا (PSBT). يُرجى توقيعها باستخدام المحفظة الخارجية.",
|
||||||
"psbt_tx_export": "التصدير إلى ملف",
|
"psbt_tx_export": "التصدير إلى ملف",
|
||||||
"no_tx_signing_in_progress": "لا يوجد معاملة توقيع قيد التقدم.",
|
"no_tx_signing_in_progress": "لا يوجد معاملة توقيع قيد التقدم.",
|
||||||
"outdated_rate": "تم تحديث السعر آخر مرة في {date}",
|
"outdated_rate": "تم تحديث السعر آخر مرة في {date}",
|
||||||
"psbt_tx_open": "فتح معاملة موقَّعة",
|
"psbt_tx_open": "فتح معاملة موقَّعة",
|
||||||
"psbt_tx_scan": "المسح الضوئي معاملة موقَّعة",
|
"psbt_tx_scan": "المسح الضوئي لمعاملة موقَّعة",
|
||||||
"qr_error_no_qrcode": "لم نتمكن من العثور على كود QR في الصورة المحددة. تأكد من أن الصورة تحتوي فقط على كود QR ولا تحتوي على محتوى إضافي مثل النص أو الأزرار.",
|
"qr_error_no_qrcode": "لم نتمكن من قراءة رمز الاستجابة السريع (QR) في الصورة المحددة. تأكد أن الصورة تحتوي فقط على رمز (QR) دون أي محتوى إضافي آخر مثل النص أو الأزرار.",
|
||||||
"qr_error_no_wallet": "لا يحتوي الملف المحدَّد على محفظة يمكن استيرادها.",
|
|
||||||
"reset_amount": "إعادة تعيين المبلغ",
|
"reset_amount": "إعادة تعيين المبلغ",
|
||||||
"reset_amount_confirm": "هل تريد إعادة تعيين المبلغ؟",
|
"reset_amount_confirm": "هل تريد إعادة تعيين المبلغ؟",
|
||||||
"success_done": "تم",
|
"success_done": "تم",
|
||||||
|
@ -227,14 +217,16 @@
|
||||||
"about_backup": "احتفظ دائمًا بنسخة احتياطية من مفاتيحك!",
|
"about_backup": "احتفظ دائمًا بنسخة احتياطية من مفاتيحك!",
|
||||||
"about_free": "محفظة BlueWallet هي مشروع مجاني ومفتوح المصدر، أنشأه مستخدمو Bitcoin.",
|
"about_free": "محفظة BlueWallet هي مشروع مجاني ومفتوح المصدر، أنشأه مستخدمو Bitcoin.",
|
||||||
"about_license": "ترخيص MIT",
|
"about_license": "ترخيص MIT",
|
||||||
"about_release_notes": "ملاحظات الإصدار",
|
"about_release_notes": "معلومات الإصدار",
|
||||||
"about_review": "اترك لنا مراجعتك",
|
"about_review": "اترك لنا مراجعة",
|
||||||
|
"performance_score": "معدل الأداء: {num}",
|
||||||
|
"run_performance_test": "اختبار الأداء",
|
||||||
"about_selftest": "تشغيل اختبار ذاتي",
|
"about_selftest": "تشغيل اختبار ذاتي",
|
||||||
"about_selftest_electrum_disabled": "لا يتوفر الاختبار الذاتي مع وضع Electrum الغير متصل بالانترنت. يرجى تعطيل وضع عدم اتصال الشبكة والمحاولة مرة أخرى.",
|
"about_selftest_electrum_disabled": "لا يتوفر الاختبار الذاتي مع وضع Electrum الغير متصل بالانترنت. يرجى تعطيل وضع عدم اتصال الشبكة والمحاولة مرة أخرى.",
|
||||||
"about_selftest_ok": "تم اجتياز جميع الاختبارات الداخلية بنجاح. المحفظة تعمل بشكل جيد.",
|
"about_selftest_ok": "تم اجتياز جميع الاختبارات الداخلية بنجاح. المحفظة تعمل بشكل جيد.",
|
||||||
"about_sm_github": "GitHub",
|
"about_sm_github": "GitHub",
|
||||||
"about_sm_discord": "سيرفر Discord",
|
"about_sm_discord": "سيرفر Discord",
|
||||||
"about_sm_telegram": "دردشة Telegram",
|
"about_sm_telegram": "قناة تيليجرام",
|
||||||
"about_sm_twitter": "تابعنا على تويتر",
|
"about_sm_twitter": "تابعنا على تويتر",
|
||||||
"advanced_options": "الخيارات المتقدمة",
|
"advanced_options": "الخيارات المتقدمة",
|
||||||
"biometrics": "القياسات الحيوية",
|
"biometrics": "القياسات الحيوية",
|
||||||
|
@ -243,7 +235,7 @@
|
||||||
"biom_no_passcode": "جهازك ليس لديه رمز مرور. للمتابعة ، يرجى اضافة رمز مرور من إعدادات الجهاز.",
|
"biom_no_passcode": "جهازك ليس لديه رمز مرور. للمتابعة ، يرجى اضافة رمز مرور من إعدادات الجهاز.",
|
||||||
"biom_remove_decrypt": "ستتم إزالة جميع محافظك وفك تشفير التخزين الخاص بك. هل انت متأكد انك تريد المتابعة؟",
|
"biom_remove_decrypt": "ستتم إزالة جميع محافظك وفك تشفير التخزين الخاص بك. هل انت متأكد انك تريد المتابعة؟",
|
||||||
"currency": "العملة",
|
"currency": "العملة",
|
||||||
"currency_source": "يتم الحصول على الأسعار من",
|
"currency_source": "تم الاستعلام عن السعر عن طريق",
|
||||||
"currency_fetch_error": "حدث خطأ أثناء الحصول على سعر العملة المحددة.",
|
"currency_fetch_error": "حدث خطأ أثناء الحصول على سعر العملة المحددة.",
|
||||||
"default_desc": "عند تعطيل هذا الإعداد، ستفتح BlueWallet المحفظة المحدَّدة فور التشغيل.",
|
"default_desc": "عند تعطيل هذا الإعداد، ستفتح BlueWallet المحفظة المحدَّدة فور التشغيل.",
|
||||||
"default_info": "المعلومات الافتراضية",
|
"default_info": "المعلومات الافتراضية",
|
||||||
|
@ -251,7 +243,6 @@
|
||||||
"default_wallets": "عرض جميع المحافظ",
|
"default_wallets": "عرض جميع المحافظ",
|
||||||
"electrum_connected": "متصل",
|
"electrum_connected": "متصل",
|
||||||
"electrum_connected_not": "غير متصل",
|
"electrum_connected_not": "غير متصل",
|
||||||
"electrum_connnected_not_description": "مطلوب اتصال Electrum نشط لاستيراد المحفظة. يمكنك التحقق إذا كان قد تم إنشاء اتصال بالانتقال إلى قسم الشبكة في الإعدادات.",
|
|
||||||
"electrum_error_connect": "يتعذَّر الاتصال بخادم Electrum المقدَّم",
|
"electrum_error_connect": "يتعذَّر الاتصال بخادم Electrum المقدَّم",
|
||||||
"lndhub_uri": "على سبيل المثال، {example}",
|
"lndhub_uri": "على سبيل المثال، {example}",
|
||||||
"electrum_host": "على سبيل المثال، {example}",
|
"electrum_host": "على سبيل المثال، {example}",
|
||||||
|
@ -279,7 +270,6 @@
|
||||||
"tor_unsupported": "اتصالات Tor غير مدعومة.",
|
"tor_unsupported": "اتصالات Tor غير مدعومة.",
|
||||||
"encrypt_decrypt": "فك تشفير وحدة التخزين",
|
"encrypt_decrypt": "فك تشفير وحدة التخزين",
|
||||||
"encrypt_decrypt_q": "هل أنت متأكد أنك تريد فك تشفير وحدة التخزين الخاصة بك؟ سيسمح إجراء ذلك بالوصول إلى محافظك دون كلمة مرور.",
|
"encrypt_decrypt_q": "هل أنت متأكد أنك تريد فك تشفير وحدة التخزين الخاصة بك؟ سيسمح إجراء ذلك بالوصول إلى محافظك دون كلمة مرور.",
|
||||||
"encrypt_del_uninstall": "الحذف في حال إلغاء تثبيت BlueWallet",
|
|
||||||
"encrypt_enc_and_pass": "مشفرة ومحمية بكلمة مرور",
|
"encrypt_enc_and_pass": "مشفرة ومحمية بكلمة مرور",
|
||||||
"encrypt_title": "الأمان",
|
"encrypt_title": "الأمان",
|
||||||
"encrypt_tstorage": "وحدة التخزين",
|
"encrypt_tstorage": "وحدة التخزين",
|
||||||
|
@ -287,10 +277,10 @@
|
||||||
"encrypt_use_expl": "سيتم استخدام {type} لتأكيد هويتك قبل إجراء معاملة أو فتح محفظة أو تصديرها أو حذفها. ولن يتم استخدام {type} لفتح وحدة تخزين مشفرة.",
|
"encrypt_use_expl": "سيتم استخدام {type} لتأكيد هويتك قبل إجراء معاملة أو فتح محفظة أو تصديرها أو حذفها. ولن يتم استخدام {type} لفتح وحدة تخزين مشفرة.",
|
||||||
"general": "عام",
|
"general": "عام",
|
||||||
"general_adv_mode": "الوضع المتقدم",
|
"general_adv_mode": "الوضع المتقدم",
|
||||||
"general_adv_mode_e": "عند تمكين هذا الإعداد، سترى خيارات متقدمة في أثناء إنشاء المحفظة، مثل أنواع المحافظ المختلفة، والقدرة على تحديد مثيل LNDHub الذي ترغب في الاتصال به، وإنتروبيا (عشوائية) مخصصة.",
|
"general_adv_mode_e": "عند تمكين هذا الإعداد، سترى خيارات متقدمة أثناء إنشاء المحفظة، مثل أنواع محافظ مختلفة، القدرة على الاتصال ب LNDHub محدد، وإنتروبيا (عشوائية) مخصصة.",
|
||||||
"general_continuity": "الارتباط",
|
"general_continuity": "الاتساق",
|
||||||
"general_continuity_e": "عند تمكين هذا الإعداد، ستتمكن من عرض المحافظ والمعاملات المحدَّدة باستخدام أجهزتك الأخرى المتصلة بحساب Apple iCloud.",
|
"general_continuity_e": "عند تمكين هذا الإعداد، ستتمكن من عرض المحافظ والعمليات المحدَّدة باستخدام أجهزتك الأخرى المتصلة بنفس حساب Apple iCloud.",
|
||||||
"groundcontrol_explanation": "GroundControl هو خادم إشعارات فورية مجاني مفتوح المصدر لمحافظ Bitcoin. يمكنك تثبيت خادم GroundControl الخاص بك ووضع عنوان URL له هنا لعدم الاعتماد على البنية التحتية لمحفظة BlueWallet. اترك الحقل فارغًا لاستخدام الإعدادات الافتراضية",
|
"groundcontrol_explanation": "GroundControl هو خادم إشعارات فورية مجاني مفتوح المصدر لمحافظ البتكوين. يمكنك تثبيت خادم GroundControl الخاص بك ووضع عنوان (URL) له هنا لعدم الاعتماد على البنية التحتية لمحفظة BlueWallet. اترك الحقل فارغًا لاستخدام الإعدادات الافتراضية",
|
||||||
"header": "الإعدادات",
|
"header": "الإعدادات",
|
||||||
"language": "اللغة",
|
"language": "اللغة",
|
||||||
"last_updated": "آخر تحديث",
|
"last_updated": "آخر تحديث",
|
||||||
|
@ -299,20 +289,19 @@
|
||||||
"lightning_saved": "تم حفظ تغييراتك بنجاح",
|
"lightning_saved": "تم حفظ تغييراتك بنجاح",
|
||||||
"lightning_settings": "إعدادات البرق (Lightning)",
|
"lightning_settings": "إعدادات البرق (Lightning)",
|
||||||
"tor_settings": "اعدادات tor",
|
"tor_settings": "اعدادات tor",
|
||||||
"lightning_settings_explain": "للاتصال بعقدة LND الخاصة بك، يُرجى تثبيت LndHub ثم وضع رابطه هنا في الإعدادات. اترك الحقل فارغًا لاستخدام LNDHub (lndhub.io) لمحفظة BlueWallet. ستتصل المحافظ التي يتم إنشاؤها بعد حفظ التغييرات بنفس عقدة LNDHub التي قمت بتحديدها.",
|
"lightning_settings_explain": "للاتصال بنود LND الخاص بك، يُرجى تثبيت LNDHub ثم وضع رابطه هنا في الإعدادات. تذكر: فقط المحافظ التي يتم إنشاؤها بعد حفظ التغييرات ستتصل بنود LNDHub التي قمت بإضافتها.",
|
||||||
"network": "الشبكة",
|
"network": "الشبكة",
|
||||||
"network_broadcast": "بث المعاملة",
|
"network_broadcast": "بث العملية",
|
||||||
"network_electrum": "خادم Electrum",
|
"network_electrum": "خادم Electrum",
|
||||||
"not_a_valid_uri": "معرِّف URI غير صالح",
|
"not_a_valid_uri": "معرِّف URI غير صالح",
|
||||||
"notifications": "الإشعارات",
|
"notifications": "الإشعارات",
|
||||||
"open_link_in_explorer" : "فتح الرابط في المتصفح",
|
"open_link_in_explorer": "فتح الرابط في المتصفح",
|
||||||
"password": "كلمه المرور",
|
"password": "كلمه المرور",
|
||||||
"password_explain": "أنشئ كلمة المرور التي ستستخدمها لفك تشفير وحدة التخزين",
|
"password_explain": "أنشئ كلمة المرور التي ستستخدمها لفك تشفير وحدة التخزين",
|
||||||
"passwords_do_not_match": "كلمتا المرور لا تتطابقان",
|
"passwords_do_not_match": "كلمتا المرور لا تتطابقان",
|
||||||
"plausible_deniability": "الإنكار المقبول",
|
"plausible_deniability": "الإنكار المقبول",
|
||||||
"privacy": "الخصوصية",
|
"privacy": "الخصوصية",
|
||||||
"privacy_read_clipboard": "قراءة الحافظة",
|
"privacy_read_clipboard": "قراءة الحافظة",
|
||||||
"privacy_read_clipboard_alert": "سيعرض BlueWallet اختصاراً اذا كانت هناك فاتورة أو عنوان موجود في الحافظة للتعامل معه.",
|
|
||||||
"privacy_system_settings": "اعدادات الجهاز",
|
"privacy_system_settings": "اعدادات الجهاز",
|
||||||
"privacy_quickactions": "اختصارات المحفظة",
|
"privacy_quickactions": "اختصارات المحفظة",
|
||||||
"privacy_quickactions_explanation": "المس مع الاستمرار ايقونة تطبيق BlueWallet على شاشتك الرئيسية للمشاهدة عرض سريع لرصيد محفظتك.",
|
"privacy_quickactions_explanation": "المس مع الاستمرار ايقونة تطبيق BlueWallet على شاشتك الرئيسية للمشاهدة عرض سريع لرصيد محفظتك.",
|
||||||
|
@ -325,7 +314,7 @@
|
||||||
"selfTest": "اختبار ذاتي",
|
"selfTest": "اختبار ذاتي",
|
||||||
"save": "حفظ",
|
"save": "حفظ",
|
||||||
"saved": "تم الحفظ",
|
"saved": "تم الحفظ",
|
||||||
"success_transaction_broadcasted" : "تمت بنجاح! لقد تم نشر معاملتك!",
|
"success_transaction_broadcasted": "تمت بنجاح! لقد تم نشر معاملتك!",
|
||||||
"total_balance": "الرصيد الاجمالي",
|
"total_balance": "الرصيد الاجمالي",
|
||||||
"total_balance_explanation": "اعرض الرصيد الإجمالي لجميع محافظك على ويدجيت الشاشة الرئيسية الخاصة بك.",
|
"total_balance_explanation": "اعرض الرصيد الإجمالي لجميع محافظك على ويدجيت الشاشة الرئيسية الخاصة بك.",
|
||||||
"widgets": "ويدجيت",
|
"widgets": "ويدجيت",
|
||||||
|
@ -344,7 +333,7 @@
|
||||||
"copy_link": "نسخ الرابط",
|
"copy_link": "نسخ الرابط",
|
||||||
"expand_note": "توسيع الملاحظة",
|
"expand_note": "توسيع الملاحظة",
|
||||||
"cpfp_create": "إنشاء",
|
"cpfp_create": "إنشاء",
|
||||||
"cpfp_exp": "سننشئ معاملة أخرى تستبدل معاملتك غير المؤكدة. وسيكون إجمالي الرسوم أعلى من رسوم المعاملة الأصلية؛ حتى يجري تعدينها بشكلٍ أسرع. وهذا ما يُسمَّى CPFP؛ أي دعم المعاملة الرئيسية بمعاملة فرعية.",
|
"cpfp_exp": "سننشئ عملية أخرى تستبدل عمليتك غير المؤكدة. وسيكون إجمالي الرسوم أعلى من رسوم العملية الأصلية؛ حتى يجري تعدينها بشكلٍ أسرع. وهذا ما يُسمَّى CPFP؛ أي التحكم بالعملية الرئيسية بمعاملة فرعية.",
|
||||||
"cpfp_no_bump": "هذه المعاملة غير قابلة للتسريع",
|
"cpfp_no_bump": "هذه المعاملة غير قابلة للتسريع",
|
||||||
"cpfp_title": "تسريع المعاملة (CPFP)",
|
"cpfp_title": "تسريع المعاملة (CPFP)",
|
||||||
"details_balance_hide": "إخفاء الرصيد",
|
"details_balance_hide": "إخفاء الرصيد",
|
||||||
|
@ -358,12 +347,12 @@
|
||||||
"details_from": "من",
|
"details_from": "من",
|
||||||
"details_inputs": "المدخلات",
|
"details_inputs": "المدخلات",
|
||||||
"details_outputs": "المخرجات",
|
"details_outputs": "المخرجات",
|
||||||
|
"date": "التاريخ",
|
||||||
"details_received": "التاريخ",
|
"details_received": "التاريخ",
|
||||||
"transaction_note_saved": "تم حفظ مذكرة المعاملة بنجاح.",
|
"transaction_note_saved": "تم حفظ مذكرة المعاملة بنجاح.",
|
||||||
"details_show_in_block_explorer": "العرض في مستكشف الكتل",
|
"details_show_in_block_explorer": "العرض في مستكشف الكتل",
|
||||||
"details_title": "المعاملة",
|
"details_title": "العملية",
|
||||||
"details_to": "إلى",
|
"details_to": "إلى",
|
||||||
"details_transaction_details": "تفاصيل المعاملة",
|
|
||||||
"enable_offline_signing": "هذه المحفظة لا يتم استعمالها مع التوقيع دون اتصال. هل ترغب في تمكينه الآن؟",
|
"enable_offline_signing": "هذه المحفظة لا يتم استعمالها مع التوقيع دون اتصال. هل ترغب في تمكينه الآن؟",
|
||||||
"list_conf": "تأكيد: {number}",
|
"list_conf": "تأكيد: {number}",
|
||||||
"pending": "قيد الانتظار",
|
"pending": "قيد الانتظار",
|
||||||
|
@ -373,13 +362,13 @@
|
||||||
"eta_3h": "الوقت المقدر للتأكيد: في حوالي 3 ساعات",
|
"eta_3h": "الوقت المقدر للتأكيد: في حوالي 3 ساعات",
|
||||||
"eta_1d": "الوقت المقدر للتأكيد: في حوالي يوم واحد",
|
"eta_1d": "الوقت المقدر للتأكيد: في حوالي يوم واحد",
|
||||||
"view_wallet": "لمشاهدة {walletLabel}",
|
"view_wallet": "لمشاهدة {walletLabel}",
|
||||||
"list_title": "المعاملات",
|
"list_title": "العمليات",
|
||||||
"open_url_error": "تعذر فتح الرابط باستخدام المتصفح الافتراضي. يرجى تغيير المتصفح الافتراضي الخاص بك وحاول مرة أخرى.",
|
"open_url_error": "تعذر فتح الرابط باستخدام المتصفح الافتراضي. يرجى تغيير المتصفح الافتراضي الخاص بك وحاول مرة أخرى.",
|
||||||
"rbf_explain": "سنستبدل هذه المعاملة بمعاملة جديدة تدفع رسوم اعلى؛ حتى يجري تعدينها بشكلٍ أسرع. وهذا ما يُسمَّى RBF؛ أي الاستبدال بالرسوم.",
|
"rbf_explain": "سنستبدل هذه المعاملة بمعاملة جديدة تدفع رسوم اعلى؛ حتى يجري تعدينها بشكلٍ أسرع. وهذا ما يُسمَّى RBF؛ أي الاستبدال بالرسوم.",
|
||||||
"rbf_title": "تسريع المعاملة (RBF)",
|
"rbf_title": "تسريع المعاملة (RBF)",
|
||||||
"status_bump": "تسريع المعاملة",
|
"status_bump": "تسريع المعاملة",
|
||||||
"status_cancel": "إلغاء المعاملة",
|
"status_cancel": "إلغاء العملية",
|
||||||
"transactions_count": "عدد المعاملات",
|
"transactions_count": "عدد العمليات",
|
||||||
"txid": "معرّف المعاملة",
|
"txid": "معرّف المعاملة",
|
||||||
"updating": "جارٍ التحديث ..."
|
"updating": "جارٍ التحديث ..."
|
||||||
},
|
},
|
||||||
|
@ -393,10 +382,9 @@
|
||||||
"add_import_wallet": "استيراد محفظة",
|
"add_import_wallet": "استيراد محفظة",
|
||||||
"add_lightning": "البرق",
|
"add_lightning": "البرق",
|
||||||
"add_lightning_explain": "لإرسال المعاملات بشكل فوري عبر شبكة البرق Lightning ",
|
"add_lightning_explain": "لإرسال المعاملات بشكل فوري عبر شبكة البرق Lightning ",
|
||||||
"add_lndhub": "اتصل ببرنامج تضمين LNDHub الخاص بك",
|
"add_lndhub": "اتصل ب LNDHub الخاص بك",
|
||||||
"add_lndhub_error": "عنوان العقدة المقدَّم هو عقدة LNDHub صالحة.",
|
"add_lndhub_error": "عنوان النود المقدَّم غير صالح.",
|
||||||
"add_lndhub_placeholder": "عنوان العقدة الخاص بك",
|
"add_lndhub_placeholder": "عنوان النود الخاص بك",
|
||||||
"add_or": "أو",
|
|
||||||
"add_placeholder": "محفظتي الأولى",
|
"add_placeholder": "محفظتي الأولى",
|
||||||
"add_title": "إضافة محفظة",
|
"add_title": "إضافة محفظة",
|
||||||
"add_wallet_name": "الاسم",
|
"add_wallet_name": "الاسم",
|
||||||
|
@ -415,10 +403,8 @@
|
||||||
"details_derivation_path": "مسار الاشتقاق (derivation path)",
|
"details_derivation_path": "مسار الاشتقاق (derivation path)",
|
||||||
"details_display": "العرض في قائمة المحافظ",
|
"details_display": "العرض في قائمة المحافظ",
|
||||||
"details_export_backup": "التصدير/النسخ الاحتياطي",
|
"details_export_backup": "التصدير/النسخ الاحتياطي",
|
||||||
"details_master_fingerprint": "بصمة الإصبع الرئيسية",
|
"details_export_history": "تصدير السجل ل ملف CSV",
|
||||||
"details_ms_l": "{m} of {n} legacy (p2sh)",
|
"details_master_fingerprint": "البصمة الرئيسية",
|
||||||
"details_ms_ns": "{m} of {n} native segwit (p2wsh)",
|
|
||||||
"details_ms_ws": "{m} of {n} wrapped segwit (p2sh-p2wsh)",
|
|
||||||
"details_multisig_type": "متعدد التواقيع",
|
"details_multisig_type": "متعدد التواقيع",
|
||||||
"details_no_cancel": "لا، إلغاء",
|
"details_no_cancel": "لا، إلغاء",
|
||||||
"details_save": "حفظ",
|
"details_save": "حفظ",
|
||||||
|
@ -437,10 +423,10 @@
|
||||||
"import_passphrase_message": "أدخل عبارة المرور إذا كنت قد استخدمت أيًا منها",
|
"import_passphrase_message": "أدخل عبارة المرور إذا كنت قد استخدمت أيًا منها",
|
||||||
"import_error": "فشل الاستيراد. يُرجى التأكد من أن البيانات المقدَّمة صالحة.",
|
"import_error": "فشل الاستيراد. يُرجى التأكد من أن البيانات المقدَّمة صالحة.",
|
||||||
"import_explanation": "اكتب هنا عبارتك التذكيرية أو مفتاحك الخاص أو WIF أو أي شيء لديك. ستبذل BlueWallet قصارى جهدها لتخمين التنسيق الصحيح واستيراد محفظتك",
|
"import_explanation": "اكتب هنا عبارتك التذكيرية أو مفتاحك الخاص أو WIF أو أي شيء لديك. ستبذل BlueWallet قصارى جهدها لتخمين التنسيق الصحيح واستيراد محفظتك",
|
||||||
"import_file": "استيراد ملف",
|
|
||||||
"import_imported": "تم الاستيراد",
|
"import_imported": "تم الاستيراد",
|
||||||
"import_scan_qr": "المسح الضوئي أو استيراد ملف",
|
"import_scan_qr": "المسح الضوئي أو استيراد ملف",
|
||||||
"import_success": "تم استيراد محفظتك بنجاح.",
|
"import_success": "تم استيراد محفظتك بنجاح.",
|
||||||
|
"import_success_watchonly": "تم استيراد محفظتك بنجاح. تنويه: هذه محفظة مراقبة فقط. لا يمكنك تنفيذ العمليات.",
|
||||||
"import_search_accounts": "البحث عن حسابات",
|
"import_search_accounts": "البحث عن حسابات",
|
||||||
"import_title": "الاستيراد",
|
"import_title": "الاستيراد",
|
||||||
"import_discovery_title": "اكتشاف",
|
"import_discovery_title": "اكتشاف",
|
||||||
|
@ -461,13 +447,11 @@
|
||||||
"list_empty_txs1_lightning": "يجب استخدام محفظة البرق (Lightning) في معاملاتك اليومية. الرسوم رخيصة جدًا والسرعة كبيرة حقًا.",
|
"list_empty_txs1_lightning": "يجب استخدام محفظة البرق (Lightning) في معاملاتك اليومية. الرسوم رخيصة جدًا والسرعة كبيرة حقًا.",
|
||||||
"list_empty_txs2": "ابدأ بمحفظتك",
|
"list_empty_txs2": "ابدأ بمحفظتك",
|
||||||
"list_empty_txs2_lightning": "\nللبدء في استخدامها، اضغط على \"إدارة الأموال\" واشحن رصيدك.",
|
"list_empty_txs2_lightning": "\nللبدء في استخدامها، اضغط على \"إدارة الأموال\" واشحن رصيدك.",
|
||||||
"list_header": "تمثِّل المحفظة زوجًا من المفاتيح السرية (المفتاح الخاص) وعنوان يمكنك مشاركته لاستلام العملات المعدنية.",
|
"list_latest_transaction": "آخر عملية",
|
||||||
"list_import_problem": "حدثت مشكلة في استيراد هذه المحفظة",
|
|
||||||
"list_latest_transaction": "آخر معاملة",
|
|
||||||
"list_ln_browser": "متصفح LApp",
|
"list_ln_browser": "متصفح LApp",
|
||||||
"list_long_choose": "اختيار صورة",
|
"list_long_choose": "اختيار صورة",
|
||||||
"list_long_clipboard": "النسخ من الحافظة",
|
"list_long_clipboard": "النسخ من الحافظة",
|
||||||
"list_long_scan": "مسح رمز الاستجابة السرعة ضوئيًا",
|
"list_long_scan": "مسح رمز الاستجابة (QR) ضوئيًا",
|
||||||
"list_title": "المحافظ",
|
"list_title": "المحافظ",
|
||||||
"list_tryagain": "إعادة المحاولة",
|
"list_tryagain": "إعادة المحاولة",
|
||||||
"no_ln_wallet_error": "قبل دفع فاتورة برق (Lightning) ، يجب عليك أولاً إضافة محفظة برق (Lightning).",
|
"no_ln_wallet_error": "قبل دفع فاتورة برق (Lightning) ، يجب عليك أولاً إضافة محفظة برق (Lightning).",
|
||||||
|
@ -475,11 +459,9 @@
|
||||||
"reorder_title": "إعادة ترتيب المحافظ",
|
"reorder_title": "إعادة ترتيب المحافظ",
|
||||||
"reorder_instructions": "اضغط باستمرار على اي محفظة لتحريكها عبر القائمة",
|
"reorder_instructions": "اضغط باستمرار على اي محفظة لتحريكها عبر القائمة",
|
||||||
"please_continue_scanning": "الرجاء متابعة الفحص.",
|
"please_continue_scanning": "الرجاء متابعة الفحص.",
|
||||||
"scan_error": "خطأ في الفحص",
|
"select_no_bitcoin": "لا توجد محافظ بتكوين متاحة حاليًا.",
|
||||||
"select_no_bitcoin": "لا توجد محافظ Bitcoin متاحة حاليًا.",
|
|
||||||
"select_no_bitcoin_exp": "تحتاج إلى محفظة بيتكوين لإعادة تعبئة محافظ البرق (Lightning). يُرجى إنشاء محفظة أو استيراد واحدة.",
|
"select_no_bitcoin_exp": "تحتاج إلى محفظة بيتكوين لإعادة تعبئة محافظ البرق (Lightning). يُرجى إنشاء محفظة أو استيراد واحدة.",
|
||||||
"select_wallet": "اختيار محفظة",
|
"select_wallet": "اختيار محفظة",
|
||||||
"take_photo": "التقاط صورة",
|
|
||||||
"xpub_copiedToClipboard": "تم النسخ إلى الحافظة.",
|
"xpub_copiedToClipboard": "تم النسخ إلى الحافظة.",
|
||||||
"pull_to_refresh": "اسحب للتحديث",
|
"pull_to_refresh": "اسحب للتحديث",
|
||||||
"warning_do_not_disclose": "تحذير! لا تنشر هذا.",
|
"warning_do_not_disclose": "تحذير! لا تنشر هذا.",
|
||||||
|
@ -509,7 +491,6 @@
|
||||||
"cosign_this_transaction": "المشاركة في التوقيع على هذه المعاملة؟",
|
"cosign_this_transaction": "المشاركة في التوقيع على هذه المعاملة؟",
|
||||||
"lets_start": "لنبدأ",
|
"lets_start": "لنبدأ",
|
||||||
"create": "إنشاء",
|
"create": "إنشاء",
|
||||||
"provide_key": "قدم مفتاحًا",
|
|
||||||
"native_segwit_title": "أفضل ممارسة",
|
"native_segwit_title": "أفضل ممارسة",
|
||||||
"wrapped_segwit_title": "أفضل توافق",
|
"wrapped_segwit_title": "أفضل توافق",
|
||||||
"legacy_title": "تنسيق قديم",
|
"legacy_title": "تنسيق قديم",
|
||||||
|
@ -526,7 +507,6 @@
|
||||||
"quorum_header": "العدد",
|
"quorum_header": "العدد",
|
||||||
"of": "من",
|
"of": "من",
|
||||||
"wallet_type": "نوع المحفظة",
|
"wallet_type": "نوع المحفظة",
|
||||||
"view_key": "عرض",
|
|
||||||
"invalid_mnemonics": "لا يبدو أن هذه العبارة التذكرية صالحة.",
|
"invalid_mnemonics": "لا يبدو أن هذه العبارة التذكرية صالحة.",
|
||||||
"invalid_cosigner": "بيانات شريك توقيع ليست صحيحة",
|
"invalid_cosigner": "بيانات شريك توقيع ليست صحيحة",
|
||||||
"not_a_multisignature_xpub": "هذه ليست XPUB من محفظة متعددة التوقيعات!",
|
"not_a_multisignature_xpub": "هذه ليست XPUB من محفظة متعددة التوقيعات!",
|
||||||
|
@ -534,14 +514,11 @@
|
||||||
"create_new_key": "إنشاء جديد",
|
"create_new_key": "إنشاء جديد",
|
||||||
"scan_or_open_file": "المسح الضوئي أو استيراد ملف",
|
"scan_or_open_file": "المسح الضوئي أو استيراد ملف",
|
||||||
"i_have_mnemonics": "لدي عبارة تذكيرية لهذا المفتاح.",
|
"i_have_mnemonics": "لدي عبارة تذكيرية لهذا المفتاح.",
|
||||||
"please_write_down_mnemonics": "يُرجى كتابة هذه العبارة التذكيرية على ورقة. لا تقلق، يمكنك كتابتها لاحقًا.",
|
|
||||||
"i_wrote_it_down": "حسنًا، لقد دوَّنتها!",
|
|
||||||
"type_your_mnemonics": "أدخل العبارة التذكيرية لاستيراد مفتاح خزنتك الحالية.",
|
"type_your_mnemonics": "أدخل العبارة التذكيرية لاستيراد مفتاح خزنتك الحالية.",
|
||||||
"this_is_cosigners_xpub": "هذا هو XPUB الخاص بشريك التوقيع—وهو جاهز للاستيراد إلى محفظة أخرى. من الآمن مشاركته.",
|
"this_is_cosigners_xpub": "هذا هو XPUB الخاص بشريك التوقيع—وهو جاهز للاستيراد إلى محفظة أخرى. من الآمن مشاركته.",
|
||||||
"wallet_key_created": "تم انشاء خزنتك. يُرجى أخذ لحظة من وقتك لعمل نسخ احتياطي لعبارتك التذكيرية.",
|
"wallet_key_created": "تم انشاء خزنتك. يُرجى أخذ لحظة من وقتك لعمل نسخ احتياطي لعبارتك التذكيرية.",
|
||||||
"are_you_sure_seed_will_be_lost": "هل أنت متأكد؟ ستفقد عبارتك التذكيرية إذا لم يكن لديك نسخة احتياطية.",
|
"are_you_sure_seed_will_be_lost": "هل أنت متأكد؟ ستفقد عبارتك التذكيرية إذا لم يكن لديك نسخة احتياطية.",
|
||||||
"forget_this_seed": "انسى هذه العبارة التذكيرية واستخدام XPUB بدلا من ذلك.",
|
"forget_this_seed": "انسى هذه العبارة التذكيرية واستخدام XPUB بدلا من ذلك.",
|
||||||
"invalid_fingerprint": "بصمة العبارة التذكيرية هذه لا تتطابق مع بصمة شريك التوقيع.",
|
|
||||||
"view_edit_cosigners": "عرض/تحرير شركاء التوقيع",
|
"view_edit_cosigners": "عرض/تحرير شركاء التوقيع",
|
||||||
"this_cosigner_is_already_imported": "تم استيراد شريك التوقيع هذا بالفعل.",
|
"this_cosigner_is_already_imported": "تم استيراد شريك التوقيع هذا بالفعل.",
|
||||||
"export_signed_psbt": "تصدير توقيع PSBT",
|
"export_signed_psbt": "تصدير توقيع PSBT",
|
||||||
|
@ -594,7 +571,6 @@
|
||||||
"sign_title": "التوقيع/التحقق من الرسالة",
|
"sign_title": "التوقيع/التحقق من الرسالة",
|
||||||
"sign_help": "هنا يمكنك إنشاء أو التحقق من توقيع مشفر بناءً على عنوان Bitcoin.",
|
"sign_help": "هنا يمكنك إنشاء أو التحقق من توقيع مشفر بناءً على عنوان Bitcoin.",
|
||||||
"sign_sign": "توقيع",
|
"sign_sign": "توقيع",
|
||||||
"sign_sign_submit": "توقيع وارسال",
|
|
||||||
"sign_verify": "تحقق",
|
"sign_verify": "تحقق",
|
||||||
"sign_signature_correct": "نجح التحقق!",
|
"sign_signature_correct": "نجح التحقق!",
|
||||||
"sign_signature_incorrect": "فشل التحقق!",
|
"sign_signature_incorrect": "فشل التحقق!",
|
||||||
|
@ -622,5 +598,11 @@
|
||||||
"auth_answer": "لقد قمت بالتوثيق مع {hostname} بنجاح!",
|
"auth_answer": "لقد قمت بالتوثيق مع {hostname} بنجاح!",
|
||||||
"could_not_auth": "لم نتمكن من توثيقك على {hostname}.",
|
"could_not_auth": "لم نتمكن من توثيقك على {hostname}.",
|
||||||
"authenticate": "التوثيق"
|
"authenticate": "التوثيق"
|
||||||
|
},
|
||||||
|
"bip47": {
|
||||||
|
"payment_code": "كود الدفع",
|
||||||
|
"payment_codes_list": "قائمة أكواد الدفع",
|
||||||
|
"who_can_pay_me": "من يستطيع الدفع لي:",
|
||||||
|
"purpose": "أكواد المشاركة التي يمكن أعادة استخدامها (BIP47)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
"of": "{number} от {total}",
|
"of": "{number} от {total}",
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"storage_is_encrypted": "Вашият портфейл е криптиран. Необходима е парола за декриптиране",
|
"storage_is_encrypted": "Вашият портфейл е криптиран. Необходима е парола за декриптиране",
|
||||||
"allow": "Разреши",
|
|
||||||
"dont_allow": "Не разрешавай",
|
|
||||||
"yes": "Да",
|
"yes": "Да",
|
||||||
"no": "Не",
|
"no": "Не",
|
||||||
"save": "Запази",
|
"save": "Запази",
|
||||||
|
@ -18,12 +16,7 @@
|
||||||
"wallet_key": "Парола на портфейла",
|
"wallet_key": "Парола на портфейла",
|
||||||
"invalid_animated_qr_code_fragment": "Невалиден анимиран QRCode фрагмент. Моля, опитай отново.",
|
"invalid_animated_qr_code_fragment": "Невалиден анимиран QRCode фрагмент. Моля, опитай отново.",
|
||||||
"file_saved": "Файлът {filePath} беше запазен в {destination}.",
|
"file_saved": "Файлът {filePath} беше запазен в {destination}.",
|
||||||
"file_save_title": "Запази",
|
"downloads_folder": "Папка с изтегляния"
|
||||||
"file_save_location": "Избери къде да запазиш {filePath}",
|
|
||||||
"downloads_folder": "Папка с изтегляния",
|
|
||||||
"external_storage": "Външно хранилище",
|
|
||||||
"discard_changes": "Отказваш промените?",
|
|
||||||
"discard_changes_detail": "Имате не запазени промени. Искаш ли да излезеш?"
|
|
||||||
},
|
},
|
||||||
"azteco": {
|
"azteco": {
|
||||||
"codeIs": "Цода на вашият ваучър е",
|
"codeIs": "Цода на вашият ваучър е",
|
||||||
|
@ -47,7 +40,6 @@
|
||||||
"lnd": {
|
"lnd": {
|
||||||
"errorInvoiceExpired": "Изтекла фактура",
|
"errorInvoiceExpired": "Изтекла фактура",
|
||||||
"expired": "Изтекла",
|
"expired": "Изтекла",
|
||||||
"expiredLow": "изтекла",
|
|
||||||
"payButton": "Плати",
|
"payButton": "Плати",
|
||||||
"placeholder": "Фактура",
|
"placeholder": "Фактура",
|
||||||
"potentialFee": "Възможна такса: {fee}",
|
"potentialFee": "Възможна такса: {fee}",
|
||||||
|
@ -62,7 +54,6 @@
|
||||||
"additional_info": "Допълнителна информация",
|
"additional_info": "Допълнителна информация",
|
||||||
"for": "За:",
|
"for": "За:",
|
||||||
"lightning_invoice": "Лайтнинг фактура",
|
"lightning_invoice": "Лайтнинг фактура",
|
||||||
"has_been_paid": "Фактурата е платена",
|
|
||||||
"open_direct_channel": "Директно свързване с нода:",
|
"open_direct_channel": "Директно свързване с нода:",
|
||||||
"please_pay": "Моля, плати",
|
"please_pay": "Моля, плати",
|
||||||
"sats": "сатоши",
|
"sats": "сатоши",
|
||||||
|
@ -84,8 +75,7 @@
|
||||||
"ask": "Запазихте ли паролата - 12/24 думи за портфейла? В случай, че изгубите достъп до устройството, паролата е необходима за да въстановите средствата. В случай, че загубите паролата - 12/24 думи, перманентно ще изгубите достъп до средствата.",
|
"ask": "Запазихте ли паролата - 12/24 думи за портфейла? В случай, че изгубите достъп до устройството, паролата е необходима за да въстановите средствата. В случай, че загубите паролата - 12/24 думи, перманентно ще изгубите достъп до средствата.",
|
||||||
"ask_no": "Не, не съм",
|
"ask_no": "Не, не съм",
|
||||||
"ask_yes": "Да",
|
"ask_yes": "Да",
|
||||||
"text_lnd": "Моля, запазете паролата/ думите. Те ви позволяват да възтановите портфейла и средствата си на друго устройство.",
|
"text_lnd": "Моля, запазете паролата/ думите. Те ви позволяват да възтановите портфейла и средствата си на друго устройство."
|
||||||
"text_lnd2": "Този портфейл се подържа от Блу Уолет."
|
|
||||||
},
|
},
|
||||||
"receive": {
|
"receive": {
|
||||||
"details_create": "Създай",
|
"details_create": "Създай",
|
||||||
|
@ -162,7 +152,6 @@
|
||||||
"no_tx_signing_in_progress": "Няма транзакция в прогрес.",
|
"no_tx_signing_in_progress": "Няма транзакция в прогрес.",
|
||||||
"psbt_tx_open": "Отвори подписана транзакция",
|
"psbt_tx_open": "Отвори подписана транзакция",
|
||||||
"psbt_tx_scan": "Подпиши транзакция",
|
"psbt_tx_scan": "Подпиши транзакция",
|
||||||
"qr_error_no_wallet": "Избраният файл не съдържа портфейл който може да бъде импортиран.",
|
|
||||||
"success_done": "Готово",
|
"success_done": "Готово",
|
||||||
"txSaved": "Файл с трансакцията ({filePath}) беше запазен в папката Свалени.",
|
"txSaved": "Файл с трансакцията ({filePath}) беше запазен в папката Свалени.",
|
||||||
"problem_with_psbt": "Проблем с ЧПБТ / PSBT"
|
"problem_with_psbt": "Проблем с ЧПБТ / PSBT"
|
||||||
|
@ -188,7 +177,6 @@
|
||||||
"biom_no_passcode": "Вашето устройство няма създадена парола. За да продължите, конфигурирайте парола в 'Настройки'на устройството.",
|
"biom_no_passcode": "Вашето устройство няма създадена парола. За да продължите, конфигурирайте парола в 'Настройки'на устройството.",
|
||||||
"biom_remove_decrypt": "Всички портфейли ще бъдат изтрити и хранилището ще бъде декриптирано. Сигурни ли сте, че искате да продължите?",
|
"biom_remove_decrypt": "Всички портфейли ще бъдат изтрити и хранилището ще бъде декриптирано. Сигурни ли сте, че искате да продължите?",
|
||||||
"currency": "Валута",
|
"currency": "Валута",
|
||||||
"currency_source": "Котировките са предотставени от",
|
|
||||||
"default_info": "Информация",
|
"default_info": "Информация",
|
||||||
"default_title": "При Стартиране",
|
"default_title": "При Стартиране",
|
||||||
"default_wallets": "Виж всички портфейли",
|
"default_wallets": "Виж всички портфейли",
|
||||||
|
@ -211,7 +199,6 @@
|
||||||
"electrum_clear": "Изчисти",
|
"electrum_clear": "Изчисти",
|
||||||
"encrypt_decrypt": "Декриптирай хранилището",
|
"encrypt_decrypt": "Декриптирай хранилището",
|
||||||
"encrypt_decrypt_q": "Сигурни ли сте, че искате да декриптирате хранилището? Това ще направи портфейлите ви достъпни без парола.",
|
"encrypt_decrypt_q": "Сигурни ли сте, че искате да декриптирате хранилището? Това ще направи портфейлите ви достъпни без парола.",
|
||||||
"encrypt_del_uninstall": "Изтрий в случай, че Блу Уолет е деинсталиран",
|
|
||||||
"encrypt_enc_and_pass": "Криптиран и защитен с парола",
|
"encrypt_enc_and_pass": "Криптиран и защитен с парола",
|
||||||
"encrypt_title": "Сигурност",
|
"encrypt_title": "Сигурност",
|
||||||
"encrypt_tstorage": "Хранилище",
|
"encrypt_tstorage": "Хранилище",
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue