mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 01:40:12 +01:00
Merge branch 'master' into listtsx
This commit is contained in:
commit
ecf9226654
@ -424,7 +424,7 @@ export class BlueReplaceFeeSuggestions extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export function BlueBigCheckmark({ style }) {
|
||||
export function BlueBigCheckmark({ style = {} }) {
|
||||
const defaultStyles = {
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
|
@ -55,7 +55,7 @@ import AztecoRedeem from './screen/receive/aztecoRedeem';
|
||||
import ReceiveDetails from './screen/receive/details';
|
||||
|
||||
import ScanQRCode from './screen/send/ScanQRCode';
|
||||
import Broadcast from './screen/send/broadcast';
|
||||
import Broadcast from './screen/send/Broadcast';
|
||||
import CoinControl from './screen/send/coinControl';
|
||||
import Confirm from './screen/send/confirm';
|
||||
import SendCreate from './screen/send/create';
|
||||
@ -165,7 +165,8 @@ const WalletsRoot = () => {
|
||||
component={LNDViewAdditionalInvoicePreImage}
|
||||
options={LNDViewAdditionalInvoicePreImage.navigationOptions(theme)}
|
||||
/>
|
||||
<WalletsStack.Screen name="Broadcast" component={Broadcast} options={Broadcast.navigationOptions(theme)} />
|
||||
|
||||
<WalletsStack.Screen name="Broadcast" component={Broadcast} options={navigationStyle({ title: loc.send.create_broadcast })(theme)} />
|
||||
<WalletsStack.Screen name="IsItMyAddress" component={IsItMyAddress} options={IsItMyAddress.navigationOptions(theme)} />
|
||||
<WalletsStack.Screen name="GenerateWord" component={GenerateWord} options={GenerateWord.navigationOptions(theme)} />
|
||||
<WalletsStack.Screen name="LnurlPay" component={LnurlPay} options={LnurlPay.navigationOptions(theme)} />
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { getUniqueId } from 'react-native-device-info';
|
||||
import Bugsnag from '@bugsnag/react-native';
|
||||
import BlueApp from '../BlueApp';
|
||||
import { BlueApp as BlueAppClass } from '../class';
|
||||
|
||||
const BlueApp = BlueAppClass.getInstance();
|
||||
|
||||
/**
|
||||
* in case Bugsnag was started, but user decided to opt out while using the app, we have this
|
||||
|
69
blue_modules/start-and-decrypt.ts
Normal file
69
blue_modules/start-and-decrypt.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { Platform } from 'react-native';
|
||||
import Biometric from '../class/biometrics';
|
||||
import prompt from '../helpers/prompt';
|
||||
import loc from '../loc';
|
||||
import { BlueApp as BlueAppClass } from '../class/';
|
||||
|
||||
const BlueApp = BlueAppClass.getInstance();
|
||||
// If attempt reaches 10, a wipe keychain option will be provided to the user.
|
||||
let unlockAttempt = 0;
|
||||
|
||||
export const startAndDecrypt = async (retry?: boolean): Promise<boolean> => {
|
||||
console.log('startAndDecrypt');
|
||||
if (BlueApp.getWallets().length > 0) {
|
||||
console.log('App already has some wallets, so we are in already started state, exiting startAndDecrypt');
|
||||
return true;
|
||||
}
|
||||
await BlueApp.migrateKeys();
|
||||
let password: undefined | string;
|
||||
if (await BlueApp.storageIsEncrypted()) {
|
||||
do {
|
||||
password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted, false);
|
||||
} while (!password);
|
||||
}
|
||||
let success = false;
|
||||
let wasException = false;
|
||||
try {
|
||||
success = await BlueApp.loadFromDisk(password);
|
||||
} catch (error) {
|
||||
// in case of exception reading from keystore, lets retry instead of assuming there is no storage and
|
||||
// proceeding with no wallets
|
||||
console.warn('exception loading from disk:', error);
|
||||
wasException = true;
|
||||
}
|
||||
|
||||
if (wasException) {
|
||||
// retrying, but only once
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000)); // sleep
|
||||
success = await BlueApp.loadFromDisk(password);
|
||||
} catch (error) {
|
||||
console.warn('second exception loading from disk:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
console.log('loaded from disk');
|
||||
// We want to return true to let the UnlockWith screen that its ok to proceed.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (password) {
|
||||
// we had password and yet could not load/decrypt
|
||||
unlockAttempt++;
|
||||
if (unlockAttempt < 10 || Platform.OS !== 'ios') {
|
||||
return startAndDecrypt(true);
|
||||
} else {
|
||||
unlockAttempt = 0;
|
||||
Biometric.showKeychainWipeAlert();
|
||||
// We want to return false to let the UnlockWith screen that it is NOT ok to proceed.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
unlockAttempt = 0;
|
||||
// Return true because there was no wallet data in keychain. Proceed.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
export default BlueApp;
|
@ -1,18 +1,20 @@
|
||||
import React, { createContext, useEffect, useState } from 'react';
|
||||
import { useAsyncStorage } from '@react-native-async-storage/async-storage';
|
||||
|
||||
import BlueApp, { TTXMetadata, startAndDecrypt } from '../BlueApp';
|
||||
import { startAndDecrypt } from './start-and-decrypt';
|
||||
import Notifications from '../blue_modules/notifications';
|
||||
import { LegacyWallet, WatchOnlyWallet } from '../class';
|
||||
import { LegacyWallet, TTXMetadata, WatchOnlyWallet, BlueApp as BlueAppClass } from '../class';
|
||||
import type { TWallet } from '../class/wallets/types';
|
||||
import presentAlert from '../components/Alert';
|
||||
import loc, { STORAGE_KEY as LOC_STORAGE_KEY } from '../loc';
|
||||
import { FiatUnit, TFiatUnit } from '../models/fiatUnit';
|
||||
import * as BlueElectrum from './BlueElectrum';
|
||||
import { PREFERRED_CURRENCY_STORAGE_KEY } from './currency';
|
||||
import { initCurrencyDaemon, PREFERRED_CURRENCY_STORAGE_KEY } from './currency';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from './hapticFeedback';
|
||||
import A from '../blue_modules/analytics';
|
||||
|
||||
const BlueApp = BlueAppClass.getInstance();
|
||||
|
||||
// hashmap of timestamps we _started_ refetching some wallet
|
||||
const _lastTimeTriedToRefetchWallet: { [walletID: string]: number } = {};
|
||||
|
||||
@ -97,6 +99,7 @@ export const BlueStorageProvider = ({ children }: { children: React.ReactNode })
|
||||
|
||||
useEffect(() => {
|
||||
if (walletsInitialized) {
|
||||
initCurrencyDaemon();
|
||||
BlueElectrum.connectMain();
|
||||
}
|
||||
}, [walletsInitialized]);
|
||||
|
@ -1,38 +1,29 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import createHash from 'create-hash';
|
||||
import { Platform } from 'react-native';
|
||||
import DefaultPreference from 'react-native-default-preference';
|
||||
import * as Keychain from 'react-native-keychain';
|
||||
import { Transaction, TWallet } from './wallets/types';
|
||||
import RNSecureKeyStore, { ACCESSIBLE } from 'react-native-secure-key-store';
|
||||
import Realm from 'realm';
|
||||
import { initCurrencyDaemon } from './blue_modules/currency';
|
||||
import * as encryption from './blue_modules/encryption';
|
||||
import {
|
||||
HDAezeedWallet,
|
||||
HDLegacyBreadwalletWallet,
|
||||
HDLegacyElectrumSeedP2PKHWallet,
|
||||
HDLegacyP2PKHWallet,
|
||||
HDSegwitBech32Wallet,
|
||||
HDSegwitElectrumSeedP2WPKHWallet,
|
||||
HDSegwitP2SHWallet,
|
||||
LegacyWallet,
|
||||
LightningCustodianWallet,
|
||||
LightningLdkWallet,
|
||||
MultisigHDWallet,
|
||||
SLIP39LegacyP2PKHWallet,
|
||||
SLIP39SegwitBech32Wallet,
|
||||
SLIP39SegwitP2SHWallet,
|
||||
SegwitBech32Wallet,
|
||||
SegwitP2SHWallet,
|
||||
WatchOnlyWallet,
|
||||
} from './class/';
|
||||
import Biometric from './class/biometrics';
|
||||
import { randomBytes } from './class/rng';
|
||||
import { TWallet, Transaction } from './class/wallets/types';
|
||||
import presentAlert from './components/Alert';
|
||||
import prompt from './helpers/prompt';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import * as encryption from '../blue_modules/encryption';
|
||||
import createHash from 'create-hash';
|
||||
import RNFS from 'react-native-fs';
|
||||
import loc from './loc';
|
||||
import Realm from 'realm';
|
||||
import Keychain from 'react-native-keychain';
|
||||
import { randomBytes } from './rng';
|
||||
import presentAlert from '../components/Alert';
|
||||
import { SegwitBech32Wallet } from './wallets/segwit-bech32-wallet';
|
||||
import { SegwitP2SHWallet } from './wallets/segwit-p2sh-wallet';
|
||||
import { WatchOnlyWallet } from './wallets/watch-only-wallet';
|
||||
import { HDLegacyP2PKHWallet } from './wallets/hd-legacy-p2pkh-wallet';
|
||||
import { HDSegwitP2SHWallet } from './wallets/hd-segwit-p2sh-wallet';
|
||||
import { HDSegwitBech32Wallet } from './wallets/hd-segwit-bech32-wallet';
|
||||
import { HDLegacyBreadwalletWallet } from './wallets/hd-legacy-breadwallet-wallet';
|
||||
import { HDLegacyElectrumSeedP2PKHWallet } from './wallets/hd-legacy-electrum-seed-p2pkh-wallet';
|
||||
import { HDSegwitElectrumSeedP2WPKHWallet } from './wallets/hd-segwit-electrum-seed-p2wpkh-wallet';
|
||||
import { MultisigHDWallet } from './wallets/multisig-hd-wallet';
|
||||
import { HDAezeedWallet } from './wallets/hd-aezeed-wallet';
|
||||
import { LightningLdkWallet } from './wallets/lightning-ldk-wallet';
|
||||
import { SLIP39LegacyP2PKHWallet, SLIP39SegwitBech32Wallet, SLIP39SegwitP2SHWallet } from './wallets/slip39-wallets';
|
||||
import { LightningCustodianWallet } from './wallets/lightning-custodian-wallet';
|
||||
import { LegacyWallet } from './wallets/legacy-wallet';
|
||||
import DefaultPreference from 'react-native-default-preference';
|
||||
|
||||
let usedBucketNum: boolean | number = false;
|
||||
let savingInProgress = 0; // its both a flag and a counter of attempts to write to disk
|
||||
@ -52,14 +43,16 @@ type TRealmTransaction = {
|
||||
|
||||
const isReactNative = typeof navigator !== 'undefined' && navigator?.product === 'ReactNative';
|
||||
|
||||
export class AppStorage {
|
||||
export class BlueApp {
|
||||
static FLAG_ENCRYPTED = 'data_encrypted';
|
||||
static LNDHUB = 'lndhub';
|
||||
static ADVANCED_MODE_ENABLED = 'advancedmodeenabled';
|
||||
static DO_NOT_TRACK = 'donottrack';
|
||||
static HANDOFF_STORAGE_KEY = 'HandOff';
|
||||
|
||||
static keys2migrate = [AppStorage.HANDOFF_STORAGE_KEY, AppStorage.DO_NOT_TRACK, AppStorage.ADVANCED_MODE_ENABLED];
|
||||
private static _instance: BlueApp | null = null;
|
||||
|
||||
static keys2migrate = [BlueApp.HANDOFF_STORAGE_KEY, BlueApp.DO_NOT_TRACK, BlueApp.ADVANCED_MODE_ENABLED];
|
||||
|
||||
public cachedPassword?: false | string;
|
||||
public tx_metadata: TTXMetadata;
|
||||
@ -71,13 +64,21 @@ export class AppStorage {
|
||||
this.cachedPassword = false;
|
||||
}
|
||||
|
||||
static getInstance(): BlueApp {
|
||||
if (!BlueApp._instance) {
|
||||
BlueApp._instance = new BlueApp();
|
||||
}
|
||||
|
||||
return BlueApp._instance;
|
||||
}
|
||||
|
||||
async migrateKeys() {
|
||||
// do not migrate keys if we are not in RN env
|
||||
if (!isReactNative) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key of AppStorage.keys2migrate) {
|
||||
for (const key of BlueApp.keys2migrate) {
|
||||
try {
|
||||
const value = await RNSecureKeyStore.get(key);
|
||||
if (value) {
|
||||
@ -135,9 +136,9 @@ export class AppStorage {
|
||||
storageIsEncrypted = async (): Promise<boolean> => {
|
||||
let data;
|
||||
try {
|
||||
data = await this.getItemWithFallbackToRealm(AppStorage.FLAG_ENCRYPTED);
|
||||
data = await this.getItemWithFallbackToRealm(BlueApp.FLAG_ENCRYPTED);
|
||||
} catch (error: any) {
|
||||
console.warn('error reading `' + AppStorage.FLAG_ENCRYPTED + '` key:', error.message);
|
||||
console.warn('error reading `' + BlueApp.FLAG_ENCRYPTED + '` key:', error.message);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -199,7 +200,7 @@ export class AppStorage {
|
||||
data = JSON.stringify(data);
|
||||
this.cachedPassword = password;
|
||||
await this.setItem('data', data);
|
||||
await this.setItem(AppStorage.FLAG_ENCRYPTED, '1');
|
||||
await this.setItem(BlueApp.FLAG_ENCRYPTED, '1');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -414,7 +415,7 @@ export class AppStorage {
|
||||
unserializedWallet = LightningCustodianWallet.fromJson(key) as unknown as LightningCustodianWallet;
|
||||
let lndhub: false | any = false;
|
||||
try {
|
||||
lndhub = await AsyncStorage.getItem(AppStorage.LNDHUB);
|
||||
lndhub = await AsyncStorage.getItem(BlueApp.LNDHUB);
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
@ -683,12 +684,12 @@ export class AppStorage {
|
||||
}
|
||||
|
||||
await this.setItem('data', JSON.stringify(data));
|
||||
await this.setItem(AppStorage.FLAG_ENCRYPTED, this.cachedPassword ? '1' : '');
|
||||
await this.setItem(BlueApp.FLAG_ENCRYPTED, this.cachedPassword ? '1' : '');
|
||||
|
||||
// now, backing up same data in realm:
|
||||
const realmkeyValue = await this.openRealmKeyValue();
|
||||
this.saveToRealmKeyValue(realmkeyValue, 'data', JSON.stringify(data));
|
||||
this.saveToRealmKeyValue(realmkeyValue, AppStorage.FLAG_ENCRYPTED, this.cachedPassword ? '1' : '');
|
||||
this.saveToRealmKeyValue(realmkeyValue, BlueApp.FLAG_ENCRYPTED, this.cachedPassword ? '1' : '');
|
||||
realmkeyValue.close();
|
||||
} catch (error: any) {
|
||||
console.error('save to disk exception:', error.message);
|
||||
@ -843,50 +844,50 @@ export class AppStorage {
|
||||
|
||||
isAdvancedModeEnabled = async (): Promise<boolean> => {
|
||||
try {
|
||||
return !!(await AsyncStorage.getItem(AppStorage.ADVANCED_MODE_ENABLED));
|
||||
return !!(await AsyncStorage.getItem(BlueApp.ADVANCED_MODE_ENABLED));
|
||||
} catch (_) {}
|
||||
return false;
|
||||
};
|
||||
|
||||
setIsAdvancedModeEnabled = async (value: boolean) => {
|
||||
await AsyncStorage.setItem(AppStorage.ADVANCED_MODE_ENABLED, value ? '1' : '');
|
||||
await AsyncStorage.setItem(BlueApp.ADVANCED_MODE_ENABLED, value ? '1' : '');
|
||||
};
|
||||
|
||||
isHandoffEnabled = async (): Promise<boolean> => {
|
||||
try {
|
||||
return !!(await AsyncStorage.getItem(AppStorage.HANDOFF_STORAGE_KEY));
|
||||
return !!(await AsyncStorage.getItem(BlueApp.HANDOFF_STORAGE_KEY));
|
||||
} catch (_) {}
|
||||
return false;
|
||||
};
|
||||
|
||||
setIsHandoffEnabled = async (value: boolean): Promise<void> => {
|
||||
await AsyncStorage.setItem(AppStorage.HANDOFF_STORAGE_KEY, value ? '1' : '');
|
||||
await AsyncStorage.setItem(BlueApp.HANDOFF_STORAGE_KEY, value ? '1' : '');
|
||||
};
|
||||
|
||||
isDoNotTrackEnabled = async (): Promise<boolean> => {
|
||||
try {
|
||||
const keyExists = await AsyncStorage.getItem(AppStorage.DO_NOT_TRACK);
|
||||
const keyExists = await AsyncStorage.getItem(BlueApp.DO_NOT_TRACK);
|
||||
if (keyExists !== null) {
|
||||
const doNotTrackValue = !!keyExists;
|
||||
if (doNotTrackValue) {
|
||||
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
|
||||
await DefaultPreference.set(AppStorage.DO_NOT_TRACK, '1');
|
||||
AsyncStorage.removeItem(AppStorage.DO_NOT_TRACK);
|
||||
await DefaultPreference.set(BlueApp.DO_NOT_TRACK, '1');
|
||||
AsyncStorage.removeItem(BlueApp.DO_NOT_TRACK);
|
||||
} else {
|
||||
return Boolean(await DefaultPreference.get(AppStorage.DO_NOT_TRACK));
|
||||
return Boolean(await DefaultPreference.get(BlueApp.DO_NOT_TRACK));
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
const doNotTrackValue = await DefaultPreference.get(AppStorage.DO_NOT_TRACK);
|
||||
const doNotTrackValue = await DefaultPreference.get(BlueApp.DO_NOT_TRACK);
|
||||
return doNotTrackValue === '1' || false;
|
||||
};
|
||||
|
||||
setDoNotTrack = async (value: boolean) => {
|
||||
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
|
||||
if (value) {
|
||||
await DefaultPreference.set(AppStorage.DO_NOT_TRACK, '1');
|
||||
await DefaultPreference.set(BlueApp.DO_NOT_TRACK, '1');
|
||||
} else {
|
||||
await DefaultPreference.clear(AppStorage.DO_NOT_TRACK);
|
||||
await DefaultPreference.clear(BlueApp.DO_NOT_TRACK);
|
||||
}
|
||||
};
|
||||
|
||||
@ -938,69 +939,3 @@ export class AppStorage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const BlueApp = new AppStorage();
|
||||
// If attempt reaches 10, a wipe keychain option will be provided to the user.
|
||||
let unlockAttempt = 0;
|
||||
|
||||
export const startAndDecrypt = async (retry?: boolean): Promise<boolean> => {
|
||||
console.log('startAndDecrypt');
|
||||
if (BlueApp.getWallets().length > 0) {
|
||||
console.log('App already has some wallets, so we are in already started state, exiting startAndDecrypt');
|
||||
return true;
|
||||
}
|
||||
await BlueApp.migrateKeys();
|
||||
let password: undefined | string;
|
||||
if (await BlueApp.storageIsEncrypted()) {
|
||||
do {
|
||||
password = await prompt((retry && loc._.bad_password) || loc._.enter_password, loc._.storage_is_encrypted, false);
|
||||
} while (!password);
|
||||
}
|
||||
let success = false;
|
||||
let wasException = false;
|
||||
try {
|
||||
success = await BlueApp.loadFromDisk(password);
|
||||
} catch (error) {
|
||||
// in case of exception reading from keystore, lets retry instead of assuming there is no storage and
|
||||
// proceeding with no wallets
|
||||
console.warn('exception loading from disk:', error);
|
||||
wasException = true;
|
||||
}
|
||||
|
||||
if (wasException) {
|
||||
// retrying, but only once
|
||||
try {
|
||||
await new Promise(resolve => setTimeout(resolve, 3000)); // sleep
|
||||
success = await BlueApp.loadFromDisk(password);
|
||||
} catch (error) {
|
||||
console.warn('second exception loading from disk:', error);
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
console.log('loaded from disk');
|
||||
// We want to return true to let the UnlockWith screen that its ok to proceed.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (password) {
|
||||
// we had password and yet could not load/decrypt
|
||||
unlockAttempt++;
|
||||
if (unlockAttempt < 10 || Platform.OS !== 'ios') {
|
||||
return startAndDecrypt(true);
|
||||
} else {
|
||||
unlockAttempt = 0;
|
||||
Biometric.showKeychainWipeAlert();
|
||||
// We want to return false to let the UnlockWith screen that it is NOT ok to proceed.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
unlockAttempt = 0;
|
||||
// Return true because there was no wallet data in keychain. Proceed.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
initCurrencyDaemon();
|
||||
|
||||
export default BlueApp;
|
@ -5,11 +5,10 @@ import URL from 'url';
|
||||
|
||||
import { readFileOutsideSandbox } from '../blue_modules/fs';
|
||||
import { Chain } from '../models/bitcoinUnits';
|
||||
import { LightningCustodianWallet, WatchOnlyWallet } from './';
|
||||
import { BlueApp, LightningCustodianWallet, WatchOnlyWallet } from './';
|
||||
import Azteco from './azteco';
|
||||
import Lnurl from './lnurl';
|
||||
import type { TWallet } from './wallets/types';
|
||||
import { AppStorage } from '../BlueApp';
|
||||
|
||||
type TCompletionHandlerParams = [string, object];
|
||||
type TContext = {
|
||||
@ -232,7 +231,7 @@ class DeeplinkSchemaMatch {
|
||||
w.setLabel(w.typeReadable);
|
||||
|
||||
try {
|
||||
const lndhub = await AsyncStorage.getItem(AppStorage.LNDHUB);
|
||||
const lndhub = await AsyncStorage.getItem(BlueApp.LNDHUB);
|
||||
if (lndhub) {
|
||||
w.setBaseURI(lndhub);
|
||||
w.init();
|
||||
|
@ -18,3 +18,4 @@ export * from './wallets/multisig-hd-wallet';
|
||||
export * from './wallets/slip39-wallets';
|
||||
export * from './hd-segwit-bech32-transaction';
|
||||
export * from './multisig-cosigner';
|
||||
export * from './blue-app';
|
@ -4,14 +4,14 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { useTheme } from './themes';
|
||||
|
||||
const BORDER_RADIUS = 30;
|
||||
const PADDINGS = 8;
|
||||
const BORDER_RADIUS = 8;
|
||||
const PADDINGS = 24;
|
||||
const ICON_MARGIN = 7;
|
||||
|
||||
const cStyles = StyleSheet.create({
|
||||
root: {
|
||||
alignSelf: 'center',
|
||||
height: '6.3%',
|
||||
height: '6.9%',
|
||||
minHeight: 44,
|
||||
},
|
||||
rootAbsolute: {
|
||||
@ -23,7 +23,6 @@ const cStyles = StyleSheet.create({
|
||||
bottom: -1000,
|
||||
},
|
||||
rootPost: {
|
||||
borderRadius: BORDER_RADIUS,
|
||||
flexDirection: 'row',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
@ -138,6 +137,7 @@ export const FButton = ({ text, icon, width, first, last, ...props }: FButtonPro
|
||||
const bStylesHook = StyleSheet.create({
|
||||
root: {
|
||||
backgroundColor: colors.buttonBackgroundColor,
|
||||
borderRadius: BORDER_RADIUS,
|
||||
},
|
||||
text: {
|
||||
color: colors.buttonAlternativeTextColor,
|
||||
@ -145,19 +145,25 @@ export const FButton = ({ text, icon, width, first, last, ...props }: FButtonPro
|
||||
textDisabled: {
|
||||
color: colors.formBorder,
|
||||
},
|
||||
marginRight: {
|
||||
marginRight: 10,
|
||||
},
|
||||
});
|
||||
const style: Record<string, any> = {};
|
||||
const additionalStyles = !last ? bStylesHook.marginRight : {};
|
||||
|
||||
if (width) {
|
||||
const paddingLeft = first ? BORDER_RADIUS / 2 : PADDINGS;
|
||||
const paddingRight = last ? BORDER_RADIUS / 2 : PADDINGS;
|
||||
style.paddingRight = paddingRight;
|
||||
style.paddingLeft = paddingLeft;
|
||||
style.width = width + paddingRight + paddingLeft;
|
||||
style.paddingHorizontal = PADDINGS;
|
||||
style.width = width + PADDINGS * 2;
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity accessibilityLabel={text} accessibilityRole="button" style={[bStyles.root, bStylesHook.root, style]} {...props}>
|
||||
<TouchableOpacity
|
||||
accessibilityLabel={text}
|
||||
accessibilityRole="button"
|
||||
style={[bStyles.root, bStylesHook.root, style, additionalStyles]}
|
||||
{...props}
|
||||
>
|
||||
<View style={bStyles.icon}>{icon}</View>
|
||||
<Text numberOfLines={1} style={[bStyles.text, props.disabled ? bStylesHook.textDisabled : bStylesHook.text]}>
|
||||
{text}
|
||||
|
@ -208,9 +208,9 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
|
||||
// @ts-ignore: Ugh
|
||||
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
numberOfLines={1}
|
||||
minimumFontScale={0.5}
|
||||
adjustsFontSizeToFit
|
||||
style={styles.walletBalanceText}
|
||||
ellipsizeMode="middle"
|
||||
>
|
||||
{balance}
|
||||
</Text>
|
||||
@ -250,24 +250,23 @@ const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps>
|
||||
)}
|
||||
|
||||
{wallet.allowBIP47() && wallet.isBIP47Enabled() && (
|
||||
<TouchableOpacity accessibilityRole="button" onPress={handleOnPaymentCodeButtonPressed}>
|
||||
<View style={styles.manageFundsButton}>
|
||||
<Text style={styles.manageFundsButtonText}>{loc.bip47.payment_code}</Text>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.manageFundsButton} accessibilityRole="button" onPress={handleOnPaymentCodeButtonPressed}>
|
||||
<Text style={styles.manageFundsButtonText}>{loc.bip47.payment_code}</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{wallet.type === LightningLdkWallet.type && (
|
||||
<TouchableOpacity accessibilityRole="button" accessibilityLabel={loc.lnd.title} onPress={handleManageFundsPressed}>
|
||||
<View style={styles.manageFundsButton}>
|
||||
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.manageFundsButton}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={loc.lnd.title}
|
||||
onPress={handleManageFundsPressed}
|
||||
>
|
||||
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{wallet.type === MultisigHDWallet.type && (
|
||||
<TouchableOpacity accessibilityRole="button" onPress={handleManageFundsPressed}>
|
||||
<View style={styles.manageFundsButton}>
|
||||
<Text style={styles.manageFundsButtonText}>{loc.multisig.manage_keys}</Text>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.manageFundsButton} accessibilityRole="button" onPress={handleManageFundsPressed}>
|
||||
<Text style={styles.manageFundsButtonText}>{loc.multisig.manage_keys}</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</LinearGradient>
|
||||
@ -297,6 +296,7 @@ const styles = StyleSheet.create({
|
||||
walletBalance: {
|
||||
flexShrink: 1,
|
||||
marginRight: 6,
|
||||
height: 34,
|
||||
},
|
||||
manageFundsButton: {
|
||||
marginTop: 14,
|
||||
|
@ -103,6 +103,9 @@ const iStyles = StyleSheet.create({
|
||||
borderRadius: 12,
|
||||
minHeight: 164,
|
||||
},
|
||||
balanceContainer: {
|
||||
height: 40,
|
||||
},
|
||||
image: {
|
||||
width: 99,
|
||||
height: 94,
|
||||
@ -218,21 +221,23 @@ export const WalletCarouselItem = ({ item, _, onPress, handleLongPress, isSelect
|
||||
<Text numberOfLines={1} style={[iStyles.label, { color: colors.inverseForegroundColor }]}>
|
||||
{item.getLabel()}
|
||||
</Text>
|
||||
{item.hideBalance ? (
|
||||
<>
|
||||
<BlueSpacing10 />
|
||||
<BlurredBalanceView />
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
ellipsizeMode="middle"
|
||||
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
|
||||
>
|
||||
{`${balance} `}
|
||||
</Text>
|
||||
)}
|
||||
<View style={iStyles.balanceContainer}>
|
||||
{item.hideBalance ? (
|
||||
<>
|
||||
<BlueSpacing10 />
|
||||
<BlurredBalanceView />
|
||||
</>
|
||||
) : (
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
adjustsFontSizeToFit
|
||||
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
||||
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
|
||||
>
|
||||
{`${balance} `}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<Text style={iStyles.br} />
|
||||
<Text numberOfLines={1} style={[iStyles.latestTx, { color: colors.inverseForegroundColor }]}>
|
||||
{loc.wallets.list_latest_transaction}
|
||||
|
@ -15,9 +15,8 @@
|
||||
6D2A6464258BA92D0092292B /* Stickers.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6D2A6463258BA92D0092292B /* Stickers.xcassets */; };
|
||||
6D2A6468258BA92D0092292B /* Stickers.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6D2A6461258BA92C0092292B /* Stickers.appex */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
6D32C5C62596CE3A008C077C /* EventEmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6D32C5C52596CE3A008C077C /* EventEmitter.m */; };
|
||||
6D4AF15925D21172009DD853 /* WidgetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */; };
|
||||
6D4AF16325D21185009DD853 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */; };
|
||||
6D4AF16D25D21192009DD853 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Models.swift */; };
|
||||
6D4AF15925D21172009DD853 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; };
|
||||
6D4AF16D25D21192009DD853 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; };
|
||||
6D4AF17825D211A3009DD853 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
|
||||
6D4AF18425D215D1009DD853 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; };
|
||||
6DD4109D266CADF10087DE03 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6D333B3A252FE1A3004D72DF /* WidgetKit.framework */; };
|
||||
@ -25,14 +24,12 @@
|
||||
6DD410A1266CADF10087DE03 /* Widgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DD410A0266CADF10087DE03 /* Widgets.swift */; };
|
||||
6DD410A7266CADF40087DE03 /* WidgetsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 6DD4109C266CADF10087DE03 /* WidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
6DD410AC266CAE470087DE03 /* PriceWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA4BC255872E3009312A5 /* PriceWidget.swift */; };
|
||||
6DD410AE266CAF1F0087DE03 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
||||
6DD410AF266CAF5C0087DE03 /* WalletInformationAndMarketWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E06254BA347007B5B82 /* WalletInformationAndMarketWidget.swift */; };
|
||||
6DD410B0266CAF5C0087DE03 /* WalletInformationWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4AB1254FB59C00E9F9AA /* WalletInformationWidget.swift */; };
|
||||
6DD410B1266CAF5C0087DE03 /* WidgetAPI+Electrum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */; };
|
||||
6DD410B1266CAF5C0087DE03 /* MarketAPI+Electrum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */; };
|
||||
6DD410B2266CAF5C0087DE03 /* WalletInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F2225525053003792DF /* WalletInformationView.swift */; };
|
||||
6DD410B3266CAF5C0087DE03 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; };
|
||||
6DD410B4266CAF5C0087DE03 /* WidgetAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */; };
|
||||
6DD410B5266CAF5C0087DE03 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */; };
|
||||
6DD410B4266CAF5C0087DE03 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; };
|
||||
6DD410B6266CAF5C0087DE03 /* PriceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6CA5272558EC52009312A5 /* PriceView.swift */; };
|
||||
6DD410B7266CAF5C0087DE03 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6D9A2E08254BA348007B5B82 /* Assets.xcassets */; };
|
||||
6DD410B8266CAF5C0087DE03 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; };
|
||||
@ -40,7 +37,7 @@
|
||||
6DD410BA266CAF5C0087DE03 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
|
||||
6DD410BB266CAF5C0087DE03 /* MarketView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F17255226DA003792DF /* MarketView.swift */; };
|
||||
6DD410BE266CAF5C0087DE03 /* SendReceiveButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F3425526311003792DF /* SendReceiveButtons.swift */; };
|
||||
6DD410BF266CB13D0087DE03 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Models.swift */; };
|
||||
6DD410BF266CB13D0087DE03 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; };
|
||||
6DD410C0266CB1460087DE03 /* MarketWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9946622555A660000E52E8 /* MarketWidget.swift */; };
|
||||
6DF25A9F249DB97E001D06F5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6DF25A9E249DB97E001D06F5 /* LaunchScreen.storyboard */; };
|
||||
6DFC807024EA0B6C007B8700 /* EFQRCode in Frameworks */ = {isa = PBXBuildFile; productRef = 6DFC806F24EA0B6C007B8700 /* EFQRCode */; };
|
||||
@ -75,6 +72,70 @@
|
||||
B43D037B225847C500FBAA95 /* TransactionTableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0375225847C500FBAA95 /* TransactionTableRow.swift */; };
|
||||
B43D037C225847C500FBAA95 /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0376225847C500FBAA95 /* Wallet.swift */; };
|
||||
B43D037D225847C500FBAA95 /* WalletInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B43D0377225847C500FBAA95 /* WalletInformation.swift */; };
|
||||
B44033BF2BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; };
|
||||
B44033C02BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; };
|
||||
B44033C12BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; };
|
||||
B44033C22BCC32F800162242 /* BitcoinUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033BE2BCC32F800162242 /* BitcoinUnit.swift */; };
|
||||
B44033C42BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; };
|
||||
B44033C52BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; };
|
||||
B44033C62BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; };
|
||||
B44033C72BCC332400162242 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C32BCC332400162242 /* Balance.swift */; };
|
||||
B44033CA2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; };
|
||||
B44033CB2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; };
|
||||
B44033CC2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; };
|
||||
B44033CD2BCC350A00162242 /* Currency.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033C92BCC350A00162242 /* Currency.swift */; };
|
||||
B44033CE2BCC352900162242 /* UserDefaultsGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */; };
|
||||
B44033CF2BCC352C00162242 /* UserDefaultsGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */; };
|
||||
B44033D02BCC352F00162242 /* UserDefaultsGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */; };
|
||||
B44033D32BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; };
|
||||
B44033D42BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; };
|
||||
B44033D52BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; };
|
||||
B44033D62BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */; };
|
||||
B44033D72BCC369400162242 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; };
|
||||
B44033D82BCC369500162242 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */; };
|
||||
B44033D92BCC369900162242 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; };
|
||||
B44033DA2BCC369A00162242 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; };
|
||||
B44033DB2BCC369B00162242 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4C3A254FBF4800E9F9AA /* Colors.swift */; };
|
||||
B44033DD2BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; };
|
||||
B44033DE2BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; };
|
||||
B44033DF2BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; };
|
||||
B44033E02BCC36C300162242 /* LatestTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033DC2BCC36C300162242 /* LatestTransaction.swift */; };
|
||||
B44033E12BCC36CA00162242 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; };
|
||||
B44033E22BCC36CB00162242 /* Placeholders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */; };
|
||||
B44033E42BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; };
|
||||
B44033E52BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; };
|
||||
B44033E62BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; };
|
||||
B44033E72BCC36FF00162242 /* WalletData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E32BCC36FF00162242 /* WalletData.swift */; };
|
||||
B44033E92BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; };
|
||||
B44033EA2BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; };
|
||||
B44033EB2BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; };
|
||||
B44033EC2BCC371A00162242 /* MarketData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033E82BCC371A00162242 /* MarketData.swift */; };
|
||||
B44033EE2BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; };
|
||||
B44033EF2BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; };
|
||||
B44033F02BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; };
|
||||
B44033F12BCC374500162242 /* Numeric+abbreviated.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */; };
|
||||
B44033F42BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; };
|
||||
B44033F52BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; };
|
||||
B44033F62BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; };
|
||||
B44033F72BCC377F00162242 /* WidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F32BCC377F00162242 /* WidgetData.swift */; };
|
||||
B44033F92BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; };
|
||||
B44033FA2BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; };
|
||||
B44033FB2BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; };
|
||||
B44033FC2BCC379200162242 /* WidgetDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033F82BCC379200162242 /* WidgetDataStore.swift */; };
|
||||
B44033FD2BCC37D600162242 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; };
|
||||
B44033FE2BCC37D700162242 /* MarketAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */; };
|
||||
B44034002BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; };
|
||||
B44034012BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; };
|
||||
B44034022BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; };
|
||||
B44034032BCC37F800162242 /* Bundle+decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B44033FF2BCC37F800162242 /* Bundle+decode.swift */; };
|
||||
B44034042BCC389100162242 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; };
|
||||
B44034052BCC389200162242 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; };
|
||||
B44034062BCC389F00162242 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
|
||||
B44034072BCC38A000162242 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
|
||||
B440340F2BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; };
|
||||
B44034102BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; };
|
||||
B44034112BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; };
|
||||
B44034122BCC40A400162242 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = B440340E2BCC40A400162242 /* fiatUnits.json */; };
|
||||
B4549F362B82B10D002E3153 /* ci_post_clone.sh in Resources */ = {isa = PBXBuildFile; fileRef = B4549F352B82B10D002E3153 /* ci_post_clone.sh */; };
|
||||
B461B852299599F800E431AA /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = B461B851299599F800E431AA /* AppDelegate.mm */; };
|
||||
B47B21EC2B2128B8001F6690 /* BlueWalletUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B47B21EB2B2128B8001F6690 /* BlueWalletUITests.swift */; };
|
||||
@ -97,8 +158,6 @@
|
||||
B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; };
|
||||
C59F90CE0D04D3E4BB39BC5D /* libPods-BlueWalletUITests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F02C2F7CA3591E4E0B06EBA /* libPods-BlueWalletUITests.a */; };
|
||||
C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||
E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
||||
E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -151,13 +210,6 @@
|
||||
remoteGlobalIDString = B4A29A212B55C990002A67DF;
|
||||
remoteInfo = "BlueWallet-NoLDK";
|
||||
};
|
||||
B4A29A232B55C990002A67DF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = B40D4E2F225841EC00428FCC;
|
||||
remoteInfo = BlueWalletWatch;
|
||||
};
|
||||
B4A29A252B55C990002A67DF /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
|
||||
@ -310,21 +362,19 @@
|
||||
6D641F2225525053003792DF /* WalletInformationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationView.swift; sourceTree = "<group>"; };
|
||||
6D641F3425526311003792DF /* SendReceiveButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendReceiveButtons.swift; sourceTree = "<group>"; };
|
||||
6D6CA4BC255872E3009312A5 /* PriceWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceWidget.swift; sourceTree = "<group>"; };
|
||||
6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WidgetAPI+Electrum.swift"; sourceTree = "<group>"; };
|
||||
6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarketAPI+Electrum.swift"; sourceTree = "<group>"; };
|
||||
6D6CA5272558EC52009312A5 /* PriceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceView.swift; sourceTree = "<group>"; };
|
||||
6D9946622555A660000E52E8 /* MarketWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketWidget.swift; sourceTree = "<group>"; };
|
||||
6D9A2E06254BA347007B5B82 /* WalletInformationAndMarketWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationAndMarketWidget.swift; sourceTree = "<group>"; };
|
||||
6D9A2E08254BA348007B5B82 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetAPI.swift; sourceTree = "<group>"; };
|
||||
6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = "<group>"; };
|
||||
6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketAPI.swift; sourceTree = "<group>"; };
|
||||
6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroup.swift; sourceTree = "<group>"; };
|
||||
6DD4109C266CADF10087DE03 /* WidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
6DD410A0266CADF10087DE03 /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = "<group>"; };
|
||||
6DD410A4266CADF40087DE03 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
6DD410AD266CAF1F0087DE03 /* fiatUnits.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = fiatUnits.json; path = ../../../../models/fiatUnits.json; sourceTree = "<group>"; };
|
||||
6DD410C3266CCB780087DE03 /* WidgetsExtension.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = WidgetsExtension.entitlements; sourceTree = SOURCE_ROOT; };
|
||||
6DEB4AB1254FB59C00E9F9AA /* WalletInformationWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletInformationWidget.swift; sourceTree = "<group>"; };
|
||||
6DEB4BFA254FBA0E00E9F9AA /* Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = "<group>"; };
|
||||
6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Placeholders.swift; sourceTree = "<group>"; };
|
||||
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
|
||||
6DF25A9E249DB97E001D06F5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
6DFC807124EA2FA9007B8700 /* ViewQRCodefaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewQRCodefaceController.swift; sourceTree = "<group>"; };
|
||||
@ -375,6 +425,18 @@
|
||||
B43D0376225847C500FBAA95 /* Wallet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Wallet.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; };
|
||||
B44033BE2BCC32F800162242 /* BitcoinUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BitcoinUnit.swift; sourceTree = "<group>"; };
|
||||
B44033C32BCC332400162242 /* Balance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Balance.swift; sourceTree = "<group>"; };
|
||||
B44033C92BCC350A00162242 /* Currency.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = "<group>"; };
|
||||
B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsGroupKey.swift; sourceTree = "<group>"; };
|
||||
B44033DC2BCC36C300162242 /* LatestTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestTransaction.swift; sourceTree = "<group>"; };
|
||||
B44033E32BCC36FF00162242 /* WalletData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletData.swift; sourceTree = "<group>"; };
|
||||
B44033E82BCC371A00162242 /* MarketData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketData.swift; sourceTree = "<group>"; };
|
||||
B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Numeric+abbreviated.swift"; sourceTree = "<group>"; };
|
||||
B44033F32BCC377F00162242 /* WidgetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetData.swift; sourceTree = "<group>"; };
|
||||
B44033F82BCC379200162242 /* WidgetDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDataStore.swift; sourceTree = "<group>"; };
|
||||
B44033FF2BCC37F800162242 /* Bundle+decode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+decode.swift"; sourceTree = "<group>"; };
|
||||
B440340E2BCC40A400162242 /* fiatUnits.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = fiatUnits.json; path = ../../../models/fiatUnits.json; sourceTree = "<group>"; };
|
||||
B4549F352B82B10D002E3153 /* ci_post_clone.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = ci_post_clone.sh; 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>"; };
|
||||
@ -567,7 +629,8 @@
|
||||
6D2AA8062568B8E50090B089 /* Fiat */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6DD410AD266CAF1F0087DE03 /* fiatUnits.json */,
|
||||
B440340E2BCC40A400162242 /* fiatUnits.json */,
|
||||
B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */,
|
||||
6D2AA8072568B8F40090B089 /* FiatUnit.swift */,
|
||||
);
|
||||
path = Fiat;
|
||||
@ -625,16 +688,7 @@
|
||||
6DEB4BC1254FB98300E9F9AA /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */,
|
||||
6D2AA8062568B8E50090B089 /* Fiat */,
|
||||
6DEB4DD82552260200E9F9AA /* Views */,
|
||||
6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */,
|
||||
6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */,
|
||||
6D9A2E6B254BAB1B007B5B82 /* WidgetDataStore.swift */,
|
||||
6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */,
|
||||
6DEB4BFA254FBA0E00E9F9AA /* Models.swift */,
|
||||
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */,
|
||||
6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */,
|
||||
6D4AF18225D215D0009DD853 /* BlueWalletWatch-Bridging-Header.h */,
|
||||
B40FC3F829CCD1AC0007EBAC /* SwiftTCPClient.swift */,
|
||||
);
|
||||
@ -655,6 +709,7 @@
|
||||
83CBB9F61A601CBA00E9B192 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B44033C82BCC34AC00162242 /* Shared */,
|
||||
B41C2E552BB3DCB8000FE097 /* PrivacyInfo.xcprivacy */,
|
||||
B4549F2E2B80FEA1002E3153 /* ci_scripts */,
|
||||
13B07FAE1A68108700A75B9A /* BlueWallet */,
|
||||
@ -766,6 +821,31 @@
|
||||
path = Objects;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B44033C82BCC34AC00162242 /* Shared */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
6D2AA8062568B8E50090B089 /* Fiat */,
|
||||
6D9A2E6A254BAB1B007B5B82 /* MarketAPI.swift */,
|
||||
6D6CA5142558EBA3009312A5 /* MarketAPI+Electrum.swift */,
|
||||
B44033C92BCC350A00162242 /* Currency.swift */,
|
||||
6DA7047D254E24D5005FE5E2 /* UserDefaultsGroup.swift */,
|
||||
6DEB4C3A254FBF4800E9F9AA /* Colors.swift */,
|
||||
6D4AF18325D215D1009DD853 /* UserDefaultsExtension.swift */,
|
||||
B44033D22BCC368800162242 /* UserDefaultsGroupKey.swift */,
|
||||
B44033DC2BCC36C300162242 /* LatestTransaction.swift */,
|
||||
B44033E32BCC36FF00162242 /* WalletData.swift */,
|
||||
B44033E82BCC371A00162242 /* MarketData.swift */,
|
||||
B44033ED2BCC374500162242 /* Numeric+abbreviated.swift */,
|
||||
B44033F32BCC377F00162242 /* WidgetData.swift */,
|
||||
B44033F82BCC379200162242 /* WidgetDataStore.swift */,
|
||||
B44033FF2BCC37F800162242 /* Bundle+decode.swift */,
|
||||
6DEB4BFA254FBA0E00E9F9AA /* Placeholders.swift */,
|
||||
B44033BE2BCC32F800162242 /* BitcoinUnit.swift */,
|
||||
B44033C32BCC332400162242 /* Balance.swift */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B4549F2E2B80FEA1002E3153 /* ci_scripts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -951,7 +1031,6 @@
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
B4A29A222B55C990002A67DF /* PBXTargetDependency */,
|
||||
B4A29A242B55C990002A67DF /* PBXTargetDependency */,
|
||||
B4A29A262B55C990002A67DF /* PBXTargetDependency */,
|
||||
B4A29A282B55C990002A67DF /* PBXTargetDependency */,
|
||||
@ -1061,6 +1140,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6DF25A9F249DB97E001D06F5 /* LaunchScreen.storyboard in Resources */,
|
||||
B440340F2BCC40A400162242 /* fiatUnits.json in Resources */,
|
||||
84E05A842721191B001A0D3A /* Settings.bundle in Resources */,
|
||||
B4549F362B82B10D002E3153 /* ci_post_clone.sh in Resources */,
|
||||
B41C2E562BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
@ -1081,8 +1161,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B41C2E582BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
B44034112BCC40A400162242 /* fiatUnits.json in Resources */,
|
||||
6DD410B7266CAF5C0087DE03 /* Assets.xcassets in Resources */,
|
||||
6DD410AE266CAF1F0087DE03 /* fiatUnits.json in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1091,7 +1171,6 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B40D4E36225841ED00428FCC /* Assets.xcassets in Resources */,
|
||||
E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */,
|
||||
B40D4E34225841EC00428FCC /* Interface.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -1101,8 +1180,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B41C2E572BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
B44034102BCC40A400162242 /* fiatUnits.json in Resources */,
|
||||
B4EE583C226703320003363C /* Assets.xcassets in Resources */,
|
||||
E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1118,6 +1197,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B41C2E592BB3DCB8000FE097 /* PrivacyInfo.xcprivacy in Resources */,
|
||||
B44034122BCC40A400162242 /* fiatUnits.json in Resources */,
|
||||
B4A29A352B55C990002A67DF /* LaunchScreen.storyboard in Resources */,
|
||||
B4A29A372B55C990002A67DF /* Images.xcassets in Resources */,
|
||||
);
|
||||
@ -1420,12 +1500,30 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B44033E92BCC371A00162242 /* MarketData.swift in Sources */,
|
||||
B44033CA2BCC350A00162242 /* Currency.swift in Sources */,
|
||||
B4AB21092B61DC3F0080440C /* SplashScreen.m in Sources */,
|
||||
B44033EE2BCC374500162242 /* Numeric+abbreviated.swift in Sources */,
|
||||
B4AB21072B61D8CA0080440C /* SplashScreen.swift in Sources */,
|
||||
B44033DD2BCC36C300162242 /* LatestTransaction.swift in Sources */,
|
||||
6D32C5C62596CE3A008C077C /* EventEmitter.m in Sources */,
|
||||
B44033FE2BCC37D700162242 /* MarketAPI.swift in Sources */,
|
||||
B44033CE2BCC352900162242 /* UserDefaultsGroup.swift in Sources */,
|
||||
13B07FC11A68108700A75B9A /* main.m in Sources */,
|
||||
B461B852299599F800E431AA /* AppDelegate.mm in Sources */,
|
||||
B44033F42BCC377F00162242 /* WidgetData.swift in Sources */,
|
||||
B44033C42BCC332400162242 /* Balance.swift in Sources */,
|
||||
B44034072BCC38A000162242 /* FiatUnit.swift in Sources */,
|
||||
B44034002BCC37F800162242 /* Bundle+decode.swift in Sources */,
|
||||
B44033E22BCC36CB00162242 /* Placeholders.swift in Sources */,
|
||||
B44033DA2BCC369A00162242 /* Colors.swift in Sources */,
|
||||
B44033D32BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */,
|
||||
32B5A32A2334450100F8D608 /* Bridge.swift in Sources */,
|
||||
B44033D82BCC369500162242 /* UserDefaultsExtension.swift in Sources */,
|
||||
B44033E42BCC36FF00162242 /* WalletData.swift in Sources */,
|
||||
B44033BF2BCC32F800162242 /* BitcoinUnit.swift in Sources */,
|
||||
B44034052BCC389200162242 /* XMLParserDelegate.swift in Sources */,
|
||||
B44033F92BCC379200162242 /* WidgetDataStore.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1434,22 +1532,32 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6DD410BE266CAF5C0087DE03 /* SendReceiveButtons.swift in Sources */,
|
||||
6DD410B4266CAF5C0087DE03 /* WidgetAPI.swift in Sources */,
|
||||
6DD410B4266CAF5C0087DE03 /* MarketAPI.swift in Sources */,
|
||||
B40FC3FA29CCD1D00007EBAC /* SwiftTCPClient.swift in Sources */,
|
||||
6DD410A1266CADF10087DE03 /* Widgets.swift in Sources */,
|
||||
6DD410AC266CAE470087DE03 /* PriceWidget.swift in Sources */,
|
||||
B44033D52BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */,
|
||||
6DD410B2266CAF5C0087DE03 /* WalletInformationView.swift in Sources */,
|
||||
B44034022BCC37F800162242 /* Bundle+decode.swift in Sources */,
|
||||
B44033CC2BCC350A00162242 /* Currency.swift in Sources */,
|
||||
6DD410B6266CAF5C0087DE03 /* PriceView.swift in Sources */,
|
||||
6DD410B3266CAF5C0087DE03 /* Colors.swift in Sources */,
|
||||
B44033C12BCC32F800162242 /* BitcoinUnit.swift in Sources */,
|
||||
6DD410BB266CAF5C0087DE03 /* MarketView.swift in Sources */,
|
||||
6DD410B5266CAF5C0087DE03 /* WidgetDataStore.swift in Sources */,
|
||||
B44033F02BCC374500162242 /* Numeric+abbreviated.swift in Sources */,
|
||||
B44033DF2BCC36C300162242 /* LatestTransaction.swift in Sources */,
|
||||
6DD410C0266CB1460087DE03 /* MarketWidget.swift in Sources */,
|
||||
B4AB225E2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */,
|
||||
B44033F62BCC377F00162242 /* WidgetData.swift in Sources */,
|
||||
6DD410BA266CAF5C0087DE03 /* FiatUnit.swift in Sources */,
|
||||
B44033FB2BCC379200162242 /* WidgetDataStore.swift in Sources */,
|
||||
B44033EB2BCC371A00162242 /* MarketData.swift in Sources */,
|
||||
6DD410AF266CAF5C0087DE03 /* WalletInformationAndMarketWidget.swift in Sources */,
|
||||
6DD410BF266CB13D0087DE03 /* Models.swift in Sources */,
|
||||
B44033C62BCC332400162242 /* Balance.swift in Sources */,
|
||||
B44033E62BCC36FF00162242 /* WalletData.swift in Sources */,
|
||||
6DD410BF266CB13D0087DE03 /* Placeholders.swift in Sources */,
|
||||
6DD410B0266CAF5C0087DE03 /* WalletInformationWidget.swift in Sources */,
|
||||
6DD410B1266CAF5C0087DE03 /* WidgetAPI+Electrum.swift in Sources */,
|
||||
6DD410B1266CAF5C0087DE03 /* MarketAPI+Electrum.swift in Sources */,
|
||||
6DD410B9266CAF5C0087DE03 /* UserDefaultsGroup.swift in Sources */,
|
||||
6DD410B8266CAF5C0087DE03 /* UserDefaultsExtension.swift in Sources */,
|
||||
);
|
||||
@ -1465,23 +1573,35 @@
|
||||
32F0A29A2311DBB20095C559 /* ComplicationController.swift in Sources */,
|
||||
B40D4E602258425500428FCC /* SpecifyInterfaceController.swift in Sources */,
|
||||
B43D0379225847C500FBAA95 /* WatchDataSource.swift in Sources */,
|
||||
B44033D42BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */,
|
||||
B44034012BCC37F800162242 /* Bundle+decode.swift in Sources */,
|
||||
849047CA2702A32A008EE567 /* Handoff.swift in Sources */,
|
||||
6D4AF16325D21185009DD853 /* WidgetDataStore.swift in Sources */,
|
||||
B44033EA2BCC371A00162242 /* MarketData.swift in Sources */,
|
||||
B44033CB2BCC350A00162242 /* Currency.swift in Sources */,
|
||||
6DFC807224EA2FA9007B8700 /* ViewQRCodefaceController.swift in Sources */,
|
||||
B40D4E46225841ED00428FCC /* NotificationController.swift in Sources */,
|
||||
B40D4E5D2258425500428FCC /* InterfaceController.swift in Sources */,
|
||||
B44033FA2BCC379200162242 /* WidgetDataStore.swift in Sources */,
|
||||
B44033DE2BCC36C300162242 /* LatestTransaction.swift in Sources */,
|
||||
B43D037B225847C500FBAA95 /* TransactionTableRow.swift in Sources */,
|
||||
B43D037D225847C500FBAA95 /* WalletInformation.swift in Sources */,
|
||||
6D4AF15925D21172009DD853 /* WidgetAPI.swift in Sources */,
|
||||
6D4AF15925D21172009DD853 /* MarketAPI.swift in Sources */,
|
||||
B40D4E642258425500428FCC /* WalletDetailsInterfaceController.swift in Sources */,
|
||||
B40D4E44225841ED00428FCC /* ExtensionDelegate.swift in Sources */,
|
||||
B40D4E682258426B00428FCC /* KeychainSwiftDistrib.swift in Sources */,
|
||||
6D4AF16D25D21192009DD853 /* Models.swift in Sources */,
|
||||
6D4AF16D25D21192009DD853 /* Placeholders.swift in Sources */,
|
||||
B44033DB2BCC369B00162242 /* Colors.swift in Sources */,
|
||||
B40D4E632258425500428FCC /* ReceiveInterfaceController.swift in Sources */,
|
||||
B43D0378225847C500FBAA95 /* WalletGradient.swift in Sources */,
|
||||
B44033C02BCC32F800162242 /* BitcoinUnit.swift in Sources */,
|
||||
B44033E52BCC36FF00162242 /* WalletData.swift in Sources */,
|
||||
B44033EF2BCC374500162242 /* Numeric+abbreviated.swift in Sources */,
|
||||
B44033D02BCC352F00162242 /* UserDefaultsGroup.swift in Sources */,
|
||||
B44033C52BCC332400162242 /* Balance.swift in Sources */,
|
||||
6D4AF18425D215D1009DD853 /* UserDefaultsExtension.swift in Sources */,
|
||||
B4AB225D2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */,
|
||||
B40D4E5E2258425500428FCC /* NumericKeypadInterfaceController.swift in Sources */,
|
||||
B44033F52BCC377F00162242 /* WidgetData.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1498,10 +1618,28 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B44033D72BCC369400162242 /* UserDefaultsExtension.swift in Sources */,
|
||||
B44033F72BCC377F00162242 /* WidgetData.swift in Sources */,
|
||||
B44033E12BCC36CA00162242 /* Placeholders.swift in Sources */,
|
||||
B44033E72BCC36FF00162242 /* WalletData.swift in Sources */,
|
||||
B44033E02BCC36C300162242 /* LatestTransaction.swift in Sources */,
|
||||
B44033D92BCC369900162242 /* Colors.swift in Sources */,
|
||||
B4A29A2C2B55C990002A67DF /* EventEmitter.m in Sources */,
|
||||
B44033D62BCC368800162242 /* UserDefaultsGroupKey.swift in Sources */,
|
||||
B44033FD2BCC37D600162242 /* MarketAPI.swift in Sources */,
|
||||
B4A29A2D2B55C990002A67DF /* main.m in Sources */,
|
||||
B4A29A2E2B55C990002A67DF /* AppDelegate.mm in Sources */,
|
||||
B44033C72BCC332400162242 /* Balance.swift in Sources */,
|
||||
B44033FC2BCC379200162242 /* WidgetDataStore.swift in Sources */,
|
||||
B44033C22BCC32F800162242 /* BitcoinUnit.swift in Sources */,
|
||||
B44033F12BCC374500162242 /* Numeric+abbreviated.swift in Sources */,
|
||||
B44034032BCC37F800162242 /* Bundle+decode.swift in Sources */,
|
||||
B44033CD2BCC350A00162242 /* Currency.swift in Sources */,
|
||||
B44034062BCC389F00162242 /* FiatUnit.swift in Sources */,
|
||||
B44033CF2BCC352C00162242 /* UserDefaultsGroup.swift in Sources */,
|
||||
B4A29A2F2B55C990002A67DF /* Bridge.swift in Sources */,
|
||||
B44034042BCC389100162242 /* XMLParserDelegate.swift in Sources */,
|
||||
B44033EC2BCC371A00162242 /* MarketData.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1544,12 +1682,6 @@
|
||||
target = B4A29A212B55C990002A67DF /* BlueWallet-NoLDK */;
|
||||
targetProxy = B49038D62B8FBA2500A8164A /* PBXContainerItemProxy */;
|
||||
};
|
||||
B4A29A222B55C990002A67DF /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
platformFilter = ios;
|
||||
target = B40D4E2F225841EC00428FCC /* BlueWalletWatch */;
|
||||
targetProxy = B4A29A232B55C990002A67DF /* PBXContainerItemProxy */;
|
||||
};
|
||||
B4A29A242B55C990002A67DF /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
targetProxy = B4A29A252B55C990002A67DF /* PBXContainerItemProxy */;
|
||||
@ -2074,7 +2206,7 @@
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 5.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -2123,7 +2255,7 @@
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 5.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -2170,7 +2302,7 @@
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 5.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -2217,7 +2349,7 @@
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 5.0;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 6.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -102,7 +102,7 @@
|
||||
</EnvironmentVariable>
|
||||
<EnvironmentVariable
|
||||
key = "_XCWidgetFamily"
|
||||
value = "systemMedium"
|
||||
value = "systemSmall"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
|
@ -36,7 +36,7 @@ class ExtensionDelegate: NSObject, WKExtensionDelegate {
|
||||
}
|
||||
|
||||
private func updateMarketData(for fiatUnit: FiatUnit) {
|
||||
WidgetAPI.fetchPrice(currency: fiatUnit.endPointKey) { (data, error) in
|
||||
MarketAPI.fetchPrice(currency: fiatUnit.endPointKey) { (data, error) in
|
||||
guard let data = data, let encodedData = try? PropertyListEncoder().encode(data) else { return }
|
||||
let groupUserDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue)
|
||||
groupUserDefaults?.set(encodedData, forKey: MarketData.string)
|
||||
|
@ -1,6 +1,6 @@
|
||||
PODS:
|
||||
- boost (1.76.0)
|
||||
- BugsnagReactNative (7.22.6):
|
||||
- BugsnagReactNative (7.22.7):
|
||||
- React-Core
|
||||
- BVLinearGradient (2.8.3):
|
||||
- React-Core
|
||||
@ -352,7 +352,7 @@ PODS:
|
||||
- react-native-tcp-socket (6.0.6):
|
||||
- CocoaAsyncSocket
|
||||
- React-Core
|
||||
- react-native-webview (13.8.4):
|
||||
- react-native-webview (13.8.6):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core
|
||||
- react-native-widget-center (0.0.9):
|
||||
@ -469,7 +469,7 @@ PODS:
|
||||
- React-perflogger (= 0.72.12)
|
||||
- ReactNativeCameraKit (13.0.0):
|
||||
- React-Core
|
||||
- RealmJS (12.6.2):
|
||||
- RealmJS (12.7.0):
|
||||
- React
|
||||
- rn-ldk (0.8.4):
|
||||
- React-Core
|
||||
@ -782,7 +782,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
boost: 7dcd2de282d72e344012f7d6564d024930a6a440
|
||||
BugsnagReactNative: 366a7e11c0bcf34842e54f40b15dd937cb267aa7
|
||||
BugsnagReactNative: 7cc5c927f6a0b00a8e3cc7157dab4cc94a4bc575
|
||||
BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||
@ -822,7 +822,7 @@ SPEC CHECKSUMS:
|
||||
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b
|
||||
react-native-secure-key-store: 910e6df6bc33cb790aba6ee24bc7818df1fe5898
|
||||
react-native-tcp-socket: e724380c910c2e704816ec817ed28f1342246ff7
|
||||
react-native-webview: 007d5c5a74de7243be6331221727639ed01ef760
|
||||
react-native-webview: 2ce07db2190ee7b3af77e8fac75ff47abe47089f
|
||||
react-native-widget-center: 12dfba20a4fa995850b52cf0afecf734397f4b9c
|
||||
React-NativeModulesApple: 694679e4193a49c09f0a76ee27ec09b2c466d59c
|
||||
React-perflogger: 63606aeab27683112e1bd4ef25bd099ec1cb03f8
|
||||
@ -842,7 +842,7 @@ SPEC CHECKSUMS:
|
||||
React-utils: 9a24cb88f950d1020ee55bddacbc8c16a611e2dc
|
||||
ReactCommon: 76843a9bb140596351ac2786257ac9fe60cafabb
|
||||
ReactNativeCameraKit: 9d46a5d7dd544ca64aa9c03c150d2348faf437eb
|
||||
RealmJS: 385df5ee940d96f1de26b1dab153e325633d3052
|
||||
RealmJS: 55c8cbedc3ef719a942e370f8c94e04cb7e6781c
|
||||
rn-ldk: 0d8749d98cc5ce67302a32831818c116b67f7643
|
||||
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
|
||||
RNCClipboard: 090462274cc05b02628bd158baf6d73c3abe8441
|
||||
|
35
ios/Shared/Balance.swift
Normal file
35
ios/Shared/Balance.swift
Normal file
@ -0,0 +1,35 @@
|
||||
import Foundation
|
||||
|
||||
class Balance {
|
||||
static func formatBalance(_ balance: Decimal, toUnit: BitcoinUnit, withFormatting: Bool = false, completion: @escaping (String) -> Void) {
|
||||
switch toUnit {
|
||||
case .BTC:
|
||||
let value = balance / Decimal(100_000_000)
|
||||
completion("\(value) BTC") // Localize unit names as needed.
|
||||
case .SATS:
|
||||
if withFormatting {
|
||||
completion(NumberFormatter.localizedString(from: balance as NSNumber, number: .decimal) + " SATS")
|
||||
} else {
|
||||
completion("\(balance) SATS")
|
||||
}
|
||||
case .LOCAL_CURRENCY:
|
||||
fetchLocalCurrencyEquivalent(satoshi: balance, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
private static func fetchLocalCurrencyEquivalent(satoshi: Decimal, completion: @escaping (String) -> Void) {
|
||||
|
||||
let currency = Currency.getUserPreferredCurrency() // Ensure this method retrieves the correct currency code.
|
||||
MarketAPI.fetchPrice(currency: currency) { dataStore, error in
|
||||
DispatchQueue.main.async {
|
||||
guard let dataStore = dataStore, error == nil else {
|
||||
completion("Error: \(error?.localizedDescription ?? "Unknown error")")
|
||||
return
|
||||
}
|
||||
let rate = Decimal(string: dataStore.rate) ?? Decimal(0)
|
||||
let convertedAmount = (satoshi / Decimal(100_000_000)) * rate
|
||||
completion("\(convertedAmount) \(currency)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
ios/Shared/BitcoinUnit.swift
Normal file
15
ios/Shared/BitcoinUnit.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// BitcoinUnit.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum BitcoinUnit: String {
|
||||
case BTC = "BTC"
|
||||
case SATS = "SATS"
|
||||
case LOCAL_CURRENCY = "LOCAL_CURRENCY"
|
||||
}
|
@ -1,24 +1,13 @@
|
||||
//
|
||||
// FiatUnit.swift
|
||||
// Bundle+decode.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/20/20.
|
||||
// Copyright © 2020 BlueWallet. All rights reserved.
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct FiatUnit: Codable {
|
||||
let endPointKey: String
|
||||
let symbol: String
|
||||
let locale: String
|
||||
let source: String
|
||||
|
||||
}
|
||||
|
||||
func fiatUnit(currency: String) -> FiatUnit? {
|
||||
return Bundle.main.decode([String: FiatUnit].self, from: "fiatUnits.json").first(where: {$1.endPointKey == currency})?.value
|
||||
}
|
||||
|
||||
extension Bundle {
|
||||
func decode<T: Decodable>(_ type: T.Type, from file: String, dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate, keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys) -> T {
|
||||
guard let url = self.url(forResource: file, withExtension: nil) else {
|
57
ios/Shared/Currency.swift
Normal file
57
ios/Shared/Currency.swift
Normal file
@ -0,0 +1,57 @@
|
||||
//
|
||||
// Currency.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CurrencyError: LocalizedError {
|
||||
var errorDescription: String = "Failed to parse response"
|
||||
}
|
||||
|
||||
class Currency {
|
||||
|
||||
static func getUserPreferredCurrency() -> String {
|
||||
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue),
|
||||
let preferredCurrency = userDefaults.string(forKey: "preferredCurrency")
|
||||
else {
|
||||
return "USD"
|
||||
}
|
||||
|
||||
if preferredCurrency != Currency.getLastSelectedCurrency() {
|
||||
UserDefaults.standard.removeObject(forKey: WidgetData.WidgetCachedDataStoreKey)
|
||||
UserDefaults.standard.removeObject(forKey: WidgetData.WidgetDataStoreKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
||||
return preferredCurrency
|
||||
}
|
||||
|
||||
static func getUserPreferredCurrencyLocale() -> String {
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue),
|
||||
let preferredCurrency = userDefaults.string(forKey: "preferredCurrencyLocale")
|
||||
else {
|
||||
return "en_US"
|
||||
}
|
||||
return preferredCurrency
|
||||
}
|
||||
|
||||
static func getLastSelectedCurrency() -> String {
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), let dataStore = userDefaults.string(forKey: "currency") else {
|
||||
return "USD"
|
||||
}
|
||||
|
||||
return dataStore
|
||||
}
|
||||
|
||||
static func saveNewSelectedCurrency() {
|
||||
UserDefaults.standard.setValue(Currency.getUserPreferredCurrency(), forKey: "currency")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
20
ios/Shared/Fiat/FiatUnit.swift
Normal file
20
ios/Shared/Fiat/FiatUnit.swift
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// FiatUnit.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/20/20.
|
||||
// Copyright © 2020 BlueWallet. All rights reserved.
|
||||
//
|
||||
import Foundation
|
||||
|
||||
struct FiatUnit: Codable {
|
||||
let endPointKey: String
|
||||
let symbol: String
|
||||
let locale: String
|
||||
let source: String
|
||||
|
||||
}
|
||||
|
||||
func fiatUnit(currency: String) -> FiatUnit? {
|
||||
return Bundle.main.decode([String: FiatUnit].self, from: "fiatUnits.json").first(where: {$1.endPointKey == currency})?.value
|
||||
}
|
14
ios/Shared/LatestTransaction.swift
Normal file
14
ios/Shared/LatestTransaction.swift
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// LatestTransaction.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct LatestTransaction {
|
||||
let isUnconfirmed: Bool?
|
||||
let epochValue: Int?
|
||||
}
|
@ -12,7 +12,7 @@ struct APIError: LocalizedError {
|
||||
var errorDescription: String = "Failed to fetch Electrum data..."
|
||||
}
|
||||
|
||||
extension WidgetAPI {
|
||||
extension MarketAPI {
|
||||
|
||||
static func fetchNextBlockFee(completion: @escaping ((MarketData?, Error?) -> Void), userElectrumSettings: UserDefaultsElectrumSettings = UserDefaultsGroup.getElectrumSettings()) {
|
||||
let settings = userElectrumSettings
|
||||
@ -73,12 +73,12 @@ extension WidgetAPI {
|
||||
|
||||
static func fetchMarketData(currency: String, completion: @escaping ((MarketData?, Error?) -> Void)) {
|
||||
var marketDataEntry = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
|
||||
WidgetAPI.fetchPrice(currency: currency, completion: { (result, error) in
|
||||
MarketAPI.fetchPrice(currency: currency, completion: { (result, error) in
|
||||
if let result = result {
|
||||
marketDataEntry.rate = result.rateDouble
|
||||
marketDataEntry.price = result.formattedRate ?? "!"
|
||||
}
|
||||
WidgetAPI.fetchNextBlockFee { (marketData, error) in
|
||||
MarketAPI.fetchNextBlockFee { (marketData, error) in
|
||||
if let nextBlock = marketData?.nextBlock {
|
||||
marketDataEntry.nextBlock = nextBlock
|
||||
} else {
|
199
ios/Shared/MarketAPI.swift
Normal file
199
ios/Shared/MarketAPI.swift
Normal file
@ -0,0 +1,199 @@
|
||||
//
|
||||
// WidgetAPI.swift
|
||||
// TodayExtension
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/2/19.
|
||||
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
var numberFormatter: NumberFormatter {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .decimal
|
||||
formatter.maximumFractionDigits = 0
|
||||
formatter.locale = Locale.current
|
||||
return formatter
|
||||
}
|
||||
|
||||
class MarketAPI {
|
||||
|
||||
private static func buildURLString(source: String, endPointKey: String) -> String {
|
||||
switch source {
|
||||
case "Yadio":
|
||||
return "https://api.yadio.io/json/\(endPointKey)"
|
||||
case "YadioConvert":
|
||||
return "https://api.yadio.io/convert/1/BTC/\(endPointKey)"
|
||||
case "Exir":
|
||||
return "https://api.exir.io/v1/ticker?symbol=btc-irt"
|
||||
case "wazirx":
|
||||
return "https://api.wazirx.com/api/v2/tickers/btcinr"
|
||||
case "Bitstamp":
|
||||
return "https://www.bitstamp.net/api/v2/ticker/btc\(endPointKey.lowercased())"
|
||||
case "Coinbase":
|
||||
return "https://api.coinbase.com/v2/prices/BTC-\(endPointKey.uppercased())/buy"
|
||||
case "CoinGecko":
|
||||
return "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=\(endPointKey.lowercased())"
|
||||
case "BNR":
|
||||
return "https://www.bnr.ro/nbrfxrates.xml"
|
||||
default:
|
||||
return "https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json"
|
||||
}
|
||||
}
|
||||
|
||||
private static func handleDefaultData(data: Data, source: String, endPointKey: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) {
|
||||
guard let json = (try? JSONSerialization.jsonObject(with: data, options: [])) as? Dictionary<String, Any> else {
|
||||
completion(nil, CurrencyError(errorDescription: "JSON parsing error."))
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the JSON based on the source and format the response
|
||||
parseJSONBasedOnSource(json: json, source: source, endPointKey: endPointKey, completion: completion)
|
||||
}
|
||||
|
||||
private static func parseJSONBasedOnSource(json: Dictionary<String, Any>, source: String, endPointKey: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) {
|
||||
var latestRateDataStore: WidgetDataStore?
|
||||
|
||||
switch source {
|
||||
case "Yadio":
|
||||
if let rateDict = json[endPointKey] as? [String: Any],
|
||||
let rateDouble = rateDict["price"] as? Double,
|
||||
let lastUpdated = rateDict["timestamp"] as? Int {
|
||||
let unix = Double(lastUpdated / 1_000)
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix))
|
||||
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)"))
|
||||
}
|
||||
case "YadioConvert":
|
||||
guard let rateDouble = json["rate"] as? Double,
|
||||
let lastUpdated = json["timestamp"] as? Int
|
||||
else { break }
|
||||
let unix = Double(lastUpdated / 1_000)
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix))
|
||||
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
case "CoinGecko":
|
||||
if let bitcoinDict = json["bitcoin"] as? [String: Any],
|
||||
let rateDouble = bitcoinDict[endPointKey.lowercased()] as? Double {
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)"))
|
||||
}
|
||||
|
||||
case "Exir":
|
||||
if let rateDouble = json["last"] as? Double {
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)"))
|
||||
}
|
||||
|
||||
case "Bitstamp":
|
||||
if let rateString = json["last"] as? String, let rateDouble = Double(rateString) {
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)"))
|
||||
}
|
||||
|
||||
case "wazirx":
|
||||
if let tickerDict = json["ticker"] as? [String: Any],
|
||||
let rateString = tickerDict["buy"] as? String,
|
||||
let rateDouble = Double(rateString) {
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)"))
|
||||
}
|
||||
|
||||
case "Coinbase":
|
||||
if let data = json["data"] as? [String: Any],
|
||||
let rateString = data["amount"] as? String,
|
||||
let rateDouble = Double(rateString) {
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "Data formatting error for source: \(source)"))
|
||||
}
|
||||
|
||||
case "BNR":
|
||||
// Handle BNR source differently if needed, perhaps requiring XML parsing
|
||||
// Placeholder for potential XML parsing logic or alternative JSON structure
|
||||
completion(nil, CurrencyError(errorDescription: "BNR data source is not yet implemented"))
|
||||
|
||||
default:
|
||||
completion(nil, CurrencyError(errorDescription: "Unsupported data source \(source)"))
|
||||
}
|
||||
}
|
||||
|
||||
// Handles XML data for BNR source
|
||||
private static func handleBNRData(data: Data, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) {
|
||||
let parser = XMLParser(data: data)
|
||||
let delegate = BNRXMLParserDelegate()
|
||||
parser.delegate = delegate
|
||||
if parser.parse(), let usdToRonRate = delegate.usdRate {
|
||||
let coinGeckoUrl = URL(string: "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")!
|
||||
URLSession.shared.dataTask(with: coinGeckoUrl) { data, _, error in
|
||||
guard let data = data, error == nil else {
|
||||
completion(nil, error ?? CurrencyError())
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
||||
let bitcoinDict = json["bitcoin"] as? [String: Double],
|
||||
let btcToUsdRate = bitcoinDict["usd"] {
|
||||
let btcToRonRate = btcToUsdRate * usdToRonRate
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
let latestRateDataStore = WidgetDataStore(rate: String(btcToRonRate), lastUpdate: lastUpdatedString, rateDouble: btcToRonRate)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError())
|
||||
}
|
||||
} catch {
|
||||
completion(nil, error)
|
||||
}
|
||||
}.resume()
|
||||
} else {
|
||||
completion(nil, CurrencyError(errorDescription: "XML parsing error."))
|
||||
}
|
||||
}
|
||||
|
||||
static func fetchPrice(currency: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) {
|
||||
let currencyToFiatUnit = fiatUnit(currency: currency)
|
||||
guard let source = currencyToFiatUnit?.source, let endPointKey = currencyToFiatUnit?.endPointKey else {
|
||||
completion(nil, CurrencyError(errorDescription: "Invalid currency unit or endpoint."))
|
||||
return
|
||||
}
|
||||
|
||||
let urlString = buildURLString(source: source, endPointKey: endPointKey)
|
||||
guard let url = URL(string: urlString) else {
|
||||
completion(nil, CurrencyError(errorDescription: "Invalid URL."))
|
||||
return
|
||||
}
|
||||
|
||||
URLSession.shared.dataTask(with: url) { data, response, error in
|
||||
guard let data = data, error == nil else {
|
||||
completion(nil, error ?? CurrencyError(errorDescription: "Network error or data not found."))
|
||||
return
|
||||
}
|
||||
|
||||
if source == "BNR" {
|
||||
handleBNRData(data: data, completion: completion)
|
||||
} else {
|
||||
handleDefaultData(data: data, source: source, endPointKey: endPointKey, completion: completion)
|
||||
}
|
||||
}.resume()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
37
ios/Shared/MarketData.swift
Normal file
37
ios/Shared/MarketData.swift
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// MarketData.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct MarketData:Codable {
|
||||
var nextBlock: String
|
||||
var sats: String
|
||||
var price: String
|
||||
var rate: Double
|
||||
var formattedNextBlock: String {
|
||||
return nextBlock == "..." ? "..." : #"\#(nextBlock) sat/b"#
|
||||
}
|
||||
var dateString: String = ""
|
||||
var formattedDate: String? {
|
||||
let isoDateFormatter = ISO8601DateFormatter()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
if let date = isoDateFormatter.date(from: dateString) {
|
||||
return dateFormatter.string(from: date)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
static let string = "MarketData"
|
||||
}
|
||||
|
||||
enum MarketDataTimeline: String {
|
||||
case Previous = "previous"
|
||||
case Current = "current"
|
||||
}
|
27
ios/Shared/Numeric+abbreviated.swift
Normal file
27
ios/Shared/Numeric+abbreviated.swift
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// Numeric+abbreviated.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Numeric {
|
||||
|
||||
var abbreviated: String {
|
||||
let bytecountFormatter = ByteCountFormatter()
|
||||
bytecountFormatter.zeroPadsFractionDigits = true
|
||||
bytecountFormatter.countStyle = .decimal
|
||||
bytecountFormatter.isAdaptive = false
|
||||
let bytesString = bytecountFormatter.string(fromByteCount: (self as! NSNumber).int64Value)
|
||||
|
||||
let numericString = bytesString
|
||||
.replacingOccurrences(of: "bytes", with: "")
|
||||
.replacingOccurrences(of: "B", with: "") // removes B (bytes) in 'KB'/'MB'/'GB'
|
||||
.replacingOccurrences(of: "G", with: "B") // replace G (Giga) to just B (billions)
|
||||
return numericString.replacingOccurrences(of: " ", with: "")
|
||||
}
|
||||
|
||||
}
|
16
ios/Shared/Placeholders.swift
Normal file
16
ios/Shared/Placeholders.swift
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Models.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/1/20.
|
||||
// Copyright © 2020 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
|
||||
let emptyMarketData = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
|
||||
let emptyWalletData = WalletData(balance: 0, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: Int(Date().timeIntervalSince1970)))
|
||||
|
||||
|
20
ios/Shared/UserDefaultsGroupKey.swift
Normal file
20
ios/Shared/UserDefaultsGroupKey.swift
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// UserDefaultsGroupKeys.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum UserDefaultsGroupKey: String {
|
||||
case GroupName = "group.io.bluewallet.bluewallet"
|
||||
case PreferredCurrency = "preferredCurrency"
|
||||
case ElectrumSettingsHost = "electrum_host"
|
||||
case ElectrumSettingsTCPPort = "electrum_tcp_port"
|
||||
case ElectrumSettingsSSLPort = "electrum_ssl_port"
|
||||
case AllWalletsBalance = "WidgetCommunicationAllWalletsSatoshiBalance"
|
||||
case AllWalletsLatestTransactionTime = "WidgetCommunicationAllWalletsLatestTransactionTime"
|
||||
case LatestTransactionIsUnconfirmed = "\"WidgetCommunicationLatestTransactionIsUnconfirmed\""
|
||||
}
|
27
ios/Shared/WalletData.swift
Normal file
27
ios/Shared/WalletData.swift
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// WalletData.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct WalletData {
|
||||
var balance: Double
|
||||
var latestTransactionTime: LatestTransaction = LatestTransaction(isUnconfirmed: false, epochValue: 0)
|
||||
var formattedBalanceBTC: String {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .none
|
||||
formatter.usesSignificantDigits = true
|
||||
formatter.maximumSignificantDigits = 9
|
||||
formatter.roundingMode = .up
|
||||
let value = NSNumber(value: balance / 100000000);
|
||||
if let valueString = formatter.string(from: value) {
|
||||
return "\(String(describing: valueString)) \(BitcoinUnit.BTC.rawValue)"
|
||||
} else {
|
||||
return "0 \(BitcoinUnit.BTC.rawValue)"
|
||||
}
|
||||
}
|
||||
}
|
22
ios/Shared/WidgetData.swift
Normal file
22
ios/Shared/WidgetData.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// WidgetData.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class WidgetData {
|
||||
|
||||
static let WidgetDataStoreKey = "WidgetDataStoreKey"
|
||||
static let WidgetCachedDataStoreKey = "WidgetCachedDataStoreKey"
|
||||
|
||||
static func savePriceRateAndLastUpdate(rate: String, lastUpdate: String) {
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue) else { return }
|
||||
userDefaults.setValue(["rate": rate, "lastUpdate": lastUpdate], forKey: WidgetDataStoreKey)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
}
|
62
ios/Shared/WidgetDataStore.swift
Normal file
62
ios/Shared/WidgetDataStore.swift
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// WidgetDataStore.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 4/14/24.
|
||||
// Copyright © 2024 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
struct WidgetDataStore: Codable {
|
||||
let rate: String
|
||||
let lastUpdate: String
|
||||
let rateDouble: Double
|
||||
var formattedRate: String? {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.locale = Locale(identifier: Currency.getUserPreferredCurrencyLocale())
|
||||
numberFormatter.numberStyle = .currency
|
||||
numberFormatter.maximumFractionDigits = 0
|
||||
numberFormatter.minimumFractionDigits = 0
|
||||
if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) {
|
||||
return rateString
|
||||
}
|
||||
return rate
|
||||
}
|
||||
var formattedRateForSmallComplication: String? {
|
||||
return rateDouble.abbreviated
|
||||
}
|
||||
|
||||
var formattedRateForComplication: String? {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.locale = Locale(identifier: Currency.getUserPreferredCurrencyLocale())
|
||||
numberFormatter.numberStyle = .currency
|
||||
numberFormatter.currencySymbol = ""
|
||||
if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) {
|
||||
return rateString
|
||||
}
|
||||
return rate
|
||||
}
|
||||
|
||||
var date: Date? {
|
||||
let isoDateFormatter = ISO8601DateFormatter()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
return isoDateFormatter.date(from: lastUpdate)
|
||||
}
|
||||
var formattedDate: String? {
|
||||
let isoDateFormatter = ISO8601DateFormatter()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
if let date = isoDateFormatter.date(from: lastUpdate) {
|
||||
return dateFormatter.string(from: date)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -29,10 +29,10 @@ struct WalletInformationWidgetProvider: TimelineProvider {
|
||||
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||
var entries: [WalletInformationWidgetEntry] = []
|
||||
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
|
||||
let userPreferredCurrency = Currency.getUserPreferredCurrency()
|
||||
let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime())
|
||||
|
||||
WidgetAPI.fetchPrice(currency: userPreferredCurrency) { (result, error) in
|
||||
MarketAPI.fetchPrice(currency: userPreferredCurrency) { (result, error) in
|
||||
let entry: WalletInformationWidgetEntry
|
||||
|
||||
if let result = result {
|
||||
|
@ -34,8 +34,8 @@ struct MarketWidgetProvider: TimelineProvider {
|
||||
let timeline = Timeline(entries: entries, policy: .atEnd)
|
||||
completion(timeline)
|
||||
} else {
|
||||
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
|
||||
WidgetAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in
|
||||
let userPreferredCurrency = Currency.getUserPreferredCurrency()
|
||||
MarketAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in
|
||||
let entry: MarketWidgetEntry
|
||||
|
||||
if let result = result {
|
||||
|
@ -36,14 +36,14 @@ struct PriceWidgetProvider: TimelineProvider {
|
||||
let timeline = Timeline(entries: entries, policy: .atEnd)
|
||||
completion(timeline)
|
||||
} else {
|
||||
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
|
||||
if userPreferredCurrency != WidgetAPI.getLastSelectedCurrency() {
|
||||
let userPreferredCurrency = Currency.getUserPreferredCurrency()
|
||||
if userPreferredCurrency != Currency.getLastSelectedCurrency() {
|
||||
marketData[.Current] = nil
|
||||
marketData[.Previous] = nil
|
||||
WidgetAPI.saveNewSelectedCurrency()
|
||||
Currency.saveNewSelectedCurrency()
|
||||
}
|
||||
|
||||
WidgetAPI.fetchPrice(currency: userPreferredCurrency) { (data, error) in
|
||||
MarketAPI.fetchPrice(currency: userPreferredCurrency) { (data, error) in
|
||||
let entry: PriceWidgetEntry
|
||||
|
||||
if let data = data, let formattedRate = data.formattedRate {
|
||||
|
@ -1,74 +0,0 @@
|
||||
//
|
||||
// Models.swift
|
||||
// BlueWallet
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/1/20.
|
||||
// Copyright © 2020 BlueWallet. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct MarketData:Codable {
|
||||
var nextBlock: String
|
||||
var sats: String
|
||||
var price: String
|
||||
var rate: Double
|
||||
var formattedNextBlock: String {
|
||||
return nextBlock == "..." ? "..." : #"\#(nextBlock) sat/b"#
|
||||
}
|
||||
var dateString: String = ""
|
||||
var formattedDate: String? {
|
||||
let isoDateFormatter = ISO8601DateFormatter()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
if let date = isoDateFormatter.date(from: dateString) {
|
||||
return dateFormatter.string(from: date)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
static let string = "MarketData"
|
||||
}
|
||||
|
||||
struct WalletData {
|
||||
var balance: Double
|
||||
var latestTransactionTime: LatestTransaction = LatestTransaction(isUnconfirmed: false, epochValue: 0)
|
||||
var formattedBalanceBTC: String {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .none
|
||||
formatter.usesSignificantDigits = true
|
||||
formatter.maximumSignificantDigits = 9
|
||||
formatter.roundingMode = .up
|
||||
let value = NSNumber(value: balance / 100000000);
|
||||
if let valueString = formatter.string(from: value) {
|
||||
return "\(String(describing: valueString)) BTC"
|
||||
} else {
|
||||
return "0 BTC"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct LatestTransaction {
|
||||
let isUnconfirmed: Bool?
|
||||
let epochValue: Int?
|
||||
}
|
||||
let emptyMarketData = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
|
||||
let emptyWalletData = WalletData(balance: 0, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: Int(Date().timeIntervalSince1970)))
|
||||
|
||||
enum MarketDataTimeline: String {
|
||||
case Previous = "previous"
|
||||
case Current = "current"
|
||||
}
|
||||
|
||||
enum UserDefaultsGroupKey: String {
|
||||
case GroupName = "group.io.bluewallet.bluewallet"
|
||||
case PreferredCurrency = "preferredCurrency"
|
||||
case ElectrumSettingsHost = "electrum_host"
|
||||
case ElectrumSettingsTCPPort = "electrum_tcp_port"
|
||||
case ElectrumSettingsSSLPort = "electrum_ssl_port"
|
||||
case AllWalletsBalance = "WidgetCommunicationAllWalletsSatoshiBalance"
|
||||
case AllWalletsLatestTransactionTime = "WidgetCommunicationAllWalletsLatestTransactionTime"
|
||||
case LatestTransactionIsUnconfirmed = "\"WidgetCommunicationLatestTransactionIsUnconfirmed\""
|
||||
}
|
@ -28,7 +28,7 @@ struct MarketView: View {
|
||||
|
||||
Spacer()
|
||||
HStack(alignment: .center, spacing: 0, content: {
|
||||
Text("Sats/\(WidgetAPI.getUserPreferredCurrency())").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor)
|
||||
Text("Sats/\(Currency.getUserPreferredCurrency())").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor)
|
||||
Spacer()
|
||||
Text(marketData.sats == "..." ? "..." : marketData.sats).padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)).lineLimit(1).minimumScaleFactor(0.1).foregroundColor(.widgetBackground).font(Font.system(size:11, weight: .semibold, design: .default)).background(Color(red: 0.97, green: 0.21, blue: 0.38)).overlay(
|
||||
RoundedRectangle(cornerRadius: 4.0)
|
||||
|
@ -16,7 +16,7 @@ struct WalletInformationView: View {
|
||||
|
||||
var formattedBalance: String {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale())
|
||||
numberFormatter.locale = Locale(identifier: Currency.getUserPreferredCurrencyLocale())
|
||||
numberFormatter.numberStyle = .currency
|
||||
let amount = numberFormatter.string(from: NSNumber(value: ((allWalletsBalance.balance / 100000000) * marketData.rate))) ?? ""
|
||||
return amount
|
||||
|
@ -1,218 +0,0 @@
|
||||
//
|
||||
// WidgetAPI.swift
|
||||
// TodayExtension
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/2/19.
|
||||
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CurrencyError: LocalizedError {
|
||||
var errorDescription: String = "Failed to parse response"
|
||||
}
|
||||
|
||||
var numberFormatter: NumberFormatter {
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .decimal
|
||||
formatter.maximumFractionDigits = 0
|
||||
formatter.locale = Locale.current
|
||||
return formatter
|
||||
}
|
||||
|
||||
class WidgetAPI {
|
||||
static func fetchPrice(currency: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) {
|
||||
let currencyToFiatUnit = fiatUnit(currency: currency)
|
||||
guard let source = currencyToFiatUnit?.source, let endPointKey = currencyToFiatUnit?.endPointKey else { return }
|
||||
|
||||
var urlString: String
|
||||
switch source {
|
||||
case "Yadio":
|
||||
urlString = "https://api.yadio.io/json/\(endPointKey)"
|
||||
case "YadioConvert":
|
||||
urlString = "https://api.yadio.io/convert/1/BTC/\(endPointKey)"
|
||||
case "Exir":
|
||||
urlString = "https://api.exir.io/v1/ticker?symbol=btc-irt"
|
||||
case "wazirx":
|
||||
urlString = "https://api.wazirx.com/api/v2/tickers/btcinr"
|
||||
case "Bitstamp":
|
||||
urlString = "https://www.bitstamp.net/api/v2/ticker/btc\(endPointKey.lowercased())"
|
||||
case "Coinbase":
|
||||
urlString = "https://api.coinbase.com/v2/prices/BTC-\(endPointKey.uppercased())/buy"
|
||||
case "CoinGecko":
|
||||
urlString = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=\(endPointKey.lowercased())"
|
||||
case "BNR":
|
||||
urlString = "https://www.bnr.ro/nbrfxrates.xml"
|
||||
default:
|
||||
urlString = "https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json"
|
||||
}
|
||||
|
||||
guard let url = URL(string:urlString) else { return }
|
||||
|
||||
if source == "BNR" {
|
||||
URLSession.shared.dataTask(with: url) { (data, response, error) in
|
||||
if let error = error {
|
||||
print("Error fetching data: \(error.localizedDescription)")
|
||||
completion(nil, error)
|
||||
return
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
print("No data received")
|
||||
completion(nil, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse XML data for USD to RON rate
|
||||
let parser = XMLParser(data: data)
|
||||
let delegate = BNRXMLParserDelegate()
|
||||
parser.delegate = delegate
|
||||
if parser.parse(), let usdToRonRate = delegate.usdRate {
|
||||
// Fetch BTC to USD rate using CoinGecko
|
||||
let coinGeckoUrl = URL(string: "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")!
|
||||
URLSession.shared.dataTask(with: coinGeckoUrl) { (data, _, error) in
|
||||
guard let data = data, error == nil else {
|
||||
completion(nil, error ?? CurrencyError())
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
||||
let bitcoinDict = json["bitcoin"] as? [String: Double],
|
||||
let btcToUsdRate = bitcoinDict["usd"] {
|
||||
let btcToRonRate = btcToUsdRate * usdToRonRate
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
let latestRateDataStore = WidgetDataStore(rate: String(btcToRonRate), lastUpdate: lastUpdatedString, rateDouble: btcToRonRate)
|
||||
completion(latestRateDataStore, nil)
|
||||
} else {
|
||||
completion(nil, CurrencyError())
|
||||
}
|
||||
} catch {
|
||||
completion(nil, error)
|
||||
}
|
||||
}.resume()
|
||||
} else {
|
||||
print("Error parsing XML")
|
||||
completion(nil, CurrencyError())
|
||||
}
|
||||
}.resume()
|
||||
} else {
|
||||
URLSession.shared.dataTask(with: url) { (data, response, error) in
|
||||
guard let dataResponse = data,
|
||||
let json = (try? JSONSerialization.jsonObject(with: dataResponse, options: .mutableContainers) as? Dictionary<String, Any>),
|
||||
error == nil
|
||||
else {
|
||||
print(error?.localizedDescription ?? "Response Error")
|
||||
completion(nil, error)
|
||||
return
|
||||
}
|
||||
|
||||
var latestRateDataStore: WidgetDataStore?
|
||||
switch source {
|
||||
case "Yadio":
|
||||
guard let rateDict = json[endPointKey] as? [String: Any],
|
||||
let rateDouble = rateDict["price"] as? Double,
|
||||
let lastUpdated = json["timestamp"] as? Int
|
||||
else { break }
|
||||
let unix = Double(lastUpdated / 1_000)
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix))
|
||||
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":
|
||||
guard let rateDict = json as? [String: Any],
|
||||
let rateDouble = rateDict["rate"] as? Double,
|
||||
let lastUpdated = json["timestamp"] as? Int
|
||||
else { break }
|
||||
let unix = Double(lastUpdated / 1_000)
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date(timeIntervalSince1970: unix))
|
||||
latestRateDataStore = WidgetDataStore(rate: String(rateDouble), lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
case "Exir":
|
||||
guard let rateDouble = json["last"] as? Double else { break }
|
||||
let rateString = String(rateDouble)
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
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":
|
||||
guard let tickerDict = json["ticker"] as? [String: Any],
|
||||
let rateString = tickerDict["buy"] as? String,
|
||||
let rateDouble = Double(rateString)
|
||||
else { break }
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
case "Coinbase":
|
||||
guard let data = json["data"] as? Dictionary<String, Any>,
|
||||
let rateString = data["amount"] as? String,
|
||||
let rateDouble = Double(rateString)
|
||||
else { break }
|
||||
let lastUpdatedString = ISO8601DateFormatter().string(from: Date())
|
||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
default:
|
||||
guard let bpi = json["bpi"] as? Dictionary<String, Any>,
|
||||
let preferredCurrency = bpi[endPointKey] as? Dictionary<String, Any>,
|
||||
let rateString = preferredCurrency["rate"] as? String,
|
||||
let rateDouble = preferredCurrency["rate_float"] as? Double,
|
||||
let time = json["time"] as? Dictionary<String, Any>,
|
||||
let lastUpdatedString = time["updatedISO"] as? String
|
||||
else { break }
|
||||
latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
|
||||
}
|
||||
|
||||
if (latestRateDataStore == nil) {
|
||||
completion(nil, CurrencyError())
|
||||
return
|
||||
}
|
||||
|
||||
completion(latestRateDataStore, nil)
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
|
||||
static func getUserPreferredCurrency() -> String {
|
||||
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue),
|
||||
let preferredCurrency = userDefaults.string(forKey: "preferredCurrency")
|
||||
else {
|
||||
return "USD"
|
||||
}
|
||||
|
||||
if preferredCurrency != WidgetAPI.getLastSelectedCurrency() {
|
||||
UserDefaults.standard.removeObject(forKey: WidgetData.WidgetCachedDataStoreKey)
|
||||
UserDefaults.standard.removeObject(forKey: WidgetData.WidgetDataStoreKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
||||
return preferredCurrency
|
||||
}
|
||||
|
||||
static func getUserPreferredCurrencyLocale() -> String {
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue),
|
||||
let preferredCurrency = userDefaults.string(forKey: "preferredCurrencyLocale")
|
||||
else {
|
||||
return "en_US"
|
||||
}
|
||||
return preferredCurrency
|
||||
}
|
||||
|
||||
static func getLastSelectedCurrency() -> String {
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue), let dataStore = userDefaults.string(forKey: "currency") else {
|
||||
return "USD"
|
||||
}
|
||||
|
||||
return dataStore
|
||||
}
|
||||
|
||||
static func saveNewSelectedCurrency() {
|
||||
UserDefaults.standard.setValue(WidgetAPI.getUserPreferredCurrency(), forKey: "currency")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,86 +0,0 @@
|
||||
//
|
||||
// Created by Marcos Rodriguez on 11/3/19.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Numeric {
|
||||
|
||||
var abbreviated: String {
|
||||
let bytecountFormatter = ByteCountFormatter()
|
||||
bytecountFormatter.zeroPadsFractionDigits = true
|
||||
bytecountFormatter.countStyle = .decimal
|
||||
bytecountFormatter.isAdaptive = false
|
||||
let bytesString = bytecountFormatter.string(fromByteCount: (self as! NSNumber).int64Value)
|
||||
|
||||
let numericString = bytesString
|
||||
.replacingOccurrences(of: "bytes", with: "")
|
||||
.replacingOccurrences(of: "B", with: "") // removes B (bytes) in 'KB'/'MB'/'GB'
|
||||
.replacingOccurrences(of: "G", with: "B") // replace G (Giga) to just B (billions)
|
||||
return numericString.replacingOccurrences(of: " ", with: "")
|
||||
}
|
||||
}
|
||||
|
||||
struct WidgetDataStore: Codable {
|
||||
let rate: String
|
||||
let lastUpdate: String
|
||||
let rateDouble: Double
|
||||
var formattedRate: String? {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale())
|
||||
numberFormatter.numberStyle = .currency
|
||||
numberFormatter.maximumFractionDigits = 0
|
||||
numberFormatter.minimumFractionDigits = 0
|
||||
if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) {
|
||||
return rateString
|
||||
}
|
||||
return rate
|
||||
}
|
||||
var formattedRateForSmallComplication: String? {
|
||||
return rateDouble.abbreviated
|
||||
}
|
||||
|
||||
var formattedRateForComplication: String? {
|
||||
let numberFormatter = NumberFormatter()
|
||||
numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale())
|
||||
numberFormatter.numberStyle = .currency
|
||||
numberFormatter.currencySymbol = ""
|
||||
if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) {
|
||||
return rateString
|
||||
}
|
||||
return rate
|
||||
}
|
||||
|
||||
var date: Date? {
|
||||
let isoDateFormatter = ISO8601DateFormatter()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
return isoDateFormatter.date(from: lastUpdate)
|
||||
}
|
||||
var formattedDate: String? {
|
||||
let isoDateFormatter = ISO8601DateFormatter()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.locale = Locale.current
|
||||
dateFormatter.timeStyle = .short
|
||||
|
||||
if let date = isoDateFormatter.date(from: lastUpdate) {
|
||||
return dateFormatter.string(from: date)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
class WidgetData {
|
||||
|
||||
static let WidgetDataStoreKey = "WidgetDataStoreKey"
|
||||
static let WidgetCachedDataStoreKey = "WidgetCachedDataStoreKey"
|
||||
|
||||
static func savePriceRateAndLastUpdate(rate: String, lastUpdate: String) {
|
||||
guard let userDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue) else { return }
|
||||
userDefaults.setValue(["rate": rate, "lastUpdate": lastUpdate], forKey: WidgetDataStoreKey)
|
||||
userDefaults.synchronize()
|
||||
}
|
||||
|
||||
}
|
@ -35,10 +35,10 @@ struct WalletInformationAndMarketWidgetProvider: TimelineProvider {
|
||||
let timeline = Timeline(entries: entries, policy: .atEnd)
|
||||
completion(timeline)
|
||||
} else {
|
||||
let userPreferredCurrency = WidgetAPI.getUserPreferredCurrency()
|
||||
let userPreferredCurrency = Currency.getUserPreferredCurrency()
|
||||
let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime())
|
||||
|
||||
WidgetAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in
|
||||
MarketAPI.fetchMarketData(currency: userPreferredCurrency) { (result, error) in
|
||||
let entry: WalletInformationAndMarketWidgetEntry
|
||||
|
||||
if let result = result {
|
||||
|
230
package-lock.json
generated
230
package-lock.json
generated
@ -11,7 +11,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.20.0",
|
||||
"@bugsnag/react-native": "7.22.6",
|
||||
"@bugsnag/react-native": "7.22.7",
|
||||
"@bugsnag/source-maps": "2.3.2",
|
||||
"@keystonehq/bc-ur-registry": "0.6.4",
|
||||
"@ngraveio/bc-ur": "1.1.12",
|
||||
@ -97,10 +97,10 @@
|
||||
"react-native-tcp-socket": "6.0.6",
|
||||
"react-native-vector-icons": "10.0.3",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webview": "13.8.4",
|
||||
"react-native-webview": "13.8.6",
|
||||
"react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38",
|
||||
"readable-stream": "3.6.2",
|
||||
"realm": "12.6.2",
|
||||
"realm": "12.7.0",
|
||||
"rn-ldk": "github:BlueWallet/rn-ldk#v0.8.4",
|
||||
"rn-nodeify": "10.3.0",
|
||||
"scryptsy": "2.1.0",
|
||||
@ -2140,9 +2140,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@bugsnag/core": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/core/-/core-7.19.0.tgz",
|
||||
"integrity": "sha512-2KGwdaLD9PhR7Wk7xPi3jGuGsKTatc/28U4TOZIDU3CgC2QhGjubwiXSECel5gwxhZ3jACKcMKSV2ovHhv1NrA==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/core/-/core-7.22.7.tgz",
|
||||
"integrity": "sha512-9DPWBkkBjhFJc5dCFy/wVC3HE0Aw3ZiLJKjyAxgywSKbILgtpD+qT1Xe8sacWyxU92znamlZ8H8ziQOe7jhhbA==",
|
||||
"dependencies": {
|
||||
"@bugsnag/cuid": "^3.0.0",
|
||||
"@bugsnag/safe-json-stringify": "^6.0.0",
|
||||
@ -2152,38 +2152,38 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/cuid": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/cuid/-/cuid-3.0.2.tgz",
|
||||
"integrity": "sha512-cIwzC93r3PQ/INeuwtZwkZIG2K8WWN0rRLZQhu+mr48Ay+i6sEki4GYfTsflse7hZ1BeDWrNb/Q9vgY3B31xHQ=="
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/cuid/-/cuid-3.1.0.tgz",
|
||||
"integrity": "sha512-U6vPVhFPLWLXQIGnmk/uPbyidB5xLVFfEdZDmmLbv41Be67re4mNsjMukHdUv669RXOWTDQNJ+bMODhuWpshkw=="
|
||||
},
|
||||
"node_modules/@bugsnag/delivery-react-native": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/delivery-react-native/-/delivery-react-native-7.22.3.tgz",
|
||||
"integrity": "sha512-6lHcberdmzVDlMumM3Ff6A/Ycmo4nIWN28d+Q1i13HS1AYnbmry9wVRzgC/dYfad7Nk5zKwOR9yhwQz7xUaBzw==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/delivery-react-native/-/delivery-react-native-7.22.7.tgz",
|
||||
"integrity": "sha512-PfJ8kcGzoW2KTC8CGSVjdmnIMUDGym3YyYNWr2K397NHs2oW0f/wprbQUx+WAotogK6BSSGzD0dnEX45cepYdA==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-console-breadcrumbs": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-console-breadcrumbs/-/plugin-console-breadcrumbs-7.22.3.tgz",
|
||||
"integrity": "sha512-SFfyFlvjkeQ9cJK64QLDdhNjSttpS/fbTxi4UnB1CTjj9G1spD4InUUnXDFHtSis4Dnx2GL4lWUbXXhE0cXIfw==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-console-breadcrumbs/-/plugin-console-breadcrumbs-7.22.7.tgz",
|
||||
"integrity": "sha512-f+nEy0+pLepPhPtEe94Yqm1qJH8ayZmLIjuTYvtcyC2+2kF6g1DMctPFn0EBKv7wvT2P7Vls6PgTLaohjECHOg==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-network-breadcrumbs": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-network-breadcrumbs/-/plugin-network-breadcrumbs-7.22.3.tgz",
|
||||
"integrity": "sha512-C1hpB05pvXBSI9rv9N3AxJBRJ3hY7BLIgkNRKYq+E3l8HNFipDrDGKt0i7R6nUSmolSFJkheQqr12BNmdOPosw==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-network-breadcrumbs/-/plugin-network-breadcrumbs-7.22.7.tgz",
|
||||
"integrity": "sha512-+zAq9D0G58+b/IJ/LGE2eNOIYrgIgQltJPMWdAyQFZcJWTqulN61ggt9yD2dO5PfSpAE/7KhNsR9TVbRPMb/qA==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react/-/plugin-react-7.19.0.tgz",
|
||||
"integrity": "sha512-owC4QXYJWGllMoOPcH5P7sbDIDuFLMCbjGAU6FwH5mBMObSQo+1ViSKImlTJQUFXATM8ySISTBVt7w3C6FFHng==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react/-/plugin-react-7.22.7.tgz",
|
||||
"integrity": "sha512-CDyCHK5+KMkpf/2vmVC7xqqP4ys25Yuj9M8xVrmP7LC02nFUPt/UzEIt43MSO4Jfw254ZimbsQrhIweabQNyxQ==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
},
|
||||
@ -2194,69 +2194,69 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react-native-client-sync": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-client-sync/-/plugin-react-native-client-sync-7.22.3.tgz",
|
||||
"integrity": "sha512-Ji5k8JRjFVyZYwGdlPRHTGbJNQI9n/rd/bqZn8697wQtl49M8WStVuLYlYoqMvjRpYaAmL7XQlNXRb/1Y8AkRQ==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-client-sync/-/plugin-react-native-client-sync-7.22.7.tgz",
|
||||
"integrity": "sha512-tFPQyRLa5dwJh7wkiYliQviLcD4zxaxucZcCn3moTGAcL5Oc/BpmACpOnYXuBeF9w7gFZMcHTsxvrhld9X1QQQ==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react-native-event-sync": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-event-sync/-/plugin-react-native-event-sync-7.22.3.tgz",
|
||||
"integrity": "sha512-xqvVcRjpAtOcS9e3jdW8h+SiZQwjd2yVmbKVLo2NESAbjeMVQcdTLogdUrdG92JnI5UnVWFW1bqoQqtug6shxA==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-event-sync/-/plugin-react-native-event-sync-7.22.7.tgz",
|
||||
"integrity": "sha512-wmjOyhMcxh0GeC1xk/XgWYutRCeaSiK89mkL3A+e3sJHv3Cmc6UNY9b0v38jMBr8L7ef5KnDy/9Yh0D0pR7DxQ==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react-native-global-error-handler": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-global-error-handler/-/plugin-react-native-global-error-handler-7.22.3.tgz",
|
||||
"integrity": "sha512-nJwwpg3EPbTbCoi+FuxFwU4svJnqbIyHqBw1IddXiGUmI6irYnI700HYDmeFIEZXEmaX19lrOPhdhecGLhOolg==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-global-error-handler/-/plugin-react-native-global-error-handler-7.22.7.tgz",
|
||||
"integrity": "sha512-+zreCSjUkGviU76LacuNnTUK+oj5Fs4ZT4xdh7PZhWb0z4CZol/d6GR20OPNHpyLEuuLMjXMZsqu9sXnr+VKdw==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react-native-hermes": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-hermes/-/plugin-react-native-hermes-7.19.0.tgz",
|
||||
"integrity": "sha512-6SGTSR6NMS2t8j02ZQ6FlA+K/nKkZqvGA+8A7WS/0M8HAShzyoMpZH10kGrU2dcCaiEtmD2T6OGBSbpF+385Dg==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-hermes/-/plugin-react-native-hermes-7.22.7.tgz",
|
||||
"integrity": "sha512-6Oqwi4KghjlPKkr+LDKBxJeorCnCeUahQuVFHXq/45gThH50CDQ4GduraZX9iqtThKX1T8PPIODubWyH6PF2Vg==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react-native-session": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-session/-/plugin-react-native-session-7.22.3.tgz",
|
||||
"integrity": "sha512-lreErWPZgjnoiGHD282+a9tCsFN4D34XEjbYLRnLRLjlugJeuTnkvDAYTFtmYpMDyEg/WBhWMaNqAdpJPj/nkQ==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-session/-/plugin-react-native-session-7.22.7.tgz",
|
||||
"integrity": "sha512-p3C7m6GXh9ICnGt+m1FwWpBCiGNGdQvoTzzN0LAxT6YQdB3t2nmhqE3QIpHmXpJK1PveTCIOO2DbeSerWtUEsg==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/plugin-react-native-unhandled-rejection": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-unhandled-rejection/-/plugin-react-native-unhandled-rejection-7.19.0.tgz",
|
||||
"integrity": "sha512-+XDk0OoeM6MZhBh7kEalbRwFuhCZST6Y1jOostfz0fhrmT4FdgQYi1FWcPNsUTcjqv7M48pOFZNx8yWI0lGaYg==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-unhandled-rejection/-/plugin-react-native-unhandled-rejection-7.22.7.tgz",
|
||||
"integrity": "sha512-xmFpUPYrQxwsr9RJ1HTu9lfNUbAHM+hIyUEshg+/Wfj/1Zvnkr0AnkqRWbQFqkOBklzYI4s7maJvm4S2go/KOQ==",
|
||||
"peerDependencies": {
|
||||
"@bugsnag/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@bugsnag/react-native": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/react-native/-/react-native-7.22.6.tgz",
|
||||
"integrity": "sha512-0TVul4cN0VVNzKkiiZTmmSNtFoOC5SGCW2ncikdF1sijc5IsavXDRemVMfLGg1xm0w3BWNsUjujmrmGCvkLxLA==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/react-native/-/react-native-7.22.7.tgz",
|
||||
"integrity": "sha512-vHmynQj7rzPW+1v8aK41G9T5HSaXipgFkkCmczOiFG9YYNzVKeaPcbwcS6Z6+tLZ55ZQeJdupfezcmj4rnAZVw==",
|
||||
"dependencies": {
|
||||
"@bugsnag/core": "^7.19.0",
|
||||
"@bugsnag/delivery-react-native": "^7.22.3",
|
||||
"@bugsnag/plugin-console-breadcrumbs": "^7.22.3",
|
||||
"@bugsnag/plugin-network-breadcrumbs": "^7.22.3",
|
||||
"@bugsnag/plugin-react": "^7.19.0",
|
||||
"@bugsnag/plugin-react-native-client-sync": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-event-sync": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-global-error-handler": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-hermes": "^7.19.0",
|
||||
"@bugsnag/plugin-react-native-session": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-unhandled-rejection": "^7.19.0",
|
||||
"@bugsnag/core": "^7.22.7",
|
||||
"@bugsnag/delivery-react-native": "^7.22.7",
|
||||
"@bugsnag/plugin-console-breadcrumbs": "^7.22.7",
|
||||
"@bugsnag/plugin-network-breadcrumbs": "^7.22.7",
|
||||
"@bugsnag/plugin-react": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-client-sync": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-event-sync": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-global-error-handler": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-hermes": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-session": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-unhandled-rejection": "^7.22.7",
|
||||
"iserror": "^0.0.2"
|
||||
}
|
||||
},
|
||||
@ -19828,9 +19828,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-webview": {
|
||||
"version": "13.8.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.4.tgz",
|
||||
"integrity": "sha512-dFoM9EfkAb++ZzycZyKRnjZtNUn85cf6bWp1iBlkgyNml7ULzR1gfaPT3qESoA3K1RfTmf5Xhw0M2In2A3a3wg==",
|
||||
"version": "13.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.6.tgz",
|
||||
"integrity": "sha512-jtZ9OgB2AN6rhDwto6dNL3PtOtl/SI4VN93pZEPbMLvRjqHfxiUrilGllL5fKAXq5Ry5FJyfUi82A4Ii8olZ7A==",
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "2.0.0",
|
||||
"invariant": "2.2.4"
|
||||
@ -20090,9 +20090,9 @@
|
||||
"integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg=="
|
||||
},
|
||||
"node_modules/realm": {
|
||||
"version": "12.6.2",
|
||||
"resolved": "https://registry.npmjs.org/realm/-/realm-12.6.2.tgz",
|
||||
"integrity": "sha512-6ICUaKHNeiEAwVIKC3AkCDTCVEtpkFAVeWvmUVdmVIUjcY/+2cMLe/tgFpLcY7pEB/n1EUg3pVyUBcVuMvwdqg==",
|
||||
"version": "12.7.0",
|
||||
"resolved": "https://registry.npmjs.org/realm/-/realm-12.7.0.tgz",
|
||||
"integrity": "sha512-8epWL4lLd1ZoA7gWfZdqlKDt9JqfoeEAcS66P8afXlFKATMhdUnUqYVFUfYhgV4KtC/JQCwipd0ysxVAY8nKuQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@realm/fetch": "^0.1.1",
|
||||
@ -23911,9 +23911,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@bugsnag/core": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/core/-/core-7.19.0.tgz",
|
||||
"integrity": "sha512-2KGwdaLD9PhR7Wk7xPi3jGuGsKTatc/28U4TOZIDU3CgC2QhGjubwiXSECel5gwxhZ3jACKcMKSV2ovHhv1NrA==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/core/-/core-7.22.7.tgz",
|
||||
"integrity": "sha512-9DPWBkkBjhFJc5dCFy/wVC3HE0Aw3ZiLJKjyAxgywSKbILgtpD+qT1Xe8sacWyxU92znamlZ8H8ziQOe7jhhbA==",
|
||||
"requires": {
|
||||
"@bugsnag/cuid": "^3.0.0",
|
||||
"@bugsnag/safe-json-stringify": "^6.0.0",
|
||||
@ -23923,76 +23923,76 @@
|
||||
}
|
||||
},
|
||||
"@bugsnag/cuid": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/cuid/-/cuid-3.0.2.tgz",
|
||||
"integrity": "sha512-cIwzC93r3PQ/INeuwtZwkZIG2K8WWN0rRLZQhu+mr48Ay+i6sEki4GYfTsflse7hZ1BeDWrNb/Q9vgY3B31xHQ=="
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/cuid/-/cuid-3.1.0.tgz",
|
||||
"integrity": "sha512-U6vPVhFPLWLXQIGnmk/uPbyidB5xLVFfEdZDmmLbv41Be67re4mNsjMukHdUv669RXOWTDQNJ+bMODhuWpshkw=="
|
||||
},
|
||||
"@bugsnag/delivery-react-native": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/delivery-react-native/-/delivery-react-native-7.22.3.tgz",
|
||||
"integrity": "sha512-6lHcberdmzVDlMumM3Ff6A/Ycmo4nIWN28d+Q1i13HS1AYnbmry9wVRzgC/dYfad7Nk5zKwOR9yhwQz7xUaBzw=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/delivery-react-native/-/delivery-react-native-7.22.7.tgz",
|
||||
"integrity": "sha512-PfJ8kcGzoW2KTC8CGSVjdmnIMUDGym3YyYNWr2K397NHs2oW0f/wprbQUx+WAotogK6BSSGzD0dnEX45cepYdA=="
|
||||
},
|
||||
"@bugsnag/plugin-console-breadcrumbs": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-console-breadcrumbs/-/plugin-console-breadcrumbs-7.22.3.tgz",
|
||||
"integrity": "sha512-SFfyFlvjkeQ9cJK64QLDdhNjSttpS/fbTxi4UnB1CTjj9G1spD4InUUnXDFHtSis4Dnx2GL4lWUbXXhE0cXIfw=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-console-breadcrumbs/-/plugin-console-breadcrumbs-7.22.7.tgz",
|
||||
"integrity": "sha512-f+nEy0+pLepPhPtEe94Yqm1qJH8ayZmLIjuTYvtcyC2+2kF6g1DMctPFn0EBKv7wvT2P7Vls6PgTLaohjECHOg=="
|
||||
},
|
||||
"@bugsnag/plugin-network-breadcrumbs": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-network-breadcrumbs/-/plugin-network-breadcrumbs-7.22.3.tgz",
|
||||
"integrity": "sha512-C1hpB05pvXBSI9rv9N3AxJBRJ3hY7BLIgkNRKYq+E3l8HNFipDrDGKt0i7R6nUSmolSFJkheQqr12BNmdOPosw=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-network-breadcrumbs/-/plugin-network-breadcrumbs-7.22.7.tgz",
|
||||
"integrity": "sha512-+zAq9D0G58+b/IJ/LGE2eNOIYrgIgQltJPMWdAyQFZcJWTqulN61ggt9yD2dO5PfSpAE/7KhNsR9TVbRPMb/qA=="
|
||||
},
|
||||
"@bugsnag/plugin-react": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react/-/plugin-react-7.19.0.tgz",
|
||||
"integrity": "sha512-owC4QXYJWGllMoOPcH5P7sbDIDuFLMCbjGAU6FwH5mBMObSQo+1ViSKImlTJQUFXATM8ySISTBVt7w3C6FFHng=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react/-/plugin-react-7.22.7.tgz",
|
||||
"integrity": "sha512-CDyCHK5+KMkpf/2vmVC7xqqP4ys25Yuj9M8xVrmP7LC02nFUPt/UzEIt43MSO4Jfw254ZimbsQrhIweabQNyxQ=="
|
||||
},
|
||||
"@bugsnag/plugin-react-native-client-sync": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-client-sync/-/plugin-react-native-client-sync-7.22.3.tgz",
|
||||
"integrity": "sha512-Ji5k8JRjFVyZYwGdlPRHTGbJNQI9n/rd/bqZn8697wQtl49M8WStVuLYlYoqMvjRpYaAmL7XQlNXRb/1Y8AkRQ=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-client-sync/-/plugin-react-native-client-sync-7.22.7.tgz",
|
||||
"integrity": "sha512-tFPQyRLa5dwJh7wkiYliQviLcD4zxaxucZcCn3moTGAcL5Oc/BpmACpOnYXuBeF9w7gFZMcHTsxvrhld9X1QQQ=="
|
||||
},
|
||||
"@bugsnag/plugin-react-native-event-sync": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-event-sync/-/plugin-react-native-event-sync-7.22.3.tgz",
|
||||
"integrity": "sha512-xqvVcRjpAtOcS9e3jdW8h+SiZQwjd2yVmbKVLo2NESAbjeMVQcdTLogdUrdG92JnI5UnVWFW1bqoQqtug6shxA=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-event-sync/-/plugin-react-native-event-sync-7.22.7.tgz",
|
||||
"integrity": "sha512-wmjOyhMcxh0GeC1xk/XgWYutRCeaSiK89mkL3A+e3sJHv3Cmc6UNY9b0v38jMBr8L7ef5KnDy/9Yh0D0pR7DxQ=="
|
||||
},
|
||||
"@bugsnag/plugin-react-native-global-error-handler": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-global-error-handler/-/plugin-react-native-global-error-handler-7.22.3.tgz",
|
||||
"integrity": "sha512-nJwwpg3EPbTbCoi+FuxFwU4svJnqbIyHqBw1IddXiGUmI6irYnI700HYDmeFIEZXEmaX19lrOPhdhecGLhOolg=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-global-error-handler/-/plugin-react-native-global-error-handler-7.22.7.tgz",
|
||||
"integrity": "sha512-+zreCSjUkGviU76LacuNnTUK+oj5Fs4ZT4xdh7PZhWb0z4CZol/d6GR20OPNHpyLEuuLMjXMZsqu9sXnr+VKdw=="
|
||||
},
|
||||
"@bugsnag/plugin-react-native-hermes": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-hermes/-/plugin-react-native-hermes-7.19.0.tgz",
|
||||
"integrity": "sha512-6SGTSR6NMS2t8j02ZQ6FlA+K/nKkZqvGA+8A7WS/0M8HAShzyoMpZH10kGrU2dcCaiEtmD2T6OGBSbpF+385Dg=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-hermes/-/plugin-react-native-hermes-7.22.7.tgz",
|
||||
"integrity": "sha512-6Oqwi4KghjlPKkr+LDKBxJeorCnCeUahQuVFHXq/45gThH50CDQ4GduraZX9iqtThKX1T8PPIODubWyH6PF2Vg=="
|
||||
},
|
||||
"@bugsnag/plugin-react-native-session": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-session/-/plugin-react-native-session-7.22.3.tgz",
|
||||
"integrity": "sha512-lreErWPZgjnoiGHD282+a9tCsFN4D34XEjbYLRnLRLjlugJeuTnkvDAYTFtmYpMDyEg/WBhWMaNqAdpJPj/nkQ=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-session/-/plugin-react-native-session-7.22.7.tgz",
|
||||
"integrity": "sha512-p3C7m6GXh9ICnGt+m1FwWpBCiGNGdQvoTzzN0LAxT6YQdB3t2nmhqE3QIpHmXpJK1PveTCIOO2DbeSerWtUEsg=="
|
||||
},
|
||||
"@bugsnag/plugin-react-native-unhandled-rejection": {
|
||||
"version": "7.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-unhandled-rejection/-/plugin-react-native-unhandled-rejection-7.19.0.tgz",
|
||||
"integrity": "sha512-+XDk0OoeM6MZhBh7kEalbRwFuhCZST6Y1jOostfz0fhrmT4FdgQYi1FWcPNsUTcjqv7M48pOFZNx8yWI0lGaYg=="
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/plugin-react-native-unhandled-rejection/-/plugin-react-native-unhandled-rejection-7.22.7.tgz",
|
||||
"integrity": "sha512-xmFpUPYrQxwsr9RJ1HTu9lfNUbAHM+hIyUEshg+/Wfj/1Zvnkr0AnkqRWbQFqkOBklzYI4s7maJvm4S2go/KOQ=="
|
||||
},
|
||||
"@bugsnag/react-native": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/react-native/-/react-native-7.22.6.tgz",
|
||||
"integrity": "sha512-0TVul4cN0VVNzKkiiZTmmSNtFoOC5SGCW2ncikdF1sijc5IsavXDRemVMfLGg1xm0w3BWNsUjujmrmGCvkLxLA==",
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@bugsnag/react-native/-/react-native-7.22.7.tgz",
|
||||
"integrity": "sha512-vHmynQj7rzPW+1v8aK41G9T5HSaXipgFkkCmczOiFG9YYNzVKeaPcbwcS6Z6+tLZ55ZQeJdupfezcmj4rnAZVw==",
|
||||
"requires": {
|
||||
"@bugsnag/core": "^7.19.0",
|
||||
"@bugsnag/delivery-react-native": "^7.22.3",
|
||||
"@bugsnag/plugin-console-breadcrumbs": "^7.22.3",
|
||||
"@bugsnag/plugin-network-breadcrumbs": "^7.22.3",
|
||||
"@bugsnag/plugin-react": "^7.19.0",
|
||||
"@bugsnag/plugin-react-native-client-sync": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-event-sync": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-global-error-handler": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-hermes": "^7.19.0",
|
||||
"@bugsnag/plugin-react-native-session": "^7.22.3",
|
||||
"@bugsnag/plugin-react-native-unhandled-rejection": "^7.19.0",
|
||||
"@bugsnag/core": "^7.22.7",
|
||||
"@bugsnag/delivery-react-native": "^7.22.7",
|
||||
"@bugsnag/plugin-console-breadcrumbs": "^7.22.7",
|
||||
"@bugsnag/plugin-network-breadcrumbs": "^7.22.7",
|
||||
"@bugsnag/plugin-react": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-client-sync": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-event-sync": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-global-error-handler": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-hermes": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-session": "^7.22.7",
|
||||
"@bugsnag/plugin-react-native-unhandled-rejection": "^7.22.7",
|
||||
"iserror": "^0.0.2"
|
||||
}
|
||||
},
|
||||
@ -37369,9 +37369,9 @@
|
||||
}
|
||||
},
|
||||
"react-native-webview": {
|
||||
"version": "13.8.4",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.4.tgz",
|
||||
"integrity": "sha512-dFoM9EfkAb++ZzycZyKRnjZtNUn85cf6bWp1iBlkgyNml7ULzR1gfaPT3qESoA3K1RfTmf5Xhw0M2In2A3a3wg==",
|
||||
"version": "13.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.6.tgz",
|
||||
"integrity": "sha512-jtZ9OgB2AN6rhDwto6dNL3PtOtl/SI4VN93pZEPbMLvRjqHfxiUrilGllL5fKAXq5Ry5FJyfUi82A4Ii8olZ7A==",
|
||||
"requires": {
|
||||
"escape-string-regexp": "2.0.0",
|
||||
"invariant": "2.2.4"
|
||||
@ -37481,9 +37481,9 @@
|
||||
"integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg=="
|
||||
},
|
||||
"realm": {
|
||||
"version": "12.6.2",
|
||||
"resolved": "https://registry.npmjs.org/realm/-/realm-12.6.2.tgz",
|
||||
"integrity": "sha512-6ICUaKHNeiEAwVIKC3AkCDTCVEtpkFAVeWvmUVdmVIUjcY/+2cMLe/tgFpLcY7pEB/n1EUg3pVyUBcVuMvwdqg==",
|
||||
"version": "12.7.0",
|
||||
"resolved": "https://registry.npmjs.org/realm/-/realm-12.7.0.tgz",
|
||||
"integrity": "sha512-8epWL4lLd1ZoA7gWfZdqlKDt9JqfoeEAcS66P8afXlFKATMhdUnUqYVFUfYhgV4KtC/JQCwipd0ysxVAY8nKuQ==",
|
||||
"requires": {
|
||||
"@realm/fetch": "^0.1.1",
|
||||
"bson": "^4.7.2",
|
||||
|
@ -98,7 +98,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.20.0",
|
||||
"@bugsnag/react-native": "7.22.6",
|
||||
"@bugsnag/react-native": "7.22.7",
|
||||
"@bugsnag/source-maps": "2.3.2",
|
||||
"@keystonehq/bc-ur-registry": "0.6.4",
|
||||
"@ngraveio/bc-ur": "1.1.12",
|
||||
@ -184,10 +184,10 @@
|
||||
"react-native-tcp-socket": "6.0.6",
|
||||
"react-native-vector-icons": "10.0.3",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webview": "13.8.4",
|
||||
"react-native-webview": "13.8.6",
|
||||
"react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38",
|
||||
"readable-stream": "3.6.2",
|
||||
"realm": "12.6.2",
|
||||
"realm": "12.7.0",
|
||||
"rn-ldk": "github:BlueWallet/rn-ldk#v0.8.4",
|
||||
"rn-nodeify": "10.3.0",
|
||||
"scryptsy": "2.1.0",
|
||||
|
@ -1,12 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ActivityIndicator, KeyboardAvoidingView, Linking, StyleSheet, Platform, TextInput, View, Keyboard } from 'react-native';
|
||||
import { useRoute, useNavigation } from '@react-navigation/native';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
|
||||
import loc from '../../loc';
|
||||
import { HDSegwitBech32Wallet } from '../../class';
|
||||
import navigationStyle from '../../components/navigationStyle';
|
||||
import {
|
||||
BlueBigCheckmark,
|
||||
BlueButtonLink,
|
||||
@ -24,6 +21,7 @@ import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/h
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import { scanQrHelper } from '../../helpers/scan-qr';
|
||||
import { isTablet } from 'react-native-device-info';
|
||||
|
||||
const BROADCAST_RESULT = Object.freeze({
|
||||
none: 'Input transaction hex',
|
||||
@ -32,13 +30,17 @@ const BROADCAST_RESULT = Object.freeze({
|
||||
error: 'error',
|
||||
});
|
||||
|
||||
const Broadcast = () => {
|
||||
interface SuccessScreenProps {
|
||||
tx: string;
|
||||
}
|
||||
|
||||
const Broadcast: React.FC = () => {
|
||||
const { name } = useRoute();
|
||||
const { navigate } = useNavigation();
|
||||
const [tx, setTx] = useState();
|
||||
const [txHex, setTxHex] = useState();
|
||||
const [tx, setTx] = useState<string | undefined>();
|
||||
const [txHex, setTxHex] = useState<string | undefined>();
|
||||
const { colors } = useTheme();
|
||||
const [broadcastResult, setBroadcastResult] = useState(BROADCAST_RESULT.none);
|
||||
const [broadcastResult, setBroadcastResult] = useState<string>(BROADCAST_RESULT.none);
|
||||
|
||||
const stylesHooks = StyleSheet.create({
|
||||
input: {
|
||||
@ -48,7 +50,7 @@ const Broadcast = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const handleUpdateTxHex = nextValue => setTxHex(nextValue.trim());
|
||||
const handleUpdateTxHex = (nextValue: string) => setTxHex(nextValue.trim());
|
||||
|
||||
const handleBroadcast = async () => {
|
||||
Keyboard.dismiss();
|
||||
@ -57,19 +59,22 @@ const Broadcast = () => {
|
||||
await BlueElectrum.ping();
|
||||
await BlueElectrum.waitTillConnected();
|
||||
const walletObj = new HDSegwitBech32Wallet();
|
||||
const result = await walletObj.broadcastTx(txHex);
|
||||
if (result) {
|
||||
const newTx = bitcoin.Transaction.fromHex(txHex);
|
||||
const txid = newTx.getId();
|
||||
setTx(txid);
|
||||
if (txHex) {
|
||||
const result = await walletObj.broadcastTx(txHex);
|
||||
if (result) {
|
||||
const newTx = bitcoin.Transaction.fromHex(txHex);
|
||||
const txid = newTx.getId();
|
||||
setTx(txid);
|
||||
|
||||
setBroadcastResult(BROADCAST_RESULT.success);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
Notifications.majorTomToGroundControl([], [], [txid]);
|
||||
} else {
|
||||
setBroadcastResult(BROADCAST_RESULT.error);
|
||||
setBroadcastResult(BROADCAST_RESULT.success);
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
||||
// @ts-ignore: fix later
|
||||
Notifications.majorTomToGroundControl([], [], [txid]);
|
||||
} else {
|
||||
setBroadcastResult(BROADCAST_RESULT.error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
presentAlert({ title: loc.errors.error, message: error.message });
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
|
||||
setBroadcastResult(BROADCAST_RESULT.error);
|
||||
@ -86,7 +91,7 @@ const Broadcast = () => {
|
||||
}
|
||||
|
||||
try {
|
||||
// sould be base64 encoded PSBT
|
||||
// should be base64 encoded PSBT
|
||||
const validTx = bitcoin.Psbt.fromBase64(scannedData).extractTransaction();
|
||||
return handleUpdateTxHex(validTx.toHex());
|
||||
} catch (e) {}
|
||||
@ -112,11 +117,7 @@ const Broadcast = () => {
|
||||
|
||||
return (
|
||||
<SafeArea>
|
||||
<KeyboardAvoidingView
|
||||
enabled={!Platform.isPad}
|
||||
behavior={Platform.OS === 'ios' ? 'position' : null}
|
||||
keyboardShouldPersistTaps="handled"
|
||||
>
|
||||
<KeyboardAvoidingView enabled={!isTablet} behavior={Platform.OS === 'ios' ? 'position' : undefined}>
|
||||
<View style={styles.wrapper} testID="BroadcastView">
|
||||
{BROADCAST_RESULT.success !== broadcastResult && (
|
||||
<BlueCard style={styles.mainCard}>
|
||||
@ -128,10 +129,6 @@ const Broadcast = () => {
|
||||
<View style={[styles.input, stylesHooks.input]}>
|
||||
<TextInput
|
||||
style={styles.text}
|
||||
maxHeight={100}
|
||||
minHeight={100}
|
||||
maxWidth="100%"
|
||||
minWidth="100%"
|
||||
multiline
|
||||
editable
|
||||
placeholderTextColor="#81868e"
|
||||
@ -155,15 +152,34 @@ const Broadcast = () => {
|
||||
<BlueSpacing20 />
|
||||
</BlueCard>
|
||||
)}
|
||||
{BROADCAST_RESULT.success === broadcastResult && <SuccessScreen tx={tx} />}
|
||||
{BROADCAST_RESULT.success === broadcastResult && tx && <SuccessScreen tx={tx} />}
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</SafeArea>
|
||||
);
|
||||
};
|
||||
|
||||
const SuccessScreen: React.FC<SuccessScreenProps> = ({ tx }) => {
|
||||
if (!tx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<BlueCard>
|
||||
<View style={styles.broadcastResultWrapper}>
|
||||
<BlueBigCheckmark />
|
||||
<BlueSpacing20 />
|
||||
<BlueTextCentered>{loc.settings.success_transaction_broadcasted}</BlueTextCentered>
|
||||
<BlueSpacing10 />
|
||||
<BlueButtonLink title={loc.settings.open_link_in_explorer} onPress={() => Linking.openURL(`https://mempool.space/tx/${tx}`)} />
|
||||
</View>
|
||||
</BlueCard>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Broadcast;
|
||||
Broadcast.navigationOptions = navigationStyle({}, opts => ({ ...opts, title: loc.send.create_broadcast }));
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
@ -203,31 +219,10 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
text: {
|
||||
padding: 8,
|
||||
minHeight: 33,
|
||||
color: '#81868e',
|
||||
maxHeight: 100,
|
||||
minHeight: 100,
|
||||
maxWidth: '100%',
|
||||
minWidth: '100%',
|
||||
},
|
||||
});
|
||||
|
||||
const SuccessScreen = ({ tx }) => {
|
||||
if (!tx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.wrapper}>
|
||||
<BlueCard>
|
||||
<View style={styles.broadcastResultWrapper}>
|
||||
<BlueBigCheckmark />
|
||||
<BlueSpacing20 />
|
||||
<BlueTextCentered>{loc.settings.success_transaction_broadcasted}</BlueTextCentered>
|
||||
<BlueSpacing10 />
|
||||
<BlueButtonLink title={loc.settings.open_link_in_explorer} onPress={() => Linking.openURL(`https://mempool.space/tx/${tx}`)} />
|
||||
</View>
|
||||
</BlueCard>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
SuccessScreen.propTypes = {
|
||||
tx: PropTypes.string.isRequired,
|
||||
};
|
@ -12,7 +12,7 @@ import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import { requestCameraAuthorization } from '../../helpers/scan-qr';
|
||||
import { Button } from '../../components/Button';
|
||||
import { AppStorage } from '../../BlueApp';
|
||||
import { BlueApp } from '../../class';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
uri: {
|
||||
@ -62,7 +62,7 @@ const LightningSettings: React.FC & { navigationOptions: NavigationOptionsGetter
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
AsyncStorage.getItem(AppStorage.LNDHUB)
|
||||
AsyncStorage.getItem(BlueApp.LNDHUB)
|
||||
.then(value => setURI(value ?? undefined))
|
||||
.then(() => setIsLoading(false))
|
||||
.catch(() => setIsLoading(false));
|
||||
@ -101,9 +101,9 @@ const LightningSettings: React.FC & { navigationOptions: NavigationOptionsGetter
|
||||
// validating only if its not empty. empty means use default
|
||||
}
|
||||
if (URI) {
|
||||
await AsyncStorage.setItem(AppStorage.LNDHUB, URI);
|
||||
await AsyncStorage.setItem(BlueApp.LNDHUB, URI);
|
||||
} else {
|
||||
await AsyncStorage.removeItem(AppStorage.LNDHUB);
|
||||
await AsyncStorage.removeItem(BlueApp.LNDHUB);
|
||||
}
|
||||
presentAlert({ message: loc.settings.lightning_saved });
|
||||
} catch (error) {
|
||||
|
@ -18,7 +18,14 @@ import {
|
||||
import { BlueButtonLink, BlueFormLabel, BlueSpacing20, BlueSpacing40, BlueText } from '../../BlueComponents';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { BlueStorageContext } from '../../blue_modules/storage-context';
|
||||
import { HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet, LightningLdkWallet, SegwitP2SHWallet } from '../../class';
|
||||
import {
|
||||
BlueApp,
|
||||
HDSegwitBech32Wallet,
|
||||
HDSegwitP2SHWallet,
|
||||
LightningCustodianWallet,
|
||||
LightningLdkWallet,
|
||||
SegwitP2SHWallet,
|
||||
} from '../../class';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import Button from '../../components/Button';
|
||||
import { LdkButton } from '../../components/LdkButton';
|
||||
@ -27,7 +34,6 @@ import { useTheme } from '../../components/themes';
|
||||
import useAsyncPromise from '../../hooks/useAsyncPromise';
|
||||
import loc from '../../loc';
|
||||
import { Chain } from '../../models/bitcoinUnits';
|
||||
import { AppStorage } from '../../BlueApp';
|
||||
import WalletButton from '../../components/WalletButton';
|
||||
import A from '../../blue_modules/analytics';
|
||||
|
||||
@ -143,7 +149,7 @@ const WalletsAdd: React.FC = () => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
AsyncStorage.getItem(AppStorage.LNDHUB)
|
||||
AsyncStorage.getItem(BlueApp.LNDHUB)
|
||||
.then(url => (url ? setWalletBaseURI(url) : setWalletBaseURI('')))
|
||||
.catch(() => setWalletBaseURI(''))
|
||||
.finally(() => setIsLoading(false));
|
||||
|
@ -3,7 +3,7 @@ const path = require('path');
|
||||
|
||||
const mainLocFile = './loc/en.json';
|
||||
const dirsToInterate = ['components', 'screen', 'blue_modules', 'class', 'hooks', 'helpers'];
|
||||
const addFiles = ['BlueComponents.js', 'App.js', 'BlueApp.ts', 'Navigation.tsx'];
|
||||
const addFiles = ['BlueComponents.js', 'App.js', 'Navigation.tsx'];
|
||||
const allowedLocPrefixes = ['loc.lnurl_auth', 'loc.units'];
|
||||
|
||||
const allLocKeysHashmap = {}; // loc key -> used or not
|
||||
|
@ -1,7 +1,6 @@
|
||||
import assert from 'assert';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { SegwitP2SHWallet } from '../../class';
|
||||
import { AppStorage } from '../../BlueApp';
|
||||
import { SegwitP2SHWallet, BlueApp } from '../../class';
|
||||
|
||||
jest.mock('../../blue_modules/BlueElectrum', () => {
|
||||
return {
|
||||
@ -10,8 +9,8 @@ jest.mock('../../blue_modules/BlueElectrum', () => {
|
||||
});
|
||||
|
||||
it('Appstorage - loadFromDisk works', async () => {
|
||||
/** @type {AppStorage} */
|
||||
const Storage = new AppStorage();
|
||||
/** @type {BlueApp} */
|
||||
const Storage = new BlueApp();
|
||||
const w = new SegwitP2SHWallet();
|
||||
w.setLabel('testlabel');
|
||||
await w.generate();
|
||||
@ -20,7 +19,7 @@ it('Appstorage - loadFromDisk works', async () => {
|
||||
|
||||
// saved, now trying to load
|
||||
|
||||
const Storage2 = new AppStorage();
|
||||
const Storage2 = new BlueApp();
|
||||
await Storage2.loadFromDisk();
|
||||
assert.strictEqual(Storage2.wallets.length, 1);
|
||||
assert.strictEqual(Storage2.wallets[0].getLabel(), 'testlabel');
|
||||
@ -30,15 +29,15 @@ it('Appstorage - loadFromDisk works', async () => {
|
||||
// emulating encrypted storage (and testing flag)
|
||||
|
||||
await AsyncStorage.setItem('data', false);
|
||||
await AsyncStorage.setItem(AppStorage.FLAG_ENCRYPTED, '1');
|
||||
const Storage3 = new AppStorage();
|
||||
await AsyncStorage.setItem(BlueApp.FLAG_ENCRYPTED, '1');
|
||||
const Storage3 = new BlueApp();
|
||||
isEncrypted = await Storage3.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
});
|
||||
|
||||
it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
/** @type {AppStorage} */
|
||||
const Storage = new AppStorage();
|
||||
/** @type {BlueApp} */
|
||||
const Storage = new BlueApp();
|
||||
let w = new SegwitP2SHWallet();
|
||||
w.setLabel('testlabel');
|
||||
await w.generate();
|
||||
@ -53,7 +52,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
|
||||
// saved, now trying to load, using good password
|
||||
|
||||
let Storage2 = new AppStorage();
|
||||
let Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
let loadResult = await Storage2.loadFromDisk('password');
|
||||
@ -63,7 +62,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
|
||||
// now trying to load, using bad password
|
||||
|
||||
Storage2 = new AppStorage();
|
||||
Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage2.loadFromDisk('passwordBAD');
|
||||
@ -73,7 +72,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
// now, trying case with adding data after decrypt.
|
||||
// saveToDisk should be handled correctly
|
||||
|
||||
Storage2 = new AppStorage();
|
||||
Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage2.loadFromDisk('password');
|
||||
@ -88,7 +87,7 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
|
||||
await Storage2.saveToDisk();
|
||||
// saved to encrypted storage after load. next load should be successfull
|
||||
Storage2 = new AppStorage();
|
||||
Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage2.loadFromDisk('password');
|
||||
@ -109,13 +108,13 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
await Storage2.saveToDisk();
|
||||
// now, will try to load & decrypt with real password and with fake password
|
||||
// real:
|
||||
let Storage3 = new AppStorage();
|
||||
let Storage3 = new BlueApp();
|
||||
loadResult = await Storage3.loadFromDisk('password');
|
||||
assert.ok(loadResult);
|
||||
assert.strictEqual(Storage3.wallets.length, 2);
|
||||
assert.strictEqual(Storage3.wallets[0].getLabel(), 'testlabel');
|
||||
// fake:
|
||||
Storage3 = new AppStorage();
|
||||
Storage3 = new BlueApp();
|
||||
loadResult = await Storage3.loadFromDisk('fakePassword');
|
||||
assert.ok(loadResult);
|
||||
assert.strictEqual(Storage3.wallets.length, 1);
|
||||
@ -123,8 +122,8 @@ it('Appstorage - encryptStorage & load encrypted storage works', async () => {
|
||||
});
|
||||
|
||||
it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load storage works', async () => {
|
||||
/** @type {AppStorage} */
|
||||
const Storage = new AppStorage();
|
||||
/** @type {BlueApp} */
|
||||
const Storage = new BlueApp();
|
||||
let w = new SegwitP2SHWallet();
|
||||
w.setLabel('testlabel');
|
||||
await w.generate();
|
||||
@ -139,7 +138,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
|
||||
// saved, now trying to load, using good password
|
||||
|
||||
let Storage2 = new AppStorage();
|
||||
let Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
let loadResult = await Storage2.loadFromDisk('password');
|
||||
@ -149,7 +148,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
|
||||
// now trying to load, using bad password
|
||||
|
||||
Storage2 = new AppStorage();
|
||||
Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage2.loadFromDisk('passwordBAD');
|
||||
@ -159,7 +158,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
// now, trying case with adding data after decrypt.
|
||||
// saveToDisk should be handled correctly
|
||||
|
||||
Storage2 = new AppStorage();
|
||||
Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage2.loadFromDisk('password');
|
||||
@ -174,7 +173,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
assert.strictEqual(Storage2.wallets[1].getLabel(), 'testlabel2');
|
||||
await Storage2.saveToDisk();
|
||||
// saved to encrypted storage after load. next load should be successfull
|
||||
Storage2 = new AppStorage();
|
||||
Storage2 = new BlueApp();
|
||||
isEncrypted = await Storage2.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage2.loadFromDisk('password');
|
||||
@ -195,13 +194,13 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
await Storage2.saveToDisk();
|
||||
// now, will try to load & decrypt with real password and with fake password
|
||||
// real:
|
||||
let Storage3 = new AppStorage();
|
||||
let Storage3 = new BlueApp();
|
||||
loadResult = await Storage3.loadFromDisk('password');
|
||||
assert.ok(loadResult);
|
||||
assert.strictEqual(Storage3.wallets.length, 2);
|
||||
assert.strictEqual(Storage3.wallets[0].getLabel(), 'testlabel');
|
||||
// fake:
|
||||
Storage3 = new AppStorage();
|
||||
Storage3 = new BlueApp();
|
||||
loadResult = await Storage3.loadFromDisk('fakePassword');
|
||||
assert.ok(loadResult);
|
||||
assert.strictEqual(Storage3.wallets.length, 1);
|
||||
@ -209,7 +208,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
|
||||
// now will decrypt storage. label of wallet should be testlabel
|
||||
|
||||
const Storage4 = new AppStorage();
|
||||
const Storage4 = new BlueApp();
|
||||
isEncrypted = await Storage4.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage4.loadFromDisk('password');
|
||||
@ -217,7 +216,7 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
const decryptStorageResult = await Storage4.decryptStorage('password');
|
||||
assert.ok(decryptStorageResult);
|
||||
|
||||
const Storage5 = new AppStorage();
|
||||
const Storage5 = new BlueApp();
|
||||
isEncrypted = await Storage5.storageIsEncrypted();
|
||||
assert.strictEqual(isEncrypted, false);
|
||||
const storage5loadResult = await Storage5.loadFromDisk();
|
||||
@ -228,8 +227,8 @@ it('Appstorage - encryptStorage & load encrypted, then decryptStorage and load s
|
||||
});
|
||||
|
||||
it('can decrypt storage that is second in a list of buckets; and isPasswordInUse() works', async () => {
|
||||
/** @type {AppStorage} */
|
||||
const Storage = new AppStorage();
|
||||
/** @type {BlueApp} */
|
||||
const Storage = new BlueApp();
|
||||
let w = new SegwitP2SHWallet();
|
||||
w.setLabel('testlabel');
|
||||
await w.generate();
|
||||
@ -256,7 +255,7 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
|
||||
// now will decrypt storage. will try to decrypt FAKE storage (second in the list) while
|
||||
// currently decrypted is the MAIN (non-fake) storage. this should throw an exception
|
||||
|
||||
const Storage4 = new AppStorage();
|
||||
const Storage4 = new BlueApp();
|
||||
isEncrypted = await Storage4.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
let loadResult = await Storage4.loadFromDisk('password');
|
||||
@ -275,7 +274,7 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
|
||||
// storage, purging other buckets. this should be possible since if user wants to shoot himsel in the foot
|
||||
// he should be able to do it.
|
||||
|
||||
const Storage5 = new AppStorage();
|
||||
const Storage5 = new BlueApp();
|
||||
isEncrypted = await Storage5.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage5.loadFromDisk('fakePassword');
|
||||
@ -288,7 +287,7 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
|
||||
|
||||
// now we will decrypt storage. label of wallet should be testlabel
|
||||
|
||||
const Storage6 = new AppStorage();
|
||||
const Storage6 = new BlueApp();
|
||||
isEncrypted = await Storage6.storageIsEncrypted();
|
||||
assert.ok(isEncrypted);
|
||||
loadResult = await Storage6.loadFromDisk('fakePassword');
|
||||
@ -296,7 +295,7 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
|
||||
const decryptStorageResult = await Storage6.decryptStorage('fakePassword');
|
||||
assert.ok(decryptStorageResult);
|
||||
|
||||
const Storage7 = new AppStorage();
|
||||
const Storage7 = new BlueApp();
|
||||
isEncrypted = await Storage7.storageIsEncrypted();
|
||||
assert.strictEqual(isEncrypted, false);
|
||||
const storage5loadResult = await Storage7.loadFromDisk();
|
||||
@ -305,6 +304,6 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
|
||||
});
|
||||
|
||||
it('Appstorage - hashIt() works', async () => {
|
||||
const storage = new AppStorage();
|
||||
const storage = new BlueApp();
|
||||
assert.strictEqual(storage.hashIt('hello'), '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user