Merge branch 'master' into successreuse

This commit is contained in:
marcosrdz 2020-11-22 22:20:19 -05:00
commit c419719958
35 changed files with 570 additions and 136 deletions

47
App.js
View File

@ -1,17 +1,6 @@
import 'react-native-gesture-handler'; // should be on top
import React, { useContext, useEffect, useRef, useState } from 'react';
import {
Linking,
DeviceEventEmitter,
AppState,
StyleSheet,
KeyboardAvoidingView,
Platform,
View,
useColorScheme,
useWindowDimensions,
} from 'react-native';
import Modal from 'react-native-modal';
import { AppState, DeviceEventEmitter, KeyboardAvoidingView, Linking, Platform, StyleSheet, useColorScheme, View } from 'react-native';
import { NavigationContainer, CommonActions } from '@react-navigation/native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { navigationRef } from './NavigationService';
@ -25,6 +14,7 @@ import OnAppLaunch from './class/on-app-launch';
import DeeplinkSchemaMatch from './class/deeplink-schema-match';
import loc from './loc';
import { BlueDefaultTheme, BlueDarkTheme, BlueCurrentTheme } from './components/themes';
import BottomModal from './components/BottomModal';
import InitRoot from './Navigation';
import BlueClipboard from './blue_modules/clipboard';
import { BlueStorageContext } from './blue_modules/storage-context';
@ -36,22 +26,25 @@ import Biometric from './class/biometrics';
import WidgetCommunication from './blue_modules/WidgetCommunication';
import changeNavigationBarColor from 'react-native-navigation-bar-color';
const A = require('./blue_modules/analytics');
if (process.env.NODE_ENV !== 'development') {
Sentry.init({
dsn: 'https://23377936131848ca8003448a893cb622@sentry.io/1295736',
});
}
const bitcoinModalString = 'Bitcoin address';
const lightningModalString = 'Lightning Invoice';
const ClipboardContentType = Object.freeze({
BITCOIN: 'BITCOIN',
LIGHTNING: 'LIGHTNING',
});
const App = () => {
const { walletsInitialized, wallets, addWallet, saveToDisk, fetchAndSaveWalletTransactions } = useContext(BlueStorageContext);
const appState = useRef(AppState.currentState);
const [isClipboardContentModalVisible, setIsClipboardContentModalVisible] = useState(false);
const [clipboardContentModalAddressType, setClipboardContentModalAddressType] = useState(bitcoinModalString);
const [clipboardContentType, setClipboardContentType] = useState();
const [clipboardContent, setClipboardContent] = useState('');
const colorScheme = useColorScheme();
const { height } = useWindowDimensions();
const stylesHook = StyleSheet.create({
modalContent: {
backgroundColor: colorScheme === 'dark' ? BlueDarkTheme.colors.elevated : BlueDefaultTheme.colors.elevated,
@ -228,11 +221,11 @@ const App = () => {
(isBitcoinAddress || isLightningInvoice || isLNURL || isBothBitcoinAndLightning)
) {
if (isBitcoinAddress) {
setClipboardContentModalAddressType(bitcoinModalString);
setClipboardContentType(ClipboardContentType.BITCOIN);
} else if (isLightningInvoice || isLNURL) {
setClipboardContentModalAddressType(lightningModalString);
setClipboardContentType(ClipboardContentType.LIGHTNING);
} else if (isBothBitcoinAndLightning) {
setClipboardContentModalAddressType(bitcoinModalString);
setClipboardContentType(ClipboardContentType.BITCOIN);
}
setIsClipboardContentModalVisible(true);
}
@ -254,18 +247,16 @@ const App = () => {
const renderClipboardContentModal = () => {
return (
<Modal
<BottomModal
onModalShow={() => ReactNativeHapticFeedback.trigger('impactLight', { ignoreAndroidSystemSettings: false })}
isVisible={isClipboardContentModalVisible}
style={styles.bottomModal}
deviceHeight={height}
onBackdropPress={hideClipboardContentModal}
onBackButtonPress={hideClipboardContentModal}
onClose={hideClipboardContentModal}
>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={[styles.modalContent, stylesHook.modalContent]}>
<BlueTextCentered>
You have a {clipboardContentModalAddressType} on your clipboard. Would you like to use it for a transaction?
{clipboardContentType === ClipboardContentType.BITCOIN && loc.wallets.clipboard_bitcoin}
{clipboardContentType === ClipboardContentType.LIGHTNING && loc.wallets.clipboard_lightning}
</BlueTextCentered>
<View style={styles.modelContentButtonLayout}>
<SecondButton noMinWidth title={loc._.cancel} onPress={hideClipboardContentModal} />
@ -282,7 +273,7 @@ const App = () => {
</View>
</View>
</KeyboardAvoidingView>
</Modal>
</BottomModal>
);
};
return (
@ -320,10 +311,6 @@ const styles = StyleSheet.create({
minHeight: 200,
height: 200,
},
bottomModal: {
justifyContent: 'flex-end',
margin: 0,
},
modelContentButtonLayout: {
flexDirection: 'row',
margin: 16,

View File

@ -70,7 +70,6 @@ import LnurlPay from './screen/lnd/lnurlPay';
import LnurlPaySuccess from './screen/lnd/lnurlPaySuccess';
import LoadingScreen from './LoadingScreen';
import UnlockWith from './UnlockWith';
import { BlueNavigationStyle } from './BlueComponents';
import DrawerList from './screen/wallets/drawerList';
import { isTablet } from 'react-native-device-info';
import SettingsPrivacy from './screen/settings/SettingsPrivacy';
@ -116,15 +115,7 @@ const WalletsRoot = () => (
<WalletsStack.Screen name="CPFP" component={CPFP} options={CPFP.navigationOptions} />
<WalletsStack.Screen name="RBFBumpFee" component={RBFBumpFee} options={RBFBumpFee.navigationOptions} />
<WalletsStack.Screen name="RBFCancel" component={RBFCancel} options={RBFCancel.navigationOptions} />
<WalletsStack.Screen
name="Settings"
component={Settings}
options={{
...BlueNavigationStyle(),
headerTitle: '',
}}
/>
<WalletsStack.Screen name="Settings" component={Settings} options={Settings.navigationOptions} />
<WalletsStack.Screen name="SelectWallet" component={SelectWallet} options={SelectWallet.navigationOptions} />
<WalletsStack.Screen name="Currency" component={Currency} options={Currency.navigationOptions} />
<WalletsStack.Screen name="About" component={About} options={About.navigationOptions} />

View File

@ -1,7 +1,7 @@
import Frisbee from 'frisbee';
import AsyncStorage from '@react-native-community/async-storage';
import { AppStorage } from '../class';
import { FiatUnit } from '../models/fiatUnit';
import { FiatServerResponse, FiatUnit } from '../models/fiatUnit';
import DefaultPreference from 'react-native-default-preference';
import RNWidgetCenter from 'react-native-widget-center';
import * as RNLocalize from 'react-native-localize';
@ -55,16 +55,14 @@ async function updateExchangeRate() {
}
}
let json;
let response;
const fiatServerResponse = new FiatServerResponse(preferredFiatCurrency);
try {
const api = new Frisbee({
baseURI: 'https://api.coindesk.com',
baseURI: fiatServerResponse.baseURI(),
});
const response = await api.get('/v1/bpi/currentprice/' + preferredFiatCurrency.endPointKey + '.json');
json = JSON.parse(response.body);
if (!json || !json.bpi || !json.bpi[preferredFiatCurrency.endPointKey] || !json.bpi[preferredFiatCurrency.endPointKey].rate_float) {
throw new Error('Could not update currency rate: ' + response.err);
}
response = await api.get(fiatServerResponse.endPoint());
fiatServerResponse.isErrorFound(response);
} catch (Err) {
console.warn(Err);
const lastSavedExchangeRate = JSON.parse(await AsyncStorage.getItem(AppStorage.EXCHANGE_RATES));
@ -73,7 +71,7 @@ async function updateExchangeRate() {
}
exchangeRates[STRUCT.LAST_UPDATED] = +new Date();
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = json.bpi[preferredFiatCurrency.endPointKey].rate_float * 1;
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = fiatServerResponse.rate(response);
await AsyncStorage.setItem(AppStorage.EXCHANGE_RATES, JSON.stringify(exchangeRates));
await AsyncStorage.setItem(AppStorage.PREFERRED_CURRENCY, JSON.stringify(preferredFiatCurrency));
await setPrefferedCurrency(preferredFiatCurrency);

View File

@ -20,6 +20,14 @@
32F0A29A2311DBB20095C559 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F0A2992311DBB20095C559 /* ComplicationController.swift */; };
5875B7B2D85DC56E00F292FF /* libPods-WalletInformationWidgetExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CC8A6C610EAE90F810EADCC /* libPods-WalletInformationWidgetExtension.a */; platformFilter = ios; };
590C62D2ED8BF487C33945B0 /* libPods-WalletInformationAndMarketWidgetExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 98455D960744E4E5DD50BA87 /* libPods-WalletInformationAndMarketWidgetExtension.a */; platformFilter = ios; };
6D2AA7FA2568B8750090B089 /* FiatUnits.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6D2AA7F92568B8750090B089 /* FiatUnits.plist */; };
6D2AA7FB2568B8750090B089 /* FiatUnits.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6D2AA7F92568B8750090B089 /* FiatUnits.plist */; };
6D2AA7FC2568B8750090B089 /* FiatUnits.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6D2AA7F92568B8750090B089 /* FiatUnits.plist */; };
6D2AA7FD2568B8750090B089 /* FiatUnits.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6D2AA7F92568B8750090B089 /* FiatUnits.plist */; };
6D2AA8082568B8F40090B089 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
6D2AA8092568B8F40090B089 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
6D2AA80A2568B8F40090B089 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
6D2AA80B2568B8F40090B089 /* FiatUnit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D2AA8072568B8F40090B089 /* FiatUnit.swift */; };
6D641F18255226DA003792DF /* MarketView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F17255226DA003792DF /* MarketView.swift */; };
6D641F19255226DA003792DF /* MarketView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F17255226DA003792DF /* MarketView.swift */; };
6D641F2325525054003792DF /* WalletInformationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D641F2225525053003792DF /* WalletInformationView.swift */; };
@ -290,6 +298,8 @@
6D294A9C24D512770039E22B /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/MainInterface.strings; sourceTree = "<group>"; };
6D294A9D24D5127F0039E22B /* xh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = xh; path = xh.lproj/Interface.strings; sourceTree = "<group>"; };
6D294A9E24D512800039E22B /* xh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = xh; path = xh.lproj/MainInterface.strings; sourceTree = "<group>"; };
6D2AA7F92568B8750090B089 /* FiatUnits.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = FiatUnits.plist; sourceTree = "<group>"; };
6D2AA8072568B8F40090B089 /* FiatUnit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FiatUnit.swift; sourceTree = "<group>"; };
6D333B3A252FE1A3004D72DF /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
6D333B3C252FE1A3004D72DF /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
6D641F17255226DA003792DF /* MarketView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketView.swift; sourceTree = "<group>"; };
@ -556,6 +566,15 @@
name = Resources;
sourceTree = "<group>";
};
6D2AA8062568B8E50090B089 /* Fiat */ = {
isa = PBXGroup;
children = (
6D2AA7F92568B8750090B089 /* FiatUnits.plist */,
6D2AA8072568B8F40090B089 /* FiatUnit.swift */,
);
path = Fiat;
sourceTree = "<group>";
};
6D6CA4BB255872E3009312A5 /* PriceWidget */ = {
isa = PBXGroup;
children = (
@ -609,6 +628,7 @@
6DEB4BC1254FB98300E9F9AA /* Shared */ = {
isa = PBXGroup;
children = (
6D2AA8062568B8E50090B089 /* Fiat */,
6DEB4DD82552260200E9F9AA /* Views */,
6D9A2E6A254BAB1B007B5B82 /* WidgetAPI.swift */,
6D6CA5142558EBA3009312A5 /* WidgetAPI+Electrum.swift */,
@ -1046,6 +1066,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6D2AA7FD2568B8750090B089 /* FiatUnits.plist in Resources */,
6D6CA4D725587397009312A5 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1054,6 +1075,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6D2AA7FA2568B8750090B089 /* FiatUnits.plist in Resources */,
6D9946832555A695000E52E8 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1062,6 +1084,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6D2AA7FC2568B8750090B089 /* FiatUnits.plist in Resources */,
6D9A2E09254BA348007B5B82 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1070,6 +1093,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6D2AA7FB2568B8750090B089 /* FiatUnits.plist in Resources */,
6DEB4B05254FB79100E9F9AA /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1259,6 +1283,7 @@
6D6CA5322558ED4D009312A5 /* Colors.swift in Sources */,
6D6CA4BD255872E3009312A5 /* PriceWidget.swift in Sources */,
6D6CA5292558EC52009312A5 /* PriceView.swift in Sources */,
6D2AA80B2568B8F40090B089 /* FiatUnit.swift in Sources */,
6D6CA53C2558F316009312A5 /* WidgetAPI.swift in Sources */,
6D6CA5332558ED54009312A5 /* Models.swift in Sources */,
);
@ -1274,6 +1299,7 @@
6D9946882555A695000E52E8 /* SendReceiveButtons.swift in Sources */,
6D9946852555A695000E52E8 /* Colors.swift in Sources */,
6D99468A2555A695000E52E8 /* WidgetDataStore.swift in Sources */,
6D2AA8082568B8F40090B089 /* FiatUnit.swift in Sources */,
6D99467B2555A68A000E52E8 /* MarketView.swift in Sources */,
6D9946872555A695000E52E8 /* UserDefaultsGroup.swift in Sources */,
6D9946632555A660000E52E8 /* MarketWidget.swift in Sources */,
@ -1286,6 +1312,7 @@
buildActionMask = 2147483647;
files = (
6D641F2325525054003792DF /* WalletInformationView.swift in Sources */,
6D2AA80A2568B8F40090B089 /* FiatUnit.swift in Sources */,
6D9A2E6D254BAB1B007B5B82 /* WidgetAPI.swift in Sources */,
6DEB4C3B254FBF4800E9F9AA /* Colors.swift in Sources */,
6D6CA5282558EC52009312A5 /* PriceView.swift in Sources */,
@ -1309,6 +1336,7 @@
6DEB4BDA254FB98E00E9F9AA /* WidgetAPI.swift in Sources */,
6DEB4BDB254FB98E00E9F9AA /* UserDefaultsGroup.swift in Sources */,
6DEB4BD9254FB98E00E9F9AA /* WidgetDataStore.swift in Sources */,
6D2AA8092568B8F40090B089 /* FiatUnit.swift in Sources */,
6D641F3625526311003792DF /* SendReceiveButtons.swift in Sources */,
6DEB4BFC254FBA0E00E9F9AA /* Models.swift in Sources */,
6D641F19255226DA003792DF /* MarketView.swift in Sources */,

View File

@ -0,0 +1,54 @@
//
// FiatUnit.swift
// BlueWallet
//
// Created by Marcos Rodriguez on 11/20/20.
// Copyright © 2020 BlueWallet. All rights reserved.
//
import Foundation
typealias FiatUnits = [FiatUnit]
struct FiatUnit: Codable {
let endPointKey: String
let symbol: String
let locale: String
let dataSource: String?
let rateKey: String?
var rateURL: URL? {
if let dataSource = dataSource {
return URL(string: "\(dataSource)/\(endPointKey)")
} else {
return URL(string:"https://api.coindesk.com/v1/bpi/currentprice/\(endPointKey).json");
}
}
func currentRate(json: Dictionary<String, Any>) -> WidgetDataStore? {
if dataSource == nil {
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 {
return nil
}
return WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
} else {
guard let rateKey = rateKey, let rateDict = json[rateKey] as? [String: Any], let rateDouble = rateDict["price"] as? Double, let lastUpdated = json["timestamp"] as? Int else {
return nil
}
return WidgetDataStore(rate: String(rateDouble), lastUpdate: String(lastUpdated), rateDouble: rateDouble)
}
}
}
func fiatUnit(currency: String) -> FiatUnit? {
guard let file = Bundle.main.path(forResource: "FiatUnits", ofType: "plist") else {
return nil
}
let fileURL: URL = URL(fileURLWithPath: file)
var fiatUnits: FiatUnits?
if let data = try? Data(contentsOf: fileURL) {
let decoder = PropertyListDecoder()
fiatUnits = try? decoder.decode(FiatUnits.self, from: data)
}
return fiatUnits?.first(where: {$0.endPointKey == currency})
}

View File

@ -0,0 +1,310 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>endPointKey</key>
<string>USD</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>en-US</string>
</dict>
<dict>
<key>endPointKey</key>
<string>ARS</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>es-AR</string>
<key>dataSource</key>
<string>https://api.yadio.io/json</string>
<key>rateKey</key>
<string>ARS</string>
</dict>
<dict>
<key>endPointKey</key>
<string>AUD</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>en-AU</string>
</dict>
<dict>
<key>endPointKey</key>
<string>BRL</string>
<key>symbol</key>
<string>R$</string>
<key>locale</key>
<string>pt-BR</string>
</dict>
<dict>
<key>endPointKey</key>
<string>CAD</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>en-CA</string>
</dict>
<dict>
<key>endPointKey</key>
<string>CHF</string>
<key>symbol</key>
<string>CHF</string>
<key>locale</key>
<string>de-CH</string>
</dict>
<dict>
<key>endPointKey</key>
<string>CLP</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>es-CL</string>
</dict>
<dict>
<key>endPointKey</key>
<string>COP</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>es-CO</string>
</dict>
<dict>
<key>endPointKey</key>
<string>CZK</string>
<key>symbol</key>
<string>Kč</string>
<key>locale</key>
<string>cs-CZ</string>
</dict>
<dict>
<key>endPointKey</key>
<string>CNY</string>
<key>symbol</key>
<string>¥</string>
<key>locale</key>
<string>zh-CN</string>
</dict>
<dict>
<key>endPointKey</key>
<string>EUR</string>
<key>symbol</key>
<string>€</string>
<key>locale</key>
<string>en-IE</string>
</dict>
<dict>
<key>endPointKey</key>
<string>GBP</string>
<key>symbol</key>
<string>£</string>
<key>locale</key>
<string>en-GB</string>
</dict>
<dict>
<key>endPointKey</key>
<string>HRK</string>
<key>symbol</key>
<string>HRK</string>
<key>locale</key>
<string>hr-HR</string>
</dict>
<dict>
<key>endPointKey</key>
<string>HUF</string>
<key>symbol</key>
<string>Ft</string>
<key>locale</key>
<string>hu-HU</string>
</dict>
<dict>
<key>endPointKey</key>
<string>ILS</string>
<key>symbol</key>
<string>₪</string>
<key>locale</key>
<string>he-IL</string>
</dict>
<dict>
<key>endPointKey</key>
<string>INR</string>
<key>symbol</key>
<string>₹</string>
<key>locale</key>
<string>hi-HN</string>
</dict>
<dict>
<key>endPointKey</key>
<string>JPY</string>
<key>symbol</key>
<string>¥</string>
<key>locale</key>
<string>ja-JP</string>
</dict>
<dict>
<key>endPointKey</key>
<string>KES</string>
<key>symbol</key>
<string>Ksh</string>
<key>locale</key>
<string>en-KE</string>
</dict>
<dict>
<key>endPointKey</key>
<string>KRW</string>
<key>symbol</key>
<string>₩</string>
<key>locale</key>
<string>ko-KR</string>
</dict>
<dict>
<key>endPointKey</key>
<string>MXN</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>es-MX</string>
</dict>
<dict>
<key>endPointKey</key>
<string>MYR</string>
<key>symbol</key>
<string>RM</string>
<key>locale</key>
<string>ms-MY</string>
</dict>
<dict>
<key>endPointKey</key>
<string>NGN</string>
<key>symbol</key>
<string>₦</string>
<key>locale</key>
<string>en-NG</string>
</dict>
<dict>
<key>endPointKey</key>
<string>NOK</string>
<key>symbol</key>
<string>kr</string>
<key>locale</key>
<string>nb-NO</string>
</dict>
<dict>
<key>endPointKey</key>
<string>NZD</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>en-NZ</string>
</dict>
<dict>
<key>endPointKey</key>
<string>PLN</string>
<key>symbol</key>
<string>zł</string>
<key>locale</key>
<string>pl-PL</string>
</dict>
<dict>
<key>endPointKey</key>
<string>PHP</string>
<key>symbol</key>
<string>₱</string>
<key>locale</key>
<string>en-PH</string>
</dict>
<dict>
<key>endPointKey</key>
<string>RUB</string>
<key>symbol</key>
<string>₽</string>
<key>locale</key>
<string>ru-RU</string>
</dict>
<dict>
<key>endPointKey</key>
<string>SGD</string>
<key>symbol</key>
<string>S$</string>
<key>locale</key>
<string>zh-SG</string>
</dict>
<dict>
<key>endPointKey</key>
<string>SEK</string>
<key>symbol</key>
<string>kr</string>
<key>locale</key>
<string>sv-SE</string>
</dict>
<dict>
<key>endPointKey</key>
<string>TRY</string>
<key>symbol</key>
<string>₺</string>
<key>locale</key>
<string>tr-TR</string>
</dict>
<dict>
<key>endPointKey</key>
<string>THB</string>
<key>symbol</key>
<string>฿</string>
<key>locale</key>
<string>th-TH</string>
</dict>
<dict>
<key>endPointKey</key>
<string>TWD</string>
<key>symbol</key>
<string>NT$</string>
<key>locale</key>
<string>zh-Hant-TW</string>
</dict>
<dict>
<key>endPointKey</key>
<string>UAH</string>
<key>symbol</key>
<string>₴</string>
<key>locale</key>
<string>uk-UA</string>
</dict>
<dict>
<key>endPointKey</key>
<string>UYU</string>
<key>symbol</key>
<string>$</string>
<key>locale</key>
<string>es-UY</string>
</dict>
<dict>
<key>endPointKey</key>
<string>VEF</string>
<key>symbol</key>
<string>Bs.</string>
<key>locale</key>
<string>es-VE</string>
</dict>
<dict>
<key>endPointKey</key>
<string>VES</string>
<key>symbol</key>
<string>Bs.</string>
<key>locale</key>
<string>es-VE</string>
<key>dataSource</key>
<string>https://api.yadio.io/json</string>
<key>rateKey</key>
<string>VES</string>
</dict>
<dict>
<key>endPointKey</key>
<string>ZAR</string>
<key>symbol</key>
<string>R</string>
<key>locale</key>
<string>en-ZA</string>
</dict>
</array>
</plist>

View File

@ -28,7 +28,7 @@ struct MarketView: View {
Spacer()
HStack(alignment: .center, spacing: 0, content: {
Text("Sats/Dollar").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor)
Text("Sats/\(WidgetAPI.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)

View File

@ -21,22 +21,22 @@ var numberFormatter: NumberFormatter {
class WidgetAPI {
static func fetchPrice(currency: String, completion: @escaping ((WidgetDataStore?, Error?) -> Void)) {
guard let url = URL(string: "https://api.coindesk.com/v1/bpi/currentPrice/\(currency).json") else {return}
let currencyToFiatUnit = fiatUnit(currency: currency)
guard let url = currencyToFiatUnit?.rateURL else {return}
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>) as Dictionary<String, Any>??),
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 }
guard let bpi = json?["bpi"] as? Dictionary<String, Any>, let preferredCurrency = bpi[currency] 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 {
guard let latestRateDataStore = currencyToFiatUnit?.currentRate(json: json)
else {
print(error?.localizedDescription ?? "Response Error")
completion(nil, error)
return }
let latestRateDataStore = WidgetDataStore(rate: rateString, lastUpdate: lastUpdatedString, rateDouble: rateDouble)
completion(latestRateDataStore, nil)
}.resume()
}

View File

@ -15,12 +15,11 @@ struct WidgetDataStore {
var formattedRate: String? {
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: WidgetAPI.getUserPreferredCurrencyLocale())
numberFormatter.numberStyle = .decimal
numberFormatter.numberStyle = .currency
numberFormatter.maximumFractionDigits = 0
numberFormatter.minimumFractionDigits = 0
if let rateNumber = numberFormatter.number(from: rate) {
numberFormatter.numberStyle = .currency
return numberFormatter.string(from: rateNumber);
if let rateString = numberFormatter.string(from: NSNumber(value: rateDouble)) {
return rateString
}
return rate
}

View File

@ -224,7 +224,7 @@
"about_sm_twitter": "تابعنا على تويتر",
"advanced_options": "الخيارات المتقدمة",
"currency": "العملة",
"currency_source": "يتم الحصول على الأسعار من CoinDesk",
"currency_source": "يتم الحصول على الأسعار من",
"default_desc": "عند تعطيل هذا الإعداد، ستفتح BlueWallet المحفظة المحدَّدة فور التشغيل.",
"default_info": "Default info",
"default_title": "عند التشغيل",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Sleduj nás na Twitteru",
"advanced_options": "Pokročilé možnosti",
"currency": "Měna",
"currency_source": "Ceny jsou získány od CoinDesk",
"currency_source": "Ceny jsou získány od",
"default_desc": "Pokud je zakázána, BlueWallet při spuštění ihned otevře vybranou peněženku.",
"default_info": "Výchozí informace",
"default_title": "Při spuštění",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Folgt uns auf Twitter",
"advanced_options": "Erweiterte Optionen",
"currency": "Währung",
"currency_source": "Die Preisangaben stammen von CoinDesk",
"currency_source": "Die Preisangaben stammen von",
"default_desc": "Wenn deaktiviert öffnet BlueWallet beim Start die ausgewählte Wallet.",
"default_info": "Standard Info",
"default_title": "Beim Start",

View File

@ -234,7 +234,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "Currency",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",
@ -293,7 +293,7 @@
},
"notifications": {
"would_you_like_to_receive_notifications": "Would you like to receive notifications when you get incoming payments?",
"no_and_dont_ask": "No and dont ask",
"no_and_dont_ask": "No, and Don't Ask Me Again",
"ask_me_later": "Ask Me Later"
},
"transactions": {
@ -327,14 +327,13 @@
"transactions_count": "transactions count"
},
"wallets": {
"add_bitcoin_explain": "Simple and powerful Bitcoin wallet",
"add_bitcoin": "Bitcoin",
"add_bitcoin_explain": "Simple and powerful Bitcoin wallet",
"add_create": "Create",
"add_entropy_generated": "{gen} bytes of generated entropy",
"add_entropy_provide": "Provide entropy via dice rolls",
"add_entropy_remain": "{gen} bytes of generated entropy. Remaining {rem} bytes will be obtained from the System random number generator.",
"add_import_wallet": "Import wallet",
"import_file": "Import File",
"add_lightning": "Lightning",
"add_lightning_explain": "For spending with instant transactions",
"add_lndhub": "Connect to your LNDHub",
@ -344,6 +343,8 @@
"add_title": "add wallet",
"add_wallet_name": "name",
"add_wallet_type": "type",
"clipboard_bitcoin": "You have a Bitcoin address on your clipboard. Would you like to use it for a transaction?",
"clipboard_lightning": "You have a Lightning Invoice on your clipboard. Would you like to use it for a transaction?",
"details_address": "Address",
"details_advanced": "Advanced",
"details_are_you_sure": "Are you sure?",
@ -365,15 +366,15 @@
"details_use_with_hardware_wallet": "Use with hardware wallet",
"details_wallet_updated": "Wallet updated",
"details_yes_delete": "Yes, delete",
"enter_bip38_password": "Enter password to decrypt",
"export_title": "wallet export",
"import_do_import": "Import",
"import_error": "Failed to import. Please, make sure that the provided data is valid.",
"import_explanation": "Write here your mnemonic, private key, WIF, or anything you've got. BlueWallet will do its best to guess the correct format and import your wallet",
"import_file": "Import File",
"import_imported": "Imported",
"import_scan_qr": "Scan or import a file",
"import_success": "Your wallet has been successfully imported.",
"looks_like_bip38": "This looks like password-protected private key (BIP38)",
"enter_bip38_password": "Enter password to decrypt",
"import_title": "import",
"list_create_a_button": "Add now",
"list_create_a_wallet": "Add a wallet",
@ -389,14 +390,15 @@
"list_long_choose": "Choose Photo",
"list_long_clipboard": "Copy from Clipboard",
"list_long_scan": "Scan QR Code",
"take_photo": "Take Photo",
"list_tap_here_to_buy": "Buy Bitcoin",
"list_title": "wallets",
"list_tryagain": "Try Again",
"looks_like_bip38": "This looks like password-protected private key (BIP38)",
"reorder_title": "Reorder Wallets",
"select_no_bitcoin": "There are currently no Bitcoin wallets available.",
"select_no_bitcoin_exp": "A Bitcoin wallet is required to refill Lightning wallets. Please, create or import one.",
"select_wallet": "Select Wallet",
"take_photo": "Take Photo",
"xpub_copiedToClipboard": "Copied to clipboard.",
"xpub_title": "wallet XPUB"
},

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Síguenos en Twitter",
"advanced_options": "Opciones avanzadas",
"currency": "Moneda",
"currency_source": "Los precios provienen de CoinDesk",
"currency_source": "Los precios provienen de",
"default_desc": "Cuando esté deshabilitado, BlueWallet abrirá por defecto la cartera seleccionada al iniciar la aplicación.",
"default_info": "Información por defecto",
"default_title": "Al iniciar",

View File

@ -227,7 +227,7 @@
"about_sm_twitter": "Siguenos en Twitter",
"advanced_options": "Opciones Avanzadas",
"currency": "Moneda",
"currency_source": "Precios obtenidos de CoinDesk",
"currency_source": "Precios obtenidos de",
"default_desc": "Cuando está deshabilitado, BlueWallet abrirá inmediatamente la billetera seleccionada al inicio",
"default_info": "Informacion por defecto",
"default_title": "En incio",

View File

@ -230,7 +230,7 @@
"about_sm_twitter": "Nous suivre sur Twitter",
"advanced_options": "Options avancées",
"currency": "Devise",
"currency_source": "Les prix sont obtenus depuis CoinDesk",
"currency_source": "Les prix sont obtenus depuis",
"default_desc": "Si désactivé, BlueWallet ouvrira immédiatement le portefeuille sélectionné au lancement.",
"default_info": "Information par défaut",
"default_title": "Au lancement",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "עקבו אחרינו בטוויטר",
"advanced_options": "אפשרויות מתקדמות",
"currency": "מטבע",
"currency_source": "מחירים מתקבלים מ- CoinDesk",
"currency_source": "מחירים מתקבלים מ-",
"default_desc": "כאשר מבוטל, BlueWallet יפתח אוטומטית את הארנק הנבחר בפתיחה.",
"default_info": "פתיחת ברירת מחדל",
"default_title": "בעת פתיחה",

View File

@ -224,7 +224,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "Mata Uang",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -40,7 +40,7 @@ dayjs.extend(relativeTime);
require('dayjs/locale/es');
break;
case 'es_419':
// es-do it is the closesd one to es_419
// es-do it is the closes one to es_419
lang = 'es-do';
require('dayjs/locale/es-do');
break;

View File

@ -224,7 +224,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "Valuta",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Volg ons op Twitter",
"advanced_options": "Geavanceerde opties",
"currency": "Valuta",
"currency_source": "Prijzen verstrekt bij CoinDesk",
"currency_source": "Prijzen verstrekt bij",
"default_desc": "Indien uitgeschakeld zal BlueWallet meteen de geselecteerde wallet openen bij het opstarten.",
"default_info": "Standaard info",
"default_title": "Bij opstarten",

View File

@ -234,7 +234,7 @@
"about_sm_twitter": "Siga-nos no Twitter",
"advanced_options": "Opções avançadas",
"currency": "Moeda",
"currency_source": "Os preços são obtidos no CoinDesk",
"currency_source": "Os preços são obtidos no",
"default_desc": "Quando desativado, o BlueWallet abrirá imediatamente a carteira selecionada no lançamento.",
"default_info": "Carteira padrão",
"default_title": "No lançamento",

View File

@ -224,7 +224,7 @@
"about_sm_twitter": "Segue-nos no Twitter",
"advanced_options": "Opções Avançadas",
"currency": "Moeda",
"currency_source": "Os preços são obtidos no CoinDesk",
"currency_source": "Os preços são obtidos no",
"default_desc": "Quando desactivado, a BlueWallet abrirá imediatamente a carteira seleccionada no lançamento.",
"default_info": "Carteira padrão",
"default_title": "A abrir",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Мы в Twitter",
"advanced_options": "Расширенные настройки",
"currency": "Валюта",
"currency_source": "Источник курсов CoinDesk",
"currency_source": "Источник курсов",
"default_desc": "Когда выключено BlueWallet сразу же откроет выбранный кошелек при запуске.",
"default_info": "Показать",
"default_title": "При старте",

View File

@ -230,7 +230,7 @@
"about_sm_twitter": "Sledujte nás na Twitteri",
"advanced_options": "Pokročilé nastavenia",
"currency": "Mena",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Sledite nam na Twitterju",
"advanced_options": "Napredne Možnosti",
"currency": "Valuta",
"currency_source": "Tečaji so pridobljeni iz CoinDesk",
"currency_source": "Tečaji so pridobljeni iz",
"default_desc": "Ko je onemogočeno, bo BlueWallet ob zagonu takoj odprl izbrano denarnico.",
"default_info": "Privzeto v",
"default_title": "Ob zagonu",

View File

@ -224,7 +224,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "Valuta",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -224,7 +224,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "Para Birimi",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -233,7 +233,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "货币",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -230,7 +230,7 @@
"about_sm_twitter": "Follow us on Twitter",
"advanced_options": "Advanced Options",
"currency": "貨幣",
"currency_source": "Prices are obtained from CoinDesk",
"currency_source": "Prices are obtained from",
"default_desc": "When disabled, BlueWallet will immediately open the selected wallet at launch.",
"default_info": "Default info",
"default_title": "On Launch",

View File

@ -1,37 +1,99 @@
export const FiatUnitSource = Object.freeze({ CoinDesk: 'CoinDesk', Yadio: 'Yadio' });
export const FiatUnit = Object.freeze({
USD: { endPointKey: 'USD', symbol: '$', locale: 'en-US' },
ARS: { endPointKey: 'ARS', symbol: '$', locale: 'es-AR' },
AUD: { endPointKey: 'AUD', symbol: '$', locale: 'en-AU' },
BRL: { endPointKey: 'BRL', symbol: 'R$', locale: 'pt-BR' },
CAD: { endPointKey: 'CAD', symbol: '$', locale: 'en-CA' },
CHF: { endPointKey: 'CHF', symbol: 'CHF', locale: 'de-CH' },
CLP: { endPointKey: 'CLP', symbol: '$', locale: 'es-CL' },
COP: { endPointKey: 'COP', symbol: '$', locale: 'es-CO' },
CZK: { endPointKey: 'CZK', symbol: 'Kč', locale: 'cs-CZ' },
CNY: { endPointKey: 'CNY', symbol: '¥', locale: 'zh-CN' },
EUR: { endPointKey: 'EUR', symbol: '€', locale: 'en-IE' },
GBP: { endPointKey: 'GBP', symbol: '£', locale: 'en-GB' },
HRK: { endPointKey: 'HRK', symbol: 'HRK', locale: 'hr-HR' },
HUF: { endPointKey: 'HUF', symbol: 'Ft', locale: 'hu-HU' },
ILS: { endPointKey: 'ILS', symbol: '₪', locale: 'he-IL' },
INR: { endPointKey: 'INR', symbol: '₹', locale: 'hi-HN' },
JPY: { endPointKey: 'JPY', symbol: '¥', locale: 'ja-JP' },
KES: { endPointKey: 'KES', symbol: 'Ksh', locale: 'en-KE' },
KRW: { endPointKey: 'KRW', symbol: '₩', locale: 'ko-KR' },
MXN: { endPointKey: 'MXN', symbol: '$', locale: 'es-MX' },
MYR: { endPointKey: 'MYR', symbol: 'RM', locale: 'ms-MY' },
NGN: { endPointKey: 'NGN', symbol: '₦', locale: 'en-NG' },
NOK: { endPointKey: 'NOK', symbol: 'kr', locale: 'nb-NO' },
NZD: { endPointKey: 'NZD', symbol: '$', locale: 'en-NZ' },
PLN: { endPointKey: 'PLN', symbol: 'zł', locale: 'pl-PL' },
PHP: { endPointKey: 'PHP', symbol: '₱', locale: 'en-PH' },
RUB: { endPointKey: 'RUB', symbol: '₽', locale: 'ru-RU' },
SGD: { endPointKey: 'SGD', symbol: 'S$', locale: 'zh-SG' },
SEK: { endPointKey: 'SEK', symbol: 'kr', locale: 'sv-SE' },
TRY: { endPointKey: 'TRY', symbol: '₺', locale: 'tr-TR' },
THB: { endPointKey: 'THB', symbol: '฿', locale: 'th-TH' },
TWD: { endPointKey: 'TWD', symbol: 'NT$', locale: 'zh-Hant-TW' },
UAH: { endPointKey: 'UAH', symbol: '₴', locale: 'uk-UA' },
VEF: { endPointKey: 'VEF', symbol: 'Bs.', locale: 'es-VE' },
ZAR: { endPointKey: 'ZAR', symbol: 'R', locale: 'en-ZA' },
USD: { endPointKey: 'USD', symbol: '$', locale: 'en-US', source: FiatUnitSource.CoinDesk },
ARS: {
endPointKey: 'ARS',
symbol: '$',
locale: 'es-AR',
dataSource: 'https://api.yadio.io/json',
rateKey: 'ARS',
source: FiatUnitSource.Yadio,
},
AUD: { endPointKey: 'AUD', symbol: '$', locale: 'en-AU', source: FiatUnitSource.CoinDesk },
BRL: { endPointKey: 'BRL', symbol: 'R$', locale: 'pt-BR', source: FiatUnitSource.CoinDesk },
CAD: { endPointKey: 'CAD', symbol: '$', locale: 'en-CA', source: FiatUnitSource.CoinDesk },
CHF: { endPointKey: 'CHF', symbol: 'CHF', locale: 'de-CH', source: FiatUnitSource.CoinDesk },
CLP: { endPointKey: 'CLP', symbol: '$', locale: 'es-CL', source: FiatUnitSource.CoinDesk },
COP: { endPointKey: 'COP', symbol: '$', locale: 'es-CO', source: FiatUnitSource.CoinDesk },
CZK: { endPointKey: 'CZK', symbol: 'Kč', locale: 'cs-CZ', source: FiatUnitSource.CoinDesk },
CNY: { endPointKey: 'CNY', symbol: '¥', locale: 'zh-CN', source: FiatUnitSource.CoinDesk },
EUR: { endPointKey: 'EUR', symbol: '€', locale: 'en-IE', source: FiatUnitSource.CoinDesk },
GBP: { endPointKey: 'GBP', symbol: '£', locale: 'en-GB', source: FiatUnitSource.CoinDesk },
HRK: { endPointKey: 'HRK', symbol: 'HRK', locale: 'hr-HR', source: FiatUnitSource.CoinDesk },
HUF: { endPointKey: 'HUF', symbol: 'Ft', locale: 'hu-HU', source: FiatUnitSource.CoinDesk },
ILS: { endPointKey: 'ILS', symbol: '₪', locale: 'he-IL', source: FiatUnitSource.CoinDesk },
INR: { endPointKey: 'INR', symbol: '₹', locale: 'hi-HN', source: FiatUnitSource.CoinDesk },
JPY: { endPointKey: 'JPY', symbol: '¥', locale: 'ja-JP', source: FiatUnitSource.CoinDesk },
KES: { endPointKey: 'KES', symbol: 'Ksh', locale: 'en-KE', source: FiatUnitSource.CoinDesk },
KRW: { endPointKey: 'KRW', symbol: '₩', locale: 'ko-KR', source: FiatUnitSource.CoinDesk },
MXN: { endPointKey: 'MXN', symbol: '$', locale: 'es-MX', source: FiatUnitSource.CoinDesk },
MYR: { endPointKey: 'MYR', symbol: 'RM', locale: 'ms-MY', source: FiatUnitSource.CoinDesk },
NGN: { endPointKey: 'NGN', symbol: '₦', locale: 'en-NG', source: FiatUnitSource.CoinDesk },
NOK: { endPointKey: 'NOK', symbol: 'kr', locale: 'nb-NO', source: FiatUnitSource.CoinDesk },
NZD: { endPointKey: 'NZD', symbol: '$', locale: 'en-NZ', source: FiatUnitSource.CoinDesk },
PLN: { endPointKey: 'PLN', symbol: 'zł', locale: 'pl-PL', source: FiatUnitSource.CoinDesk },
PHP: { endPointKey: 'PHP', symbol: '₱', locale: 'en-PH', source: FiatUnitSource.CoinDesk },
RUB: { endPointKey: 'RUB', symbol: '₽', locale: 'ru-RU', source: FiatUnitSource.CoinDesk },
SGD: { endPointKey: 'SGD', symbol: 'S$', locale: 'zh-SG', source: FiatUnitSource.CoinDesk },
SEK: { endPointKey: 'SEK', symbol: 'kr', locale: 'sv-SE', source: FiatUnitSource.CoinDesk },
TRY: { endPointKey: 'TRY', symbol: '₺', locale: 'tr-TR', source: FiatUnitSource.CoinDesk },
THB: { endPointKey: 'THB', symbol: '฿', locale: 'th-TH', source: FiatUnitSource.CoinDesk },
TWD: { endPointKey: 'TWD', symbol: 'NT$', locale: 'zh-Hant-TW', source: FiatUnitSource.CoinDesk },
UAH: { endPointKey: 'UAH', symbol: '₴', locale: 'uk-UA', source: FiatUnitSource.CoinDesk },
UYU: { endPointKey: 'UYU', symbol: '$', locale: 'es-UY', source: FiatUnitSource.CoinDesk },
VEF: { endPointKey: 'VEF', symbol: 'Bs.', locale: 'es-VE', source: FiatUnitSource.CoinDesk },
VES: {
endPointKey: 'VES',
symbol: 'Bs.',
locale: 'es-VE',
dataSource: 'https://api.yadio.io/json',
rateKey: 'VES',
source: FiatUnitSource.Yadio,
},
ZAR: { endPointKey: 'ZAR', symbol: 'R', locale: 'en-ZA', source: FiatUnitSource.CoinDesk },
});
export class FiatServerResponse {
constructor(fiatUnit) {
this.fiatUnit = fiatUnit;
}
baseURI = () => {
if (this.fiatUnit.dataSource) {
return this.fiatUnit.dataSource;
} else {
return 'https://api.coindesk.com';
}
};
endPoint = () => {
if (this.fiatUnit.dataSource) {
return `/${this.fiatUnit.endPointKey}`;
} else {
return '/v1/bpi/currentprice/' + this.fiatUnit.endPointKey + '.json';
}
};
rate = response => {
const json = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
if (this.fiatUnit.dataSource) {
return json[this.fiatUnit.rateKey].price * 1;
} else {
return json.bpi[this.fiatUnit.endPointKey].rate_float * 1;
}
};
isErrorFound = response => {
const json = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
if (this.fiatUnit.dataSource) {
if (!json || !json[this.fiatUnit.rateKey]) {
throw new Error('Could not update currency rate: ' + response.err);
}
} else {
if (!json || !json.bpi || !json.bpi[this.fiatUnit.endPointKey] || !json.bpi[this.fiatUnit.endPointKey].rate_float) {
throw new Error('Could not update currency rate: ' + response.err);
}
}
};
}

View File

@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react';
import { FlatList, TouchableOpacity, ActivityIndicator, View, StyleSheet } from 'react-native';
import { FlatList, ActivityIndicator, View, StyleSheet } from 'react-native';
import { SafeBlueArea, BlueListItem, BlueTextHooks, BlueCard, BlueNavigationStyle } from '../../BlueComponents';
import PropTypes from 'prop-types';
import { FiatUnit } from '../../models/fiatUnit';
import { FiatUnit, FiatUnitSource } from '../../models/fiatUnit';
import loc from '../../loc';
import { useTheme } from '@react-navigation/native';
const currency = require('../../blue_modules/currency');
@ -48,16 +48,14 @@ const Currency = () => {
style={styles.flex}
keyExtractor={(_item, index) => `${index}`}
data={data}
initialNumToRender={25}
extraData={data}
renderItem={({ item }) => {
return (
<BlueListItem
disabled={isSavingNewPreferredCurrency}
title={`${item.endPointKey} (${item.symbol})`}
{...(selectedCurrency.endPointKey === item.endPointKey
? { rightIcon: { name: 'check', type: 'octaicon', color: '#0070FF' } }
: { hideChevron: true })}
Component={TouchableOpacity}
checkmark={selectedCurrency.endPointKey === item.endPointKey}
onPress={async () => {
setIsSavingNewPreferredCurrency(true);
setSelectedCurrency(item);
@ -70,7 +68,9 @@ const Currency = () => {
}}
/>
<BlueCard>
<BlueTextHooks>{loc.settings.currency_source}</BlueTextHooks>
<BlueTextHooks>
{loc.settings.currency_source} {selectedCurrency.source ?? FiatUnitSource.CoinDesk}
</BlueTextHooks>
</BlueCard>
</SafeBlueArea>
);

View File

@ -1,6 +1,6 @@
import React from 'react';
import { ScrollView, TouchableOpacity, StyleSheet, StatusBar } from 'react-native';
import { BlueListItem, BlueHeaderDefaultSubHooks } from '../../BlueComponents';
import { BlueListItem, BlueNavigationStyle, BlueHeaderDefaultSubHooks } from '../../BlueComponents';
import { useNavigation } from '@react-navigation/native';
import loc from '../../loc';
@ -47,3 +47,7 @@ const Settings = () => {
};
export default Settings;
Settings.navigationOptions = () => ({
...BlueNavigationStyle(),
headerTitle: '',
});

View File

@ -141,16 +141,15 @@ const WalletsList = () => {
* Forcefully fetches TXs and balance for ALL wallets.
* Triggered manually by user on pull-to-refresh.
*/
const refreshTransactions = () => {
setIsLoading(true);
const refreshTransactions = (showLoadingIndicator = true) => {
setIsLoading(showLoadingIndicator);
refreshAllWalletTransactions().finally(() => setIsLoading(false));
};
useEffect(
refreshTransactions,
useEffect(() => {
refreshTransactions(false);
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
); // call refreshTransactions() only once, when screen mounts
}, []); // call refreshTransactions() only once, when screen mounts
const handleClick = index => {
console.log('click', index);
@ -197,7 +196,6 @@ const WalletsList = () => {
console.log('onSnapToItem', index);
if (wallets[index] && (wallets[index].timeToRefreshBalance() || wallets[index].timeToRefreshTransaction())) {
console.log(wallets[index].getLabel(), 'thinks its time to refresh either balance or transactions. refetching both');
setIsLoading(true);
refreshAllWalletTransactions(index).finally(() => setIsLoading(false));
}
};

View File

@ -6,6 +6,7 @@ vim ios/BlueWallet.xcodeproj/project.pbxproj
vim ios/WalletInformationWidget/Widgets/MarketWidget/Info.plist
vim ios/WalletInformationWidget/Widgets/WalletInformationAndMarketWidget/Info.plist
vim ios/WalletInformationWidget/Info.plist
vim ios/WalletInformationWidget/Widgets/PriceWidget/Info.plist
vim android/app/build.gradle
vim package.json
vim package-lock.json