Merge branch 'main' into CW-118-Allow-disabling-of-fiat

This commit is contained in:
Serhii 2022-11-22 19:48:43 +02:00
commit 50d32021f6
51 changed files with 520 additions and 538 deletions

View file

@ -46,7 +46,7 @@ android {
defaultConfig { defaultConfig {
applicationId appProperties['id'] applicationId appProperties['id']
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View file

@ -21,7 +21,8 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"> android:screenOrientation="portrait"
android:exported="true">
<meta-data <meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable" android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" android:resource="@drawable/launch_background"

View file

@ -36,7 +36,7 @@ class Node extends HiveObject with Keyable {
static const typeId = 1; static const typeId = 1;
static const boxName = 'Nodes'; static const boxName = 'Nodes';
@HiveField(0) @HiveField(0, defaultValue: '')
late String uriRaw; late String uriRaw;
@HiveField(1) @HiveField(1)
@ -45,7 +45,7 @@ class Node extends HiveObject with Keyable {
@HiveField(2) @HiveField(2)
String? password; String? password;
@HiveField(3) @HiveField(3, defaultValue: 0)
late int typeRaw; late int typeRaw;
@HiveField(4) @HiveField(4)

View file

@ -15,16 +15,16 @@ class UnspentCoinsInfo extends HiveObject {
static const boxName = 'Unspent'; static const boxName = 'Unspent';
static const boxKey = 'unspentBoxKey'; static const boxKey = 'unspentBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String walletId; String walletId;
@HiveField(1) @HiveField(1, defaultValue: '')
String hash; String hash;
@HiveField(2) @HiveField(2, defaultValue: false)
bool isFrozen; bool isFrozen;
@HiveField(3) @HiveField(3, defaultValue: false)
bool isSending; bool isSending;
@HiveField(4) @HiveField(4)

View file

@ -33,31 +33,31 @@ class WalletInfo extends HiveObject {
static const typeId = 4; static const typeId = 4;
static const boxName = 'WalletInfo'; static const boxName = 'WalletInfo';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: '')
String name; String name;
@HiveField(2) @HiveField(2)
WalletType type; WalletType type;
@HiveField(3) @HiveField(3, defaultValue: false)
bool isRecovery; bool isRecovery;
@HiveField(4) @HiveField(4, defaultValue: 0)
int restoreHeight; int restoreHeight;
@HiveField(5) @HiveField(5, defaultValue: 0)
int timestamp; int timestamp;
@HiveField(6) @HiveField(6, defaultValue: '')
String dirPath; String dirPath;
@HiveField(7) @HiveField(7, defaultValue: '')
String path; String path;
@HiveField(8) @HiveField(8, defaultValue: '')
String address; String address;
@HiveField(10) @HiveField(10)

View file

@ -252,4 +252,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f
COCOAPODS: 1.11.2 COCOAPODS: 1.11.3

View file

@ -5,11 +5,13 @@ import 'package:http/http.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/anypay/any_pay_payment.dart'; import 'package:cake_wallet/anypay/any_pay_payment.dart';
import 'package:cake_wallet/anypay/any_pay_trasnaction.dart'; import 'package:cake_wallet/anypay/any_pay_trasnaction.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
class AnyPayApi { class AnyPayApi {
static const contentTypePaymentRequest = 'application/payment-request'; static const contentTypePaymentRequest = 'application/payment-request';
static const contentTypePayment = 'application/payment'; static const contentTypePayment = 'application/payment';
static const xPayproVersion = '2'; static const xPayproVersion = '2';
static const anypayToken = secrets.anypayToken;
static String chainByScheme(String scheme) { static String chainByScheme(String scheme) {
switch (scheme.toLowerCase()) { switch (scheme.toLowerCase()) {
@ -44,7 +46,9 @@ class AnyPayApi {
final headers = <String, String>{ final headers = <String, String>{
'Content-Type': contentTypePaymentRequest, 'Content-Type': contentTypePaymentRequest,
'X-Paypro-Version': xPayproVersion, 'X-Paypro-Version': xPayproVersion,
'Accept': '*/*',}; 'Accept': '*/*',
'x-wallet': 'cake',
'x-wallet-token': anypayToken,};
final body = <String, dynamic>{ final body = <String, dynamic>{
'chain': chainByScheme(scheme), 'chain': chainByScheme(scheme),
'currency': currencyByScheme(scheme).title}; 'currency': currencyByScheme(scheme).title};
@ -66,7 +70,9 @@ class AnyPayApi {
final headers = <String, String>{ final headers = <String, String>{
'Content-Type': contentTypePayment, 'Content-Type': contentTypePayment,
'X-Paypro-Version': xPayproVersion, 'X-Paypro-Version': xPayproVersion,
'Accept': '*/*',}; 'Accept': '*/*',
'x-wallet': 'cake',
'x-wallet-token': anypayToken,};
final body = <String, dynamic>{ final body = <String, dynamic>{
'chain': chain, 'chain': chain,
'currency': currency, 'currency': currency,

View file

@ -140,4 +140,20 @@ class CWBitcoin extends Bitcoin {
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) { WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
return LitecoinWalletService(walletInfoSource, unspentCoinSource); return LitecoinWalletService(walletInfoSource, unspentCoinSource);
} }
@override
TransactionPriority getBitcoinTransactionPriorityMedium()
=> BitcoinTransactionPriority.medium;
@override
TransactionPriority getLitecoinTransactionPriorityMedium()
=> LitecoinTransactionPriority.medium;
@override
TransactionPriority getBitcoinTransactionPrioritySlow()
=> BitcoinTransactionPriority.slow;
@override
TransactionPriority getLitecoinTransactionPrioritySlow()
=> LitecoinTransactionPriority.slow;
} }

View file

@ -30,10 +30,10 @@ class Order extends HiveObject {
static const boxName = 'Orders'; static const boxName = 'Orders';
static const boxKey = 'ordersBoxKey'; static const boxKey = 'ordersBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: '')
String transferId; String transferId;
@HiveField(2) @HiveField(2)
@ -42,7 +42,7 @@ class Order extends HiveObject {
@HiveField(3) @HiveField(3)
String? to; String? to;
@HiveField(4) @HiveField(4, defaultValue: '')
late String stateRaw; late String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw); TradeState get state => TradeState.deserialize(raw: stateRaw);
@ -50,16 +50,16 @@ class Order extends HiveObject {
@HiveField(5) @HiveField(5)
DateTime createdAt; DateTime createdAt;
@HiveField(6) @HiveField(6, defaultValue: '')
String amount; String amount;
@HiveField(7) @HiveField(7, defaultValue: '')
String receiveAddress; String receiveAddress;
@HiveField(8) @HiveField(8, defaultValue: '')
String walletId; String walletId;
@HiveField(9) @HiveField(9, defaultValue: 0)
late int providerRaw; late int providerRaw;
BuyProviderDescription get provider => BuyProviderDescription get provider =>

View file

@ -701,6 +701,7 @@ Future setup(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(), ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount, amount: amount,
ioniaMerchant: merchant, ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>()
); );
}); });

View file

@ -17,13 +17,13 @@ class Contact extends HiveObject with Keyable {
static const typeId = 0; static const typeId = 0;
static const boxName = 'Contacts'; static const boxName = 'Contacts';
@HiveField(0) @HiveField(0, defaultValue: '')
String name; String name;
@HiveField(1) @HiveField(1, defaultValue: '')
String address; String address;
@HiveField(2) @HiveField(2, defaultValue: 0)
late int raw; late int raw;
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw); CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);

View file

@ -12,6 +12,7 @@ class PreferencesKey {
static const shouldDisableFiatKey = 'disable_fiat'; static const shouldDisableFiatKey = 'disable_fiat';
static const allowBiometricalAuthenticationKey = static const allowBiometricalAuthenticationKey =
'allow_biometrical_authentication'; 'allow_biometrical_authentication';
static const disableExchangeKey = 'disable_exchange';
static const currentTheme = 'current_theme'; static const currentTheme = 'current_theme';
static const isDarkThemeLegacy = 'dark_theme'; static const isDarkThemeLegacy = 'dark_theme';
static const displayActionListModeKey = 'display_list_mode'; static const displayActionListModeKey = 'display_list_mode';

View file

@ -10,7 +10,7 @@ class TransactionDescription extends HiveObject {
static const boxName = 'TransactionDescriptions'; static const boxName = 'TransactionDescriptions';
static const boxKey = 'transactionDescriptionsBoxKey'; static const boxKey = 'transactionDescriptionsBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1)

View file

@ -232,7 +232,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromAmount = double.parse(responseJSON['fromAmount'].toString()); final fromAmount = double.parse(responseJSON['fromAmount'].toString());
final toAmount = double.parse(responseJSON['toAmount'].toString()); final toAmount = double.parse(responseJSON['toAmount'].toString());
final rateId = responseJSON['rateId'] as String ?? ''; final rateId = responseJSON['rateId'] as String? ?? '';
if (rateId.isNotEmpty) { if (rateId.isNotEmpty) {
_lastUsedRateId = rateId; _lastUsedRateId = rateId;

View file

@ -40,26 +40,26 @@ class Trade extends HiveObject {
static const boxName = 'Trades'; static const boxName = 'Trades';
static const boxKey = 'tradesBoxKey'; static const boxKey = 'tradesBoxKey';
@HiveField(0) @HiveField(0, defaultValue: '')
String id; String id;
@HiveField(1) @HiveField(1, defaultValue: 0)
late int providerRaw; late int providerRaw;
ExchangeProviderDescription get provider => ExchangeProviderDescription get provider =>
ExchangeProviderDescription.deserialize(raw: providerRaw); ExchangeProviderDescription.deserialize(raw: providerRaw);
@HiveField(2) @HiveField(2, defaultValue: 0)
late int fromRaw; late int fromRaw;
CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw); CryptoCurrency get from => CryptoCurrency.deserialize(raw: fromRaw);
@HiveField(3) @HiveField(3, defaultValue: 0)
late int toRaw; late int toRaw;
CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw); CryptoCurrency get to => CryptoCurrency.deserialize(raw: toRaw);
@HiveField(4) @HiveField(4, defaultValue: '')
late String stateRaw; late String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw); TradeState get state => TradeState.deserialize(raw: stateRaw);
@ -70,7 +70,7 @@ class Trade extends HiveObject {
@HiveField(6) @HiveField(6)
DateTime? expiredAt; DateTime? expiredAt;
@HiveField(7) @HiveField(7, defaultValue: '')
String amount; String amount;
@HiveField(8) @HiveField(8)

View file

@ -36,8 +36,8 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
@ -50,13 +50,11 @@ class IoniaApi {
// Verify email // Verify email
Future<IoniaUserCredentials> verifyEmail({ Future<IoniaUserCredentials> verifyEmail({
required String username,
required String email, required String email,
required String code, required String code,
required String clientId}) async { required String clientId}) async {
final headers = <String, String>{ final headers = <String, String>{
'clientId': clientId, 'clientId': clientId,
'username': username,
'EmailAddress': email}; 'EmailAddress': email};
final query = <String, String>{'verificationCode': code}; final query = <String, String>{'verificationCode': code};
final uri = verifyEmailUri.replace(queryParameters: query); final uri = verifyEmailUri.replace(queryParameters: query);
@ -66,8 +64,8 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
@ -75,13 +73,13 @@ class IoniaApi {
} }
final password = data['password'] as String; final password = data['password'] as String;
username = data['username'] as String; final username = data['username'] as String;
return IoniaUserCredentials(username, password); return IoniaUserCredentials(username, password);
} }
// Sign In // Sign In
Future<String> signIn(String email, {required String clientId}) async { Future<void> signIn(String email, {required String clientId}) async {
final headers = <String, String>{'clientId': clientId}; final headers = <String, String>{'clientId': clientId};
final query = <String, String>{'emailAddress': email}; final query = <String, String>{'emailAddress': email};
final uri = signInUri.replace(queryParameters: query); final uri = signInUri.replace(queryParameters: query);
@ -91,15 +89,13 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
throw Exception(data['ErrorMessage'] as String); throw Exception(data['ErrorMessage'] as String);
} }
return data['username'] as String;
} }
// Get virtual card // Get virtual card
@ -118,15 +114,15 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool; final isSuccessful = bodyJson['Successful'] as bool;
if (!isSuccessful) { if (!isSuccessful) {
throw Exception(data['message'] as String); throw Exception(data['message'] as String);
} }
final virtualCard = data['VirtualCard'] as Map<String, Object>; final virtualCard = data['VirtualCard'] as Map<String, dynamic>;
return IoniaVirtualCard.fromMap(virtualCard); return IoniaVirtualCard.fromMap(virtualCard);
} }
@ -146,8 +142,8 @@ class IoniaApi {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, Object>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
final data = bodyJson['Data'] as Map<String, Object>; final data = bodyJson['Data'] as Map<String, dynamic>;
final isSuccessful = bodyJson['Successful'] as bool? ?? false; final isSuccessful = bodyJson['Successful'] as bool? ?? false;
if (!isSuccessful) { if (!isSuccessful) {

View file

@ -31,9 +31,8 @@ class IoniaService {
// Verify email // Verify email
Future<void> verifyEmail(String code) async { Future<void> verifyEmail(String code) async {
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
final email = (await secureStorage.read(key: ioniaEmailStorageKey))!; final email = (await secureStorage.read(key: ioniaEmailStorageKey))!;
final credentials = await ioniaApi.verifyEmail(email: email, username: username, code: code, clientId: clientId); final credentials = await ioniaApi.verifyEmail(email: email, code: code, clientId: clientId);
await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password); await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password);
await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username); await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username);
} }
@ -41,9 +40,8 @@ class IoniaService {
// Sign In // Sign In
Future<void> signIn(String email) async { Future<void> signIn(String email) async {
final username = await ioniaApi.signIn(email, clientId: clientId); await ioniaApi.signIn(email, clientId: clientId);
await secureStorage.write(key: ioniaEmailStorageKey, value: email); await secureStorage.write(key: ioniaEmailStorageKey, value: email);
await secureStorage.write(key: ioniaUsernameStorageKey, value: username);
} }
Future<String> getUserEmail() async { Future<String> getUserEmail() async {

View file

@ -11,7 +11,7 @@ class IoniaVirtualCard {
required this.fundsLimit, required this.fundsLimit,
required this.spendLimit}); required this.spendLimit});
factory IoniaVirtualCard.fromMap(Map<String, Object> source) { factory IoniaVirtualCard.fromMap(Map<String, dynamic> source) {
final created = source['created'] as String; final created = source['created'] as String;
final createdAt = DateTime.tryParse(created); final createdAt = DateTime.tryParse(created);

View file

@ -170,6 +170,14 @@ class CWMonero extends Monero {
return MoneroTransactionPriority.automatic; return MoneroTransactionPriority.automatic;
} }
@override
TransactionPriority getMoneroTransactionPrioritySlow()
=> MoneroTransactionPriority.slow;
@override
TransactionPriority getMoneroTransactionPriorityAutomatic()
=> MoneroTransactionPriority.automatic;
@override @override
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) { TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
return MoneroTransactionPriority.deserialize(raw: raw); return MoneroTransactionPriority.deserialize(raw: raw);

View file

@ -106,22 +106,22 @@ class AuthPageState extends State<AuthPage> {
_progressBar = null; _progressBar = null;
} }
Future<void> close({String? route}) async { Future<void> close({String? route, dynamic arguments}) async {
if (_key.currentContext == null) { if (_key.currentContext == null) {
throw Exception('Key context is null. Should be not happened'); throw Exception('Key context is null. Should be not happened');
} }
WidgetsBinding.instance.addPostFrameCallback((_) { /// not the best scenario, but WidgetsBinding is not behaving correctly on Android
dismissFlushBar(_authBar); await Future<void>.delayed(Duration(milliseconds: 50));
dismissFlushBar(_progressBar); await _authBar?.dismiss();
WidgetsBinding.instance.addPostFrameCallback((_) { await Future<void>.delayed(Duration(milliseconds: 50));
if (route != null) { await _progressBar?.dismiss();
Navigator.of(_key.currentContext!).pushReplacementNamed(route); await Future<void>.delayed(Duration(milliseconds: 50));
} else { if (route != null) {
Navigator.of(_key.currentContext!).pop(); Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments);
} } else {
}); Navigator.of(_key.currentContext!).pop();
}); }
} }
@override @override

View file

@ -315,6 +315,8 @@ class DashboardPage extends BasePage {
} }
Future<void> _onClickExchangeButton(BuildContext context) async { Future<void> _onClickExchangeButton(BuildContext context) async {
await Navigator.of(context).pushNamed(Routes.exchange); if (walletViewModel.isEnabledExchangeAction) {
await Navigator.of(context).pushNamed(Routes.exchange);
}
} }
} }

View file

@ -3,7 +3,6 @@ import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/confirm_modal.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart';
import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
@ -18,6 +17,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
class IoniaBuyGiftCardDetailPage extends BasePage { class IoniaBuyGiftCardDetailPage extends BasePage {
IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel); IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel);
@ -295,73 +295,35 @@ class IoniaBuyGiftCardDetailPage extends BasePage {
final amount = ioniaPurchaseViewModel.invoice!.totalAmount; final amount = ioniaPurchaseViewModel.invoice!.totalAmount;
final addresses = ioniaPurchaseViewModel.invoice!.outAddresses; final addresses = ioniaPurchaseViewModel.invoice!.outAddresses;
ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount);
ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first;
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) { builder: (_) {
return IoniaConfirmModal( return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending, alertTitle: S.of(context).confirm_sending,
alertContent: Container( paymentId: S.of(context).payment_id,
height: 200, paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId,
padding: EdgeInsets.all(15), amount: S.of(context).send_amount,
child: Column(children: [ amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}',
Row(children: [ fiatAmountValue:
Text(S.of(context).payment_id, '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} '
textAlign: TextAlign.center, '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
style: TextStyle( fee: S.of(context).send_fee,
fontSize: 16, feeValue:
fontWeight: FontWeight.w400, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} '
color: PaletteDark.pigeonBlue, '${ioniaPurchaseViewModel.invoice!.chain}',
decoration: TextDecoration.none)), feeFiatAmount:
Text(ioniaPurchaseViewModel.invoice!.paymentId, '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} '
style: TextStyle( '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
fontSize: 16, outputs: ioniaPurchaseViewModel.sendViewModel.outputs,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.spaceBetween),
SizedBox(height: 10),
Row(children: [
Text(S.of(context).amount,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none)),
Text('$amount ${ioniaPurchaseViewModel.invoice!.chain}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.spaceBetween),
SizedBox(height: 25),
Row(children: [
Text(S.of(context).recipient_address,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none))
], mainAxisAlignment: MainAxisAlignment.center),
Expanded(
child: ListView.builder(
itemBuilder: (_, int index) {
return Text(addresses[index],
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none));
},
itemCount: addresses.length,
physics: NeverScrollableScrollPhysics()))
])),
rightButtonText: S.of(context).ok, rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel, leftButtonText: S.of(context).cancel,
leftActionColor: Color(0xffFF6600), alertLeftActionButtonTextColor: Colors.white,
rightActionColor: Theme.of(context).accentTextTheme!.bodyText1!.color!, alertRightActionButtonTextColor: Colors.white,
alertLeftActionButtonColor: Palette.brightOrange,
alertRightActionButtonColor: Theme.of(context).textTheme!.subtitle2!.color,
actionRightButton: () async { actionRightButton: () async {
Navigator.of(context).pop(); Navigator.of(context).pop();
await ioniaPurchaseViewModel.commitPaymentInvoice(); await ioniaPurchaseViewModel.commitPaymentInvoice();

View file

@ -1,149 +0,0 @@
import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class IoniaConfirmModal extends StatelessWidget {
IoniaConfirmModal({
required this.alertTitle,
required this.alertContent,
required this.leftButtonText,
required this.rightButtonText,
required this.actionLeftButton,
required this.actionRightButton,
required this.leftActionColor,
required this.rightActionColor,
this.hideActions = false,
});
final String alertTitle;
final Widget alertContent;
final String leftButtonText;
final String rightButtonText;
final VoidCallback actionLeftButton;
final VoidCallback actionRightButton;
final Color leftActionColor;
final Color rightActionColor;
final bool hideActions;
Widget actionButtons(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IoniaActionButton(
buttonText: leftButtonText,
action: actionLeftButton,
backgoundColor: leftActionColor,
),
Container(
width: 1,
height: 52,
color: Theme.of(context).dividerColor,
),
IoniaActionButton(
buttonText: rightButtonText,
action: actionRightButton,
backgoundColor: rightActionColor,
),
],
);
}
Widget title(BuildContext context) {
return Text(
alertTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
decoration: TextDecoration.none,
),
);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
child: Container(
decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
child: Center(
child: GestureDetector(
onTap: () => null,
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
width: 327,
color: Theme.of(context).accentTextTheme!.headline6!.decorationColor!,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: EdgeInsets.fromLTRB(24, 20, 24, 0),
child: title(context),
),
Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Container(
height: 1,
color: Theme.of(context).dividerColor,
),
),
alertContent,
actionButtons(context),
],
),
),
),
),
),
),
),
);
}
}
class IoniaActionButton extends StatelessWidget {
const IoniaActionButton({
required this.buttonText,
required this.action,
required this.backgoundColor,
});
final String buttonText;
final VoidCallback action;
final Color backgoundColor;
@override
Widget build(BuildContext context) {
return Flexible(
child: Container(
height: 52,
padding: EdgeInsets.only(left: 6, right: 6),
color: backgoundColor,
child: ButtonTheme(
minWidth: double.infinity,
child: TextButton(
onPressed: action,
// FIX-ME: ignored highlightColor and splashColor
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
child: Text(
buttonText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: backgoundColor != null ? Colors.white : Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
));
}
}

View file

@ -9,7 +9,6 @@ class QrPainter extends CustomPainter {
this.errorCorrectionLevel, this.errorCorrectionLevel,
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) { ) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
_p.color = this.color; _p.color = this.color;
_qr.addData(data);
_qrImage = QrImage(_qr); _qrImage = QrImage(_qr);
} }

View file

@ -4,10 +4,13 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:flutter/scheduler.dart';
class ConfirmSendingAlert extends BaseAlertDialog { class ConfirmSendingAlert extends BaseAlertDialog {
ConfirmSendingAlert({ ConfirmSendingAlert({
required this.alertTitle, required this.alertTitle,
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -19,9 +22,15 @@ class ConfirmSendingAlert extends BaseAlertDialog {
required this.rightButtonText, required this.rightButtonText,
required this.actionLeftButton, required this.actionLeftButton,
required this.actionRightButton, required this.actionRightButton,
this.alertBarrierDismissible = true}); this.alertBarrierDismissible = true,
this.alertLeftActionButtonTextColor,
this.alertRightActionButtonTextColor,
this.alertLeftActionButtonColor,
this.alertRightActionButtonColor});
final String alertTitle; final String alertTitle;
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -34,6 +43,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
final VoidCallback actionLeftButton; final VoidCallback actionLeftButton;
final VoidCallback actionRightButton; final VoidCallback actionRightButton;
final bool alertBarrierDismissible; final bool alertBarrierDismissible;
final Color? alertLeftActionButtonTextColor;
final Color? alertRightActionButtonTextColor;
final Color? alertLeftActionButtonColor;
final Color? alertRightActionButtonColor;
@override @override
String get titleText => alertTitle; String get titleText => alertTitle;
@ -56,8 +69,22 @@ class ConfirmSendingAlert extends BaseAlertDialog {
@override @override
bool get barrierDismissible => alertBarrierDismissible; bool get barrierDismissible => alertBarrierDismissible;
@override
Color? get leftActionButtonTextColor => alertLeftActionButtonTextColor;
@override
Color? get rightActionButtonTextColor => alertRightActionButtonTextColor;
@override
Color? get leftActionButtonColor => alertLeftActionButtonColor;
@override
Color? get rightActionButtonColor => alertRightActionButtonColor;
@override @override
Widget content(BuildContext context) => ConfirmSendingAlertContent( Widget content(BuildContext context) => ConfirmSendingAlertContent(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -70,6 +97,8 @@ class ConfirmSendingAlert extends BaseAlertDialog {
class ConfirmSendingAlertContent extends StatefulWidget { class ConfirmSendingAlertContent extends StatefulWidget {
ConfirmSendingAlertContent({ ConfirmSendingAlertContent({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -78,6 +107,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
required this.feeFiatAmount, required this.feeFiatAmount,
required this.outputs}); required this.outputs});
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -88,6 +119,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
@override @override
ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState( ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount, amount: amount,
amountValue: amountValue, amountValue: amountValue,
fiatAmountValue: fiatAmountValue, fiatAmountValue: fiatAmountValue,
@ -100,6 +133,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> { class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> {
ConfirmSendingAlertContentState({ ConfirmSendingAlertContentState({
this.paymentId,
this.paymentIdValue,
required this.amount, required this.amount,
required this.amountValue, required this.amountValue,
required this.fiatAmountValue, required this.fiatAmountValue,
@ -115,6 +150,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
: S.current.recipient_address; : S.current.recipient_address;
} }
final String? paymentId;
final String? paymentIdValue;
final String amount; final String amount;
final String amountValue; final String amountValue;
final String fiatAmountValue; final String fiatAmountValue;
@ -129,6 +166,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
double fromTop = 0; double fromTop = 0;
String recipientTitle; String recipientTitle;
int itemCount; int itemCount;
bool showScrollbar = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -140,6 +178,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
setState(() {}); setState(() {});
}); });
SchedulerBinding.instance.addPostFrameCallback((_) {
setState(() {
showScrollbar = controller.position.maxScrollExtent > 0;
});
});
return Stack( return Stack(
alignment: Alignment.center, alignment: Alignment.center,
clipBehavior: Clip.none, clipBehavior: Clip.none,
@ -150,6 +194,44 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
controller: controller, controller: controller,
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
if (paymentIdValue != null && paymentId != null)
Padding(
padding: EdgeInsets.only(bottom: 32),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
paymentId!,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme!
.headline6!.color!,
decoration: TextDecoration.none,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
paymentIdValue!,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme!
.headline6!.color!,
decoration: TextDecoration.none,
),
),
],
)
],
),
),
Row( Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -365,7 +447,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
) )
) )
), ),
if (itemCount > 1) CakeScrollbar( if (showScrollbar) CakeScrollbar(
backgroundHeight: backgroundHeight, backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight, thumbHeight: thumbHeight,
fromTop: fromTop, fromTop: fromTop,

View file

@ -11,6 +11,10 @@ class BaseAlertDialog extends StatelessWidget {
VoidCallback get actionLeft => () {}; VoidCallback get actionLeft => () {};
VoidCallback get actionRight => () {}; VoidCallback get actionRight => () {};
bool get barrierDismissible => true; bool get barrierDismissible => true;
Color? get leftActionButtonTextColor => null;
Color? get rightActionButtonTextColor => null;
Color? get leftActionButtonColor => null;
Color? get rightActionButtonColor => null;
Widget title(BuildContext context) { Widget title(BuildContext context) {
return Text( return Text(
@ -45,52 +49,64 @@ class BaseAlertDialog extends StatelessWidget {
height: 52, height: 52,
child: Row( child: Row(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionLeft,
color: Theme.of(context).accentTextTheme!.bodyText1!.decorationColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: leftActionButtonColor ??
onPressed: actionLeft, Theme.of(context)
child: Text( .accentTextTheme!
leftActionButtonText, .bodyText1!
textAlign: TextAlign.center, .decorationColor!,
style: TextStyle( shape: const RoundedRectangleBorder(
fontSize: 15, borderRadius: BorderRadius.all(Radius.zero))),
fontFamily: 'Lato', child: Text(
fontWeight: FontWeight.w600, leftActionButtonText,
color: Theme.of(context).primaryTextTheme!.bodyText1!.backgroundColor!, textAlign: TextAlign.center,
decoration: TextDecoration.none, style: TextStyle(
), fontSize: 15,
)), fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
), color: leftActionButtonTextColor ??
Theme.of(context).primaryTextTheme!
.bodyText1!.backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
Container( Container(
width: 1, width: 1,
color: Theme.of(context).dividerColor, color: Theme.of(context).dividerColor,
), ),
Flexible( Expanded(
child: Container( child: TextButton(
width: double.infinity, onPressed: actionRight,
color: Theme.of(context).accentTextTheme!.bodyText2!.backgroundColor!, style: TextButton.styleFrom(
child: TextButton( backgroundColor: rightActionButtonColor ??
onPressed: actionRight, Theme.of(context).accentTextTheme!
child: Text( .bodyText2!.backgroundColor!,
rightActionButtonText, shape: const RoundedRectangleBorder(
textAlign: TextAlign.center, borderRadius: BorderRadius.all(Radius.zero))),
style: TextStyle( child: Text(
fontSize: 15, rightActionButtonText,
fontFamily: 'Lato', textAlign: TextAlign.center,
fontWeight: FontWeight.w600, style: TextStyle(
color: Theme.of(context).primaryTextTheme!.bodyText2!.backgroundColor!, fontSize: 15,
decoration: TextDecoration.none, fontFamily: 'Lato',
), fontWeight: FontWeight.w600,
)), color: rightActionButtonTextColor ??
), Theme.of(context)
), .primaryTextTheme!
], .bodyText2!
)); .backgroundColor!,
decoration: TextDecoration.none,
),
)),
),
],
));
} }
@override @override

View file

@ -31,6 +31,7 @@ abstract class SettingsStoreBase with Store {
required bool initialSaveRecipientAddress, required bool initialSaveRecipientAddress,
required bool initialDisableFiat, required bool initialDisableFiat,
required bool initialAllowBiometricalAuthentication, required bool initialAllowBiometricalAuthentication,
required bool initialExchangeEnabled,
required ThemeBase initialTheme, required ThemeBase initialTheme,
required int initialPinLength, required int initialPinLength,
required String initialLanguageCode, required String initialLanguageCode,
@ -49,6 +50,7 @@ abstract class SettingsStoreBase with Store {
shouldSaveRecipientAddress = initialSaveRecipientAddress, shouldSaveRecipientAddress = initialSaveRecipientAddress,
shouldDisableFiat = initialDisableFiat, shouldDisableFiat = initialDisableFiat,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication, allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
disableExchange = initialExchangeEnabled,
currentTheme = initialTheme, currentTheme = initialTheme,
pinCodeLength = initialPinLength, pinCodeLength = initialPinLength,
languageCode = initialLanguageCode, languageCode = initialLanguageCode,
@ -154,6 +156,9 @@ abstract class SettingsStoreBase with Store {
@observable @observable
bool allowBiometricalAuthentication; bool allowBiometricalAuthentication;
@observable
bool disableExchange;
@observable @observable
ThemeBase currentTheme; ThemeBase currentTheme;
@ -234,6 +239,8 @@ abstract class SettingsStoreBase with Store {
final allowBiometricalAuthentication = sharedPreferences final allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
false; false;
final disableExchange = sharedPreferences
.getBool(PreferencesKey.disableExchangeKey) ?? false;
final legacyTheme = final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index ? ThemeType.dark.index
@ -298,6 +305,7 @@ abstract class SettingsStoreBase with Store {
initialSaveRecipientAddress: shouldSaveRecipientAddress, initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialDisableFiat: shouldDisableFiat, initialDisableFiat: shouldDisableFiat,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialExchangeEnabled: disableExchange,
initialTheme: savedTheme, initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode, actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength, initialPinLength: pinLength,

View file

@ -45,7 +45,6 @@ Future<DateTime?> _buildCupertinoDataPicker(
initialDateTime: initialDate, initialDateTime: initialDate,
minimumDate: firstDate, minimumDate: firstDate,
maximumDate: lastDate, maximumDate: lastDate,
backgroundColor: Colors.white,
), ),
); );
} }

View file

@ -53,7 +53,6 @@ abstract class DashboardViewModelBase with Store {
hasBuyAction = false, hasBuyAction = false,
isEnabledBuyAction = false, isEnabledBuyAction = false,
hasExchangeAction = false, hasExchangeAction = false,
isEnabledExchangeAction = false,
isShowFirstYatIntroduction = false, isShowFirstYatIntroduction = false,
isShowSecondYatIntroduction = false, isShowSecondYatIntroduction = false,
isShowThirdYatIntroduction = false, isShowThirdYatIntroduction = false,
@ -249,8 +248,8 @@ abstract class DashboardViewModelBase with Store {
void furtherShowYatPopup(bool shouldShow) => void furtherShowYatPopup(bool shouldShow) =>
settingsStore.shouldShowYatPopup = shouldShow; settingsStore.shouldShowYatPopup = shouldShow;
@observable @computed
bool isEnabledExchangeAction; bool get isEnabledExchangeAction => !settingsStore.disableExchange;
@observable @observable
bool hasExchangeAction; bool hasExchangeAction;
@ -365,7 +364,6 @@ abstract class DashboardViewModelBase with Store {
} }
void updateActions() { void updateActions() {
isEnabledExchangeAction = true;
hasExchangeAction = !isHaven; hasExchangeAction = !isHaven;
isEnabledBuyAction = wallet.type != WalletType.haven isEnabledBuyAction = wallet.type != WalletType.haven
&& wallet.type != WalletType.monero; && wallet.type != WalletType.monero;

View file

@ -7,15 +7,13 @@ import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart'
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart'; import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_core/monero_transaction_priority.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart'; import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/trade.dart';
@ -200,11 +198,11 @@ abstract class ExchangeViewModelBase with Store {
switch (wallet.type) { switch (wallet.type) {
case WalletType.monero: case WalletType.monero:
case WalletType.haven: case WalletType.haven:
return _settingsViewModel.transactionPriority == MoneroTransactionPriority.slow; return _settingsViewModel.transactionPriority == monero!.getMoneroTransactionPrioritySlow();
case WalletType.bitcoin: case WalletType.bitcoin:
return _settingsViewModel.transactionPriority == BitcoinTransactionPriority.slow; return _settingsViewModel.transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
case WalletType.litecoin: case WalletType.litecoin:
return _settingsViewModel.transactionPriority == LitecoinTransactionPriority.slow; return _settingsViewModel.transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
default: default:
return false; return false;
} }
@ -376,96 +374,105 @@ abstract class ExchangeViewModelBase with Store {
TradeRequest? request; TradeRequest? request;
String amount = ''; String amount = '';
for (var provider in _sortedAvailableProviders.values) { try {
if (!(await provider.checkIsAvailable())) { for (var provider in _sortedAvailableProviders.values) {
continue; if (!(await provider.checkIsAvailable())) {
} continue;
}
if (provider is SideShiftExchangeProvider) { if (provider is SideShiftExchangeProvider) {
request = SideShiftRequest( request = SideShiftRequest(
depositMethod: depositCurrency, depositMethod: depositCurrency,
settleMethod: receiveCurrency, settleMethod: receiveCurrency,
depositAmount: depositAmount.replaceAll(',', '.'), depositAmount: depositAmount.replaceAll(',', '.'),
settleAddress: receiveAddress, settleAddress: receiveAddress,
refundAddress: depositAddress, refundAddress: depositAddress,
); );
amount = depositAmount; amount = depositAmount;
} }
if (provider is SimpleSwapExchangeProvider) { if (provider is SimpleSwapExchangeProvider) {
request = SimpleSwapRequest( request = SimpleSwapRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
address: receiveAddress,
refundAddress: depositAddress,
);
amount = depositAmount;
}
if (provider is XMRTOExchangeProvider) {
request = XMRTOTradeRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'), amount: depositAmount.replaceAll(',', '.'),
receiveAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress, address: receiveAddress,
refundAddress: depositAddress, refundAddress: depositAddress,
isBTCRequest: isReceiveAmountEntered); );
amount = depositAmount; amount = depositAmount;
} }
if (provider is ChangeNowExchangeProvider) { if (provider is XMRTOExchangeProvider) {
request = ChangeNowRequest( request = XMRTOTradeRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
fromAmount: depositAmount.replaceAll(',', '.'), amount: depositAmount.replaceAll(',', '.'),
toAmount: receiveAmount.replaceAll(',', '.'), receiveAmount: receiveAmount.replaceAll(',', '.'),
refundAddress: depositAddress, address: receiveAddress,
address: receiveAddress, refundAddress: depositAddress,
isReverse: isReverse); isBTCRequest: isReceiveAmountEntered);
amount = isReverse ? receiveAmount : depositAmount; amount = depositAmount;
} }
if (provider is MorphTokenExchangeProvider) { if (provider is ChangeNowExchangeProvider) {
request = MorphTokenRequest( request = ChangeNowRequest(
from: depositCurrency, from: depositCurrency,
to: receiveCurrency, to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'), fromAmount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress, toAmount: receiveAmount.replaceAll(',', '.'),
address: receiveAddress); refundAddress: depositAddress,
amount = depositAmount; address: receiveAddress,
} isReverse: isReverse);
amount = isReverse ? receiveAmount : depositAmount;
}
amount = amount.replaceAll(',', '.'); if (provider is MorphTokenExchangeProvider) {
request = MorphTokenRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount.replaceAll(',', '.'),
refundAddress: depositAddress,
address: receiveAddress);
amount = depositAmount;
}
if (limitsState is LimitsLoadedSuccessfully) { amount = amount.replaceAll(',', '.');
if (double.parse(amount) < limits.min!) {
continue; if (limitsState is LimitsLoadedSuccessfully) {
} else if (limits.max != null && double.parse(amount) > limits.max!) { if (double.parse(amount) < limits.min!) {
continue;
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(
request: request!, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
/// return after the first successful trade
return;
} catch (e) {
continue; continue;
} else if (limits.max != null && double.parse(amount) > limits.max!) {
continue;
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(
request: request!, isFixedRateMode: isFixedRateMode);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
/// return after the first successful trade
return;
} catch (e) {
continue;
}
} }
} }
} }
}
/// if the code reached here then none of the providers succeeded /// if the code reached here then none of the providers succeeded
tradeState = TradeIsCreatedFailure( tradeState = TradeIsCreatedFailure(
title: S.current.trade_not_created, title: S.current.trade_not_created,
error: S.current.none_of_selected_providers_can_exchange); error: S.current.none_of_selected_providers_can_exchange);
} on ConcurrentModificationError {
/// if create trade happened at the exact same time of the scheduled rate update
/// then delay the create trade a bit and try again
///
/// this is because the limitation of the SplayTreeMap that
/// you can't modify it while iterating through it
Future.delayed(Duration(milliseconds: 500), createTrade);
}
} }
@action @action
@ -637,13 +644,13 @@ abstract class ExchangeViewModelBase with Store {
switch (wallet.type) { switch (wallet.type) {
case WalletType.monero: case WalletType.monero:
case WalletType.haven: case WalletType.haven:
_settingsStore.priority[wallet.type] = MoneroTransactionPriority.automatic; _settingsStore.priority[wallet.type] = monero!.getMoneroTransactionPriorityAutomatic();
break; break;
case WalletType.bitcoin: case WalletType.bitcoin:
_settingsStore.priority[wallet.type] = BitcoinTransactionPriority.medium; _settingsStore.priority[wallet.type] = bitcoin!.getBitcoinTransactionPriorityMedium();
break; break;
case WalletType.litecoin: case WalletType.litecoin:
_settingsStore.priority[wallet.type] = LitecoinTransactionPriority.medium; _settingsStore.priority[wallet.type] = bitcoin!.getLitecoinTransactionPriorityMedium();
break; break;
default: default:
break; break;

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_merchant.dart'; import 'package:cake_wallet/ionia/ionia_merchant.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
import 'package:cake_wallet/view_model/send/send_view_model.dart';
part 'ionia_purchase_merch_view_model.g.dart'; part 'ionia_purchase_merch_view_model.g.dart';
@ -17,6 +18,7 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
required this.ioniaAnyPayService, required this.ioniaAnyPayService,
required this.amount, required this.amount,
required this.ioniaMerchant, required this.ioniaMerchant,
required this.sendViewModel,
}) : tipAmount = 0.0, }) : tipAmount = 0.0,
percentage = 0.0, percentage = 0.0,
invoiceCreationState = InitialExecutionState(), invoiceCreationState = InitialExecutionState(),
@ -40,6 +42,8 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
final IoniaMerchant ioniaMerchant; final IoniaMerchant ioniaMerchant;
final SendViewModel sendViewModel;
final IoniaAnyPay ioniaAnyPayService; final IoniaAnyPay ioniaAnyPayService;
IoniaAnyPayPaymentInfo? paymentInfo; IoniaAnyPayPaymentInfo? paymentInfo;

View file

@ -155,13 +155,13 @@ abstract class SettingsViewModelBase with Store {
handler: (BuildContext context) { handler: (BuildContext context) {
Navigator.of(context).pushNamed(Routes.auth, arguments: Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) { (bool isAuthenticatedSuccessfully, AuthPageState auth) {
auth.close(); auth.close(
if (isAuthenticatedSuccessfully) { route: isAuthenticatedSuccessfully ? Routes.setupPin : null,
Navigator.of(context).pushNamed(Routes.setupPin, arguments: arguments: (PinCodeState<PinCodeWidget> setupPinContext,
(PinCodeState<PinCodeWidget> setupPinContext, String _) { String _) {
setupPinContext.close(); setupPinContext.close();
}); },
} );
}); });
}), }),
PickerListItem( PickerListItem(
@ -212,7 +212,12 @@ abstract class SettingsViewModelBase with Store {
setAllowBiometricalAuthentication(value); setAllowBiometricalAuthentication(value);
} }
}), }),
SwitcherListItem(
title: S.current.disable_exchange,
value: () => _settingsStore.disableExchange,
onValueChange: (BuildContext context, bool value) {
_settingsStore.disableExchange = value;
}),
ChoicesListItem( ChoicesListItem(
title: S.current.color_theme, title: S.current.color_theme,
items: ThemeList.all, items: ThemeList.all,

View file

@ -579,55 +579,55 @@
"add_value": "Wert hinzufügen", "add_value": "Wert hinzufügen",
"activate": "aktivieren", "activate": "aktivieren",
"get_a": "Hole ein", "get_a": "Hole ein",
"digital_and_physical_card": "digitale en fysieke prepaid debetkaart", "digital_and_physical_card": "digitale und physische Prepaid-Debitkarte",
"get_card_note": " die u kunt herladen met digitale valuta. Geen aanvullende informatie nodig!", "get_card_note": " die Sie mit digitaler Währung aufladen können. Keine zusätzlichen Informationen erforderlich!",
"signup_for_card_accept_terms": "Meld je aan voor de kaart en accepteer de voorwaarden.", "signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.",
"add_fund_to_card": "Voeg prepaid tegoed toe aan de kaarten (tot ${value})", "add_fund_to_card": "Prepaid-Guthaben zu den Karten hinzufügen (bis zu ${value})",
"use_card_info_two": "Tegoeden worden omgezet naar USD wanneer ze op de prepaid-rekening staan, niet in digitale valuta.", "use_card_info_two": "Guthaben werden auf dem Prepaid-Konto in USD umgerechnet, nicht in digitale Währung.",
"use_card_info_three": "Gebruik de digitale kaart online of met contactloze betaalmethoden.", "use_card_info_three": "Verwenden Sie die digitale Karte online oder mit kontaktlosen Zahlungsmethoden.",
"optionally_order_card": "Optioneel een fysieke kaart bestellen.", "optionally_order_card": "Optional eine physische Karte bestellen.",
"hide_details" : "Details verbergen", "hide_details": "Details ausblenden",
"show_details" : "Toon details", "show_details": "Details anzeigen",
"upto": "tot ${value}", "upto": "bis zu ${value}",
"discount": "Bespaar ${value}%", "discount": "${value} % sparen",
"gift_card_amount": "Bedrag cadeaubon", "gift_card_amount": "Gutscheinbetrag",
"bill_amount": "Bill bedrag", "bill_amount": "Rechnungsbetrag",
"you_pay": "U betaalt", "you_pay": "Sie bezahlen",
"tip": "Tip:", "tip": "Hinweis:",
"custom": "aangepast", "custom": "benutzerdefiniert",
"by_cake_pay": "door Cake Pay", "by_cake_pay": "von Cake Pay",
"expires": "Verloopt", "expires": "Läuft ab",
"mm": "MM", "mm": "MM",
"yy": "JJ", "yy": "YY",
"online": "online", "online": "online",
"offline": "Offline", "offline": "offline",
"gift_card_number": "Cadeaukaartnummer", "gift_card_number": "Geschenkkartennummer",
"pin_number": "PIN-nummer", "pin_number": "PIN-Nummer",
"total_saving": "Totale besparingen", "total_saving": "Gesamteinsparungen",
"last_30_days": "Laatste 30 dagen", "last_30_days": "Letzte 30 Tage",
"avg_savings": "Gem. besparingen", "avg_savings": "Durchschn. Einsparungen",
"view_all": "Alles bekijken", "view_all": "Alle anzeigen",
"active_cards": "Actieve kaarten", "active_cards": "Aktive Karten",
"delete_account": "Account verwijderen", "delete_account": "Konto löschen",
"cards": "Kaarten", "cards": "Karten",
"active": "Actief", "active": "Aktiv",
"redeemed": "Verzilverd", "redeemed": "Versilbert",
"gift_card_balance_note": "Cadeaukaarten met een resterend saldo verschijnen hier", "gift_card_balance_note": "Geschenkkarten mit Restguthaben erscheinen hier",
"gift_card_redeemed_note": "Cadeaubonnen die je hebt ingewisseld, verschijnen hier", "gift_card_redeemed_note": "Gutscheine, die Sie eingelöst haben, werden hier angezeigt",
"logout": "Uitloggen", "logout": "Abmelden",
"add_tip": "Tip toevoegen", "add_tip": "Tipp hinzufügen",
"percentageOf": "van ${amount}", "percentageOf": "von ${amount}",
"is_percentage": "is", "is_percentage": "ist",
"search_category": "Zoek categorie", "search_category": "Suchkategorie",
"mark_as_redeemed": "Markeer als ingewisseld", "mark_as_redeemed": "Als eingelöst markieren",
"more_options": "Meer opties", "more_options": "Weitere Optionen",
"waiting_payment_confirmation": "In afwachting van betalingsbevestiging", "waiting_payment_confirmation": "Warte auf Zahlungsbestätigung",
"transaction_sent_notice": "Als het scherm na 1 minuut niet verder gaat, controleer dan een blokverkenner en je e-mail.", "transaction_sent_notice": "Wenn der Bildschirm nach 1 Minute nicht weitergeht, überprüfen Sie einen Block-Explorer und Ihre E-Mail.",
"agree": "mee eens", "agree": "stimme zu",
"in_store": "In winkel", "in_store": "Im Geschäft",
"generating_gift_card": "Cadeaubon genereren", "generating_gift_card": "Geschenkkarte wird erstellt",
"payment_was_received": "Uw betaling is ontvangen.", "payment_was_received": "Ihre Zahlung ist eingegangen.",
"proceed_after_one_minute": "Als het scherm na 1 minuut niet verder gaat, controleer dan uw e-mail.", "proceed_after_one_minute": "Wenn der Bildschirm nach 1 Minute nicht weitergeht, überprüfen Sie bitte Ihre E-Mail.",
"order_id": "Bestell-ID", "order_id": "Bestell-ID",
"gift_card_is_generated": "Geschenkkarte wird generiert", "gift_card_is_generated": "Geschenkkarte wird generiert",
"open_gift_card": "Geschenkkarte öffnen", "open_gift_card": "Geschenkkarte öffnen",
@ -652,5 +652,6 @@
"use_suggested": "Vorgeschlagen verwenden", "use_suggested": "Vorgeschlagen verwenden",
"do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!", "do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!",
"help": "hilfe", "help": "hilfe",
"disable_fiat": "Fiat deaktivieren" "disable_fiat": "Fiat deaktivieren",
"disable_exchange": "Exchange deaktivieren"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Use Suggested", "use_suggested": "Use Suggested",
"do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!", "do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!",
"help": "help", "help": "help",
"disable_fiat": "Disable fiat" "disable_fiat": "Disable fiat",
"disable_exchange": "Disable exchange"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Usar sugerido", "use_suggested": "Usar sugerido",
"do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!", "do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!",
"help": "ayuda", "help": "ayuda",
"disable_fiat": "Deshabilitar fiat" "disable_fiat": "Deshabilitar fiat",
"disable_exchange": "Deshabilitar intercambio"
} }

View file

@ -650,5 +650,6 @@
"use_suggested": "Utilisation suggérée", "use_suggested": "Utilisation suggérée",
"do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!", "do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!",
"help": "aider", "help": "aider",
"disable_fiat": "Désactiver fiat" "disable_fiat": "Désactiver fiat",
"disable_exchange": "Désactiver l'échange"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "सुझाए गए का प्रयोग करें", "use_suggested": "सुझाए गए का प्रयोग करें",
"do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!", "do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!",
"help": "मदद करना", "help": "मदद करना",
"disable_fiat": "िएट अक्षम करें" "disable_fiat": "िएट अक्षम करें",
"disable_exchange": "एक्सचेंज अक्षम करें"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Koristite predloženo", "use_suggested": "Koristite predloženo",
"do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!", "do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!",
"help": "pomozite", "help": "pomozite",
"disable_fiat": "Isključi, fiat" "disable_fiat": "Isključi, fiat",
"disable_exchange": "Onemogući exchange"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Usa suggerito", "use_suggested": "Usa suggerito",
"do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!", "do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!",
"help": "aiuto", "help": "aiuto",
"disable_fiat": "Disabilita fiat" "disable_fiat": "Disabilita fiat",
"disable_exchange": "Disabilita scambio"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "推奨を使用", "use_suggested": "推奨を使用",
"do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます", "do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます",
"help": "ヘルプ", "help": "ヘルプ",
"disable_fiat": "フィアットを無効にする" "disable_fiat": "フィアットを無効にする",
"disable_exchange": "交換を無効にする"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "추천 사용", "use_suggested": "추천 사용",
"do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!", "do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!",
"help": "돕다", "help": "돕다",
"disable_fiat": "법정화폐 비활성화" "disable_fiat": "법정화폐 비활성화",
"disable_exchange": "교환 비활성화"
} }

View file

@ -579,55 +579,55 @@
"add_value": "Waarde toevoegen", "add_value": "Waarde toevoegen",
"activate": "Activeren", "activate": "Activeren",
"get_a": "Krijg een ", "get_a": "Krijg een ",
"digital_and_physical_card": "digitale und physische Prepaid-Debitkarte", "digital_and_physical_card": "digitale en fysieke prepaid debetkaart",
"get_card_note": " die Sie mit digitaler Währung aufladen können. Keine zusätzlichen Informationen erforderlich!", "get_card_note": " die u kunt herladen met digitale valuta. Geen aanvullende informatie nodig!",
"signup_for_card_accept_terms": "Melden Sie sich für die Karte an und akzeptieren Sie die Bedingungen.", "signup_for_card_accept_terms": "Meld je aan voor de kaart en accepteer de voorwaarden.",
"add_fund_to_card": "Prepaid-Guthaben zu den Karten hinzufügen (bis zu ${value})", "add_fund_to_card": "Voeg prepaid tegoed toe aan de kaarten (tot ${value})",
"use_card_info_two": "Guthaben werden auf dem Prepaid-Konto in USD umgerechnet, nicht in digitale Währung.", "use_card_info_two": "Tegoeden worden omgezet naar USD wanneer ze op de prepaid-rekening staan, niet in digitale valuta.",
"use_card_info_three": "Verwenden Sie die digitale Karte online oder mit kontaktlosen Zahlungsmethoden.", "use_card_info_three": "Gebruik de digitale kaart online of met contactloze betaalmethoden.",
"optional_order_card": "Optional eine physische Karte bestellen.", "optionally_order_card": "Optioneel een fysieke kaart bestellen.",
"hide_details": "Details ausblenden", "hide_details" : "Details verbergen",
"show_details": "Details anzeigen", "show_details" : "Toon details",
"upto": "bis zu ${value}", "upto": "tot ${value}",
"discount": "${value} % sparen", "discount": "Bespaar ${value}%",
"gift_card_amount": "Gutscheinbetrag", "gift_card_amount": "Bedrag cadeaubon",
"bill_amount": "Rechnungsbetrag", "bill_amount": "Bill bedrag",
"you_pay": "Sie bezahlen", "you_pay": "U betaalt",
"tip": "Hinweis:", "tip": "Tip:",
"custom": "benutzerdefiniert", "custom": "aangepast",
"by_cake_pay": "von Cake Pay", "by_cake_pay": "door Cake Pay",
"expires": "Läuft ab", "expires": "Verloopt",
"mm": "MM", "mm": "MM",
"yy": "YY", "yy": "JJ",
"online": "online", "online": "online",
"offline": "offline", "offline": "Offline",
"gift_card_number": "Geschenkkartennummer", "gift_card_number": "Cadeaukaartnummer",
"pin_number": "PIN-Nummer", "pin_number": "PIN-nummer",
"total_saving": "Gesamteinsparungen", "total_saving": "Totale besparingen",
"last_30_days": "Letzte 30 Tage", "last_30_days": "Laatste 30 dagen",
"avg_savings": "Durchschn. Einsparungen", "avg_savings": "Gem. besparingen",
"view_all": "Alle anzeigen", "view_all": "Alles bekijken",
"active_cards": "Aktive Karten", "active_cards": "Actieve kaarten",
"delete_account": "Konto löschen", "delete_account": "Account verwijderen",
"cards": "Karten", "cards": "Kaarten",
"active": "Aktiv", "active": "Actief",
"redeemed": "Versilbert", "redeemed": "Verzilverd",
"gift_card_balance_note": "Geschenkkarten mit Restguthaben erscheinen hier", "gift_card_balance_note": "Cadeaukaarten met een resterend saldo verschijnen hier",
"gift_card_redeemed_note": "Gutscheine, die Sie eingelöst haben, werden hier angezeigt", "gift_card_redeemed_note": "Cadeaubonnen die je hebt ingewisseld, verschijnen hier",
"abmelden": "Abmelden", "logout": "Uitloggen",
"add_tip": "Tipp hinzufügen", "add_tip": "Tip toevoegen",
"percentageOf": "von ${amount}", "percentageOf": "van ${amount}",
"is_percentage": "ist", "is_percentage": "is",
"search_category": "Suchkategorie", "search_category": "Zoek categorie",
"mark_as_redeemed": "Als eingelöst markieren", "mark_as_redeemed": "Markeer als ingewisseld",
"more_options": "Weitere Optionen", "more_options": "Meer opties",
"waiting_payment_confirmation": "Warte auf Zahlungsbestätigung", "waiting_payment_confirmation": "In afwachting van betalingsbevestiging",
"transaction_sent_notice": "Wenn der Bildschirm nach 1 Minute nicht weitergeht, überprüfen Sie einen Block-Explorer und Ihre E-Mail.", "transaction_sent_notice": "Als het scherm na 1 minuut niet verder gaat, controleer dan een blokverkenner en je e-mail.",
"agree": "stimme zu", "agree": "mee eens",
"in_store": "Im Geschäft", "in_store": "In winkel",
"generating_gift_card": "Geschenkkarte wird erstellt", "generating_gift_card": "Cadeaubon genereren",
"payment_was_received": "Ihre Zahlung ist eingegangen.", "payment_was_received": "Uw betaling is ontvangen.",
"proceed_after_one_minute": "Wenn der Bildschirm nach 1 Minute nicht weitergeht, überprüfen Sie bitte Ihre E-Mail.", "proceed_after_one_minute": "Als het scherm na 1 minuut niet verder gaat, controleer dan uw e-mail.",
"order_id": "Order-ID", "order_id": "Order-ID",
"gift_card_is_generated": "Cadeaukaart is gegenereerd", "gift_card_is_generated": "Cadeaukaart is gegenereerd",
"open_gift_card": "Geschenkkaart openen", "open_gift_card": "Geschenkkaart openen",
@ -652,5 +652,6 @@
"use_suggested": "Gebruik aanbevolen", "use_suggested": "Gebruik aanbevolen",
"do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!", "do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!",
"help": "helpen", "help": "helpen",
"disable_fiat": "법정화폐 비활성화" "disable_fiat": "법정화폐 비활성화",
"disable_exchange": "Uitwisseling uitschakelen"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Użyj sugerowane", "use_suggested": "Użyj sugerowane",
"do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!", "do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!",
"help": "pomoc", "help": "pomoc",
"disable_fiat": "Wyłącz fiat" "disable_fiat": "Wyłącz fiat",
"disable_exchange": "Wyłącz wymianę"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Uso sugerido", "use_suggested": "Uso sugerido",
"do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!", "do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!",
"help": "ajuda", "help": "ajuda",
"disable_fiat": "Desativar fiat" "disable_fiat": "Desativar fiat",
"disable_exchange": "Desativar troca"
} }

View file

@ -652,5 +652,6 @@
"use_suggested": "Использовать предложенный", "use_suggested": "Использовать предложенный",
"do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!", "do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!",
"help": "помощь", "help": "помощь",
"disable_fiat": "Отключить фиат" "disable_fiat": "Отключить фиат",
"disable_exchange": "Отключить обмен"
} }

View file

@ -651,5 +651,6 @@
"use_suggested": "Використати запропоноване", "use_suggested": "Використати запропоноване",
"do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!", "do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!",
"help": "допомога", "help": "допомога",
"disable_fiat": "Вимкнути фиат" "disable_fiat": "Вимкнути фиат",
"disable_exchange": "Вимкнути exchange"
} }

View file

@ -650,5 +650,6 @@
"use_suggested": "使用建议", "use_suggested": "使用建议",
"do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢", "do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢",
"help": "帮助", "help": "帮助",
"disable_fiat": "禁用法令" "disable_fiat": "禁用法令",
"disable_exchange": "禁用交换"
} }

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1 APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.1.2" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=21 MONERO_COM_BUILD_NUMBER=32
MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.4.8" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=122 CAKEWALLET_BUILD_NUMBER=136
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1 APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com" MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.1.2" MONERO_COM_VERSION="1.2.1"
MONERO_COM_BUILD_NUMBER=23 MONERO_COM_BUILD_NUMBER=29
MONERO_COM_BUNDLE_ID="com.cakewallet.monero" MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.4.8" CAKEWALLET_VERSION="4.5.1"
CAKEWALLET_BUILD_NUMBER=121 CAKEWALLET_BUILD_NUMBER=133
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven" HAVEN_NAME="Haven"

View file

@ -92,6 +92,10 @@ abstract class Bitcoin {
void updateUnspents(Object wallet); void updateUnspents(Object wallet);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource); WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource); WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
TransactionPriority getBitcoinTransactionPriorityMedium();
TransactionPriority getLitecoinTransactionPriorityMedium();
TransactionPriority getBitcoinTransactionPrioritySlow();
TransactionPriority getLitecoinTransactionPrioritySlow();
} }
"""; """;
@ -218,6 +222,8 @@ abstract class Monero {
int getHeigthByDate({required DateTime date}); int getHeigthByDate({required DateTime date});
TransactionPriority getDefaultTransactionPriority(); TransactionPriority getDefaultTransactionPriority();
TransactionPriority getMoneroTransactionPrioritySlow();
TransactionPriority getMoneroTransactionPriorityAutomatic();
TransactionPriority deserializeMoneroTransactionPriority({required int raw}); TransactionPriority deserializeMoneroTransactionPriority({required int raw});
List<TransactionPriority> getTransactionPriorities(); List<TransactionPriority> getTransactionPriorities();
List<String> getMoneroWordList(String language); List<String> getMoneroWordList(String language);

View file

@ -26,6 +26,7 @@ class SecretKey {
SecretKey('sideShiftAffiliateId', () => ''), SecretKey('sideShiftAffiliateId', () => ''),
SecretKey('sideShiftApiKey', () => ''), SecretKey('sideShiftApiKey', () => ''),
SecretKey('simpleSwapApiKey', () => ''), SecretKey('simpleSwapApiKey', () => ''),
SecretKey('anypayToken', () => ''),
SecretKey('onramperApiKey', () => ''), SecretKey('onramperApiKey', () => ''),
]; ];