Merge branch 'main' into CW-175-Refactoring-of-crypto-currency-list

This commit is contained in:
Serhii 2022-11-18 23:17:59 +02:00
commit 133a694b07
95 changed files with 1279 additions and 863 deletions

View file

@ -46,7 +46,7 @@ android {
defaultConfig {
applicationId appProperties['id']
minSdkVersion 21
targetSdkVersion 30
targetSdkVersion 31
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
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:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
android:exported="true">
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"

View file

@ -495,7 +495,7 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
hash: coin.hash,
isFrozen: coin.isFrozen,
isSending: coin.isSending,
note: coin.note
noteRaw: coin.note
);
await unspentCoinsInfo.add(newInfo);

View file

@ -9,13 +9,13 @@ class MoneroTransactionPriority extends TransactionPriority {
static const all = [
MoneroTransactionPriority.slow,
MoneroTransactionPriority.regular,
MoneroTransactionPriority.automatic,
MoneroTransactionPriority.medium,
MoneroTransactionPriority.fast,
MoneroTransactionPriority.fastest
];
static const slow = MoneroTransactionPriority(title: 'Slow', raw: 0);
static const regular = MoneroTransactionPriority(title: 'Regular', raw: 1);
static const automatic = MoneroTransactionPriority(title: 'Automatic', raw: 1);
static const medium = MoneroTransactionPriority(title: 'Medium', raw: 2);
static const fast = MoneroTransactionPriority(title: 'Fast', raw: 3);
static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
@ -29,7 +29,7 @@ class MoneroTransactionPriority extends TransactionPriority {
case WalletType.bitcoin:
return [
MoneroTransactionPriority.slow,
MoneroTransactionPriority.regular,
MoneroTransactionPriority.automatic,
MoneroTransactionPriority.fast
];
default:
@ -42,7 +42,7 @@ class MoneroTransactionPriority extends TransactionPriority {
case 0:
return slow;
case 1:
return regular;
return automatic;
case 2:
return medium;
case 3:
@ -59,8 +59,8 @@ class MoneroTransactionPriority extends TransactionPriority {
switch (this) {
case MoneroTransactionPriority.slow:
return 'Slow'; // S.current.transaction_priority_slow;
case MoneroTransactionPriority.regular:
return 'Regular'; // S.current.transaction_priority_regular;
case MoneroTransactionPriority.automatic:
return 'Automatic'; // S.current.transaction_priority_regular;
case MoneroTransactionPriority.medium:
return 'Medium'; // S.current.transaction_priority_medium;
case MoneroTransactionPriority.fast:

View file

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

View file

@ -9,24 +9,28 @@ class UnspentCoinsInfo extends HiveObject {
required this.hash,
required this.isFrozen,
required this.isSending,
required this.note});
required this.noteRaw});
static const typeId = 9;
static const boxName = 'Unspent';
static const boxKey = 'unspentBoxKey';
@HiveField(0)
@HiveField(0, defaultValue: '')
String walletId;
@HiveField(1)
@HiveField(1, defaultValue: '')
String hash;
@HiveField(2)
@HiveField(2, defaultValue: false)
bool isFrozen;
@HiveField(3)
@HiveField(3, defaultValue: false)
bool isSending;
@HiveField(4)
String note;
String? noteRaw;
String get note => noteRaw ?? '';
set note(String value) => noteRaw = value;
}

View file

@ -33,46 +33,46 @@ class WalletInfo extends HiveObject {
static const typeId = 4;
static const boxName = 'WalletInfo';
@HiveField(0)
@HiveField(0, defaultValue: '')
String id;
@HiveField(1)
@HiveField(1, defaultValue: '')
String name;
@HiveField(2)
WalletType type;
@HiveField(3)
@HiveField(3, defaultValue: false)
bool isRecovery;
@HiveField(4)
@HiveField(4, defaultValue: 0)
int restoreHeight;
@HiveField(5)
@HiveField(5, defaultValue: 0)
int timestamp;
@HiveField(6)
@HiveField(6, defaultValue: '')
String dirPath;
@HiveField(7)
@HiveField(7, defaultValue: '')
String path;
@HiveField(8)
@HiveField(8, defaultValue: '')
String address;
@HiveField(10)
Map<String, String>? addresses;
@HiveField(11)
String yatEid;
String? yatEid;
@HiveField(12)
String yatLastUsedAddressRaw;
String? yatLastUsedAddressRaw;
@HiveField(13)
bool? showIntroCakePayCard;
String get yatLastUsedAddress => yatLastUsedAddressRaw;
String get yatLastUsedAddress => yatLastUsedAddressRaw ?? '';
set yatLastUsedAddress(String address) {
yatLastUsedAddressRaw = address;

View file

@ -187,7 +187,9 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
accountIndex: walletAddresses.account!.id);
} else {
final output = outputs.first;
final address = output.address;
final address = output.isParsedAddress && (output.extractedAddress?.isNotEmpty ?? false)
? output.extractedAddress!
: output.address;
final amount = output.sendAll
? null
: output.cryptoAmount!.replaceAll(',', '.');
@ -223,7 +225,7 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
switch (priority) {
case MoneroTransactionPriority.slow:
return 24590000;
case MoneroTransactionPriority.regular:
case MoneroTransactionPriority.automatic:
return 123050000;
case MoneroTransactionPriority.medium:
return 245029999;

View file

@ -2,7 +2,7 @@ import 'package:cw_haven/api/structs/pending_transaction.dart';
import 'package:cw_haven/api/transaction_history.dart'
as haven_transaction_history;
import 'package:cw_core/crypto_currency.dart';
// import 'package:cake_wallet/core/amount_converter.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart';
class DoubleSpendException implements Exception {
@ -25,17 +25,13 @@ class PendingHavenTransaction with PendingTransaction {
@override
String get hex => '';
// FIX-ME: AmountConverter
@override
String get amountFormatted => '';
// AmountConverter.amountIntToString(
// cryptoCurrency, pendingTransactionDescription.amount);
String get amountFormatted => AmountConverter.amountIntToString(
cryptoCurrency, pendingTransactionDescription.amount);
// FIX-ME: AmountConverter
@override
String get feeFormatted => '';
// AmountConverter.amountIntToString(
// cryptoCurrency, pendingTransactionDescription.fee);
String get feeFormatted => AmountConverter.amountIntToString(
cryptoCurrency, pendingTransactionDescription.fee);
@override
Future<void> commit() async {

View file

@ -182,7 +182,7 @@ void commitTransaction({required Pointer<PendingTransactionRaw> transactionPoint
PendingTransactionDescription _createTransactionSync(Map args) {
final address = args['address'] as String;
final paymentId = args['paymentId'] as String;
final amount = args['amount'] as String;
final amount = args['amount'] as String?;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;

View file

@ -242,7 +242,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
switch (priority) {
case MoneroTransactionPriority.slow:
return 24590000;
case MoneroTransactionPriority.regular:
case MoneroTransactionPriority.automatic:
return 123050000;
case MoneroTransactionPriority.medium:
return 245029999;

View file

@ -2,7 +2,7 @@ import 'package:cw_monero/api/structs/pending_transaction.dart';
import 'package:cw_monero/api/transaction_history.dart'
as monero_transaction_history;
import 'package:cw_core/crypto_currency.dart';
// import 'package:cake_wallet/core/amount_converter.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/pending_transaction.dart';
@ -27,17 +27,13 @@ class PendingMoneroTransaction with PendingTransaction {
String get txKey => pendingTransactionDescription.txKey;
// FIX-ME: AmountConverter
@override
String get amountFormatted => '';
// AmountConverter.amountIntToString(
// CryptoCurrency.xmr, pendingTransactionDescription.amount);
String get amountFormatted => AmountConverter.amountIntToString(
CryptoCurrency.xmr, pendingTransactionDescription.amount);
// FIX-ME: AmountConverter
@override
String get feeFormatted => '';
// AmountConverter.amountIntToString(
// CryptoCurrency.xmr, pendingTransactionDescription.fee);
String get feeFormatted => AmountConverter.amountIntToString(
CryptoCurrency.xmr, pendingTransactionDescription.fee);
@override
Future<void> commit() async {

View file

@ -119,7 +119,7 @@ PODS:
- SDWebImage (5.9.1):
- SDWebImage/Core (= 5.9.1)
- SDWebImage/Core (5.9.1)
- share (0.0.1):
- share_plus (0.0.1):
- Flutter
- shared_preferences_ios (0.0.1):
- Flutter
@ -153,7 +153,7 @@ DEPENDENCIES:
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- platform_device_id (from `.symlinks/plugins/platform_device_id/ios`)
- share (from `.symlinks/plugins/share/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- uni_links (from `.symlinks/plugins/uni_links/ios`)
- UnstoppableDomainsResolution (~> 4.0.0)
@ -206,8 +206,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/permission_handler_apple/ios"
platform_device_id:
:path: ".symlinks/plugins/platform_device_id/ios"
share:
:path: ".symlinks/plugins/share/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_ios:
:path: ".symlinks/plugins/shared_preferences_ios/ios"
uni_links:
@ -241,7 +241,7 @@ SPEC CHECKSUMS:
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
SwiftProtobuf: c3c12645230d9b09c72267e0de89468c5543bd86
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
@ -252,4 +252,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f
COCOAPODS: 1.11.2
COCOAPODS: 1.11.3

View file

@ -17,8 +17,8 @@ class AnyPayPaymentInstruction {
return AnyPayPaymentInstruction(
type: obj['type'] as String,
requiredFeeRate: obj['requiredFeeRate'] as int,
txKey: obj['tx_key'] as bool,
txHash: obj['tx_hash'] as bool,
txKey: obj['tx_key'] as bool? ?? false,
txHash: obj['tx_hash'] as bool? ?? false,
outputs: outputs);
}

View file

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

View file

@ -112,6 +112,10 @@ class CWBitcoin extends Bitcoin {
int formatterStringDoubleToBitcoinAmount(String amount)
=> stringDoubleToBitcoinAmount(amount);
@override
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate)
=> (priority as BitcoinTransactionPriority).labelWithRate(rate);
@override
List<Unspent> getUnspents(Object wallet) {
final bitcoinWallet = wallet as ElectrumWallet;
@ -136,4 +140,20 @@ class CWBitcoin extends Bitcoin {
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> 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 boxKey = 'ordersBoxKey';
@HiveField(0)
@HiveField(0, defaultValue: '')
String id;
@HiveField(1)
@HiveField(1, defaultValue: '')
String transferId;
@HiveField(2)
@ -42,7 +42,7 @@ class Order extends HiveObject {
@HiveField(3)
String? to;
@HiveField(4)
@HiveField(4, defaultValue: '')
late String stateRaw;
TradeState get state => TradeState.deserialize(raw: stateRaw);
@ -50,16 +50,16 @@ class Order extends HiveObject {
@HiveField(5)
DateTime createdAt;
@HiveField(6)
@HiveField(6, defaultValue: '')
String amount;
@HiveField(7)
@HiveField(7, defaultValue: '')
String receiveAddress;
@HiveField(8)
@HiveField(8, defaultValue: '')
String walletId;
@HiveField(9)
@HiveField(9, defaultValue: 0)
late int providerRaw;
BuyProviderDescription get provider =>

View file

@ -16,6 +16,7 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cake_backup/backup.dart' as cake_backup;
class BackupService {
BackupService(this._flutterSecureStorage, this._walletInfoSource,
@ -23,9 +24,10 @@ class BackupService {
: _cipher = Cryptography.instance.chacha20Poly1305Aead(),
_correctWallets = <WalletInfo>[];
static const currentVersion = _v1;
static const currentVersion = _v2;
static const _v1 = 1;
static const _v2 = 2;
final Cipher _cipher;
final FlutterSecureStorage _flutterSecureStorage;
@ -37,13 +39,16 @@ class BackupService {
Future<void> importBackup(Uint8List data, String password,
{String nonce = secrets.backupSalt}) async {
final version = getVersion(data);
final backupBytes = data.toList()..removeAt(0);
final backupData = Uint8List.fromList(backupBytes);
switch (version) {
case _v1:
final backupBytes = data.toList()..removeAt(0);
final backupData = Uint8List.fromList(backupBytes);
await _importBackupV1(backupData, password, nonce: nonce);
break;
case _v2:
await _importBackupV2(data, password);
break;
default:
break;
}
@ -54,20 +59,26 @@ class BackupService {
switch (version) {
case _v1:
return await _exportBackupV1(password, nonce: nonce);
case _v2:
return await _exportBackupV2(password);
default:
throw Exception('Incorrect version: $version for exportBackup');
}
}
@Deprecated('Use v2 instead')
Future<Uint8List> _exportBackupV1(String password,
{String nonce = secrets.backupSalt}) async {
{String nonce = secrets.backupSalt}) async
=> throw Exception('Deprecated. Export for backups v1 is deprecated. Please use export v2.');
Future<Uint8List> _exportBackupV2(String password) async {
final zipEncoder = ZipFileEncoder();
final appDir = await getApplicationDocumentsDirectory();
final now = DateTime.now();
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
final fileEntities = appDir.listSync(recursive: false);
final keychainDump = await _exportKeychainDump(password, nonce: nonce);
final keychainDump = await _exportKeychainDumpV2(password);
final preferencesDump = await _exportPreferencesJSON();
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
@ -98,15 +109,13 @@ class BackupService {
final content = File(archivePath).readAsBytesSync();
tmpDir.deleteSync(recursive: true);
final encryptedData = await _encrypt(content, password, nonce);
return setVersion(encryptedData, currentVersion);
return await _encryptV2(content, password);
}
Future<void> _importBackupV1(Uint8List data, String password,
{required String nonce}) async {
final appDir = await getApplicationDocumentsDirectory();
final decryptedData = await _decrypt(data, password, nonce);
final decryptedData = await _decryptV1(data, password, nonce);
final zip = ZipDecoder().decodeBytes(decryptedData);
zip.files.forEach((file) {
@ -123,7 +132,30 @@ class BackupService {
});
await _verifyWallets();
await _importKeychainDump(password, nonce: nonce);
await _importKeychainDumpV1(password, nonce: nonce);
await _importPreferencesDump();
}
Future<void> _importBackupV2(Uint8List data, String password) async {
final appDir = await getApplicationDocumentsDirectory();
final decryptedData = await _decryptV2(data, password);
final zip = ZipDecoder().decodeBytes(decryptedData);
zip.files.forEach((file) {
final filename = file.name;
if (file.isFile) {
final content = file.content as List<int>;
File('${appDir.path}/' + filename)
..createSync(recursive: true)
..writeAsBytesSync(content);
} else {
Directory('${appDir.path}/' + filename)..create(recursive: true);
}
});
await _verifyWallets();
await _importKeychainDumpV2(password);
await _importPreferencesDump();
}
@ -258,12 +290,12 @@ class BackupService {
await preferencesFile.delete();
}
Future<void> _importKeychainDump(String password,
Future<void> _importKeychainDumpV1(String password,
{required String nonce,
String keychainSalt = secrets.backupKeychainSalt}) async {
final appDir = await getApplicationDocumentsDirectory();
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData = await _decrypt(
final decryptedKeychainDumpFileData = await _decryptV1(
keychainDumpFile.readAsBytesSync(), '$keychainSalt$password', nonce);
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
as Map<String, dynamic>;
@ -288,6 +320,35 @@ class BackupService {
keychainDumpFile.deleteSync();
}
Future<void> _importKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final appDir = await getApplicationDocumentsDirectory();
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData = await _decryptV2(
keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
final keychainJSON = json.decode(utf8.decode(decryptedKeychainDumpFileData))
as Map<String, dynamic>;
final keychainWalletsInfo = keychainJSON['wallets'] as List;
final decodedPin = keychainJSON['pin'] as String;
final pinCodeKey = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final backupPasswordKey =
generateStoreKeyFor(key: SecretStoreKey.backupPassword);
final backupPassword = keychainJSON[backupPasswordKey] as String;
await _flutterSecureStorage.write(
key: backupPasswordKey, value: backupPassword);
keychainWalletsInfo.forEach((dynamic rawInfo) async {
final info = rawInfo as Map<String, dynamic>;
await importWalletKeychainInfo(info);
});
await _flutterSecureStorage.write(
key: pinCodeKey, value: encodedPinCode(pin: decodedPin));
keychainDumpFile.deleteSync();
}
Future<void> importWalletKeychainInfo(Map<String, dynamic> info) async {
final name = info['name'] as String;
final password = info['password'] as String;
@ -295,9 +356,14 @@ class BackupService {
await _keyService.saveWalletPassword(walletName: name, password: password);
}
Future<Uint8List> _exportKeychainDump(String password,
@Deprecated('Use v2 instead')
Future<Uint8List> _exportKeychainDumpV1(String password,
{required String nonce,
String keychainSalt = secrets.backupKeychainSalt}) async {
String keychainSalt = secrets.backupKeychainSalt}) async
=> throw Exception('Deprecated');
Future<Uint8List> _exportKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final encodedPin = await _flutterSecureStorage.read(key: key);
final decodedPin = decodedPinCode(pin: encodedPin!);
@ -319,49 +385,48 @@ class BackupService {
'wallets': wallets,
backupPasswordKey: backupPassword
}));
final encrypted = await _encrypt(
Uint8List.fromList(data), '$keychainSalt$password', nonce);
final encrypted = await _encryptV2(
Uint8List.fromList(data), '$keychainSalt$password');
return encrypted;
}
Future<String> _exportPreferencesJSON() async {
// FIX-ME: Force unwrap
final preferences = <String, dynamic>{
PreferencesKey.currentWalletName:
_sharedPreferences.getString(PreferencesKey.currentWalletName)!,
_sharedPreferences.getString(PreferencesKey.currentWalletName),
PreferencesKey.currentNodeIdKey:
_sharedPreferences.getInt(PreferencesKey.currentNodeIdKey)!,
_sharedPreferences.getInt(PreferencesKey.currentNodeIdKey),
PreferencesKey.currentBalanceDisplayModeKey: _sharedPreferences
.getInt(PreferencesKey.currentBalanceDisplayModeKey)!,
.getInt(PreferencesKey.currentBalanceDisplayModeKey),
PreferencesKey.currentWalletType:
_sharedPreferences.getInt(PreferencesKey.currentWalletType)!,
_sharedPreferences.getInt(PreferencesKey.currentWalletType),
PreferencesKey.currentFiatCurrencyKey:
_sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!,
_sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey),
PreferencesKey.shouldSaveRecipientAddressKey: _sharedPreferences
.getBool(PreferencesKey.shouldSaveRecipientAddressKey)!,
.getBool(PreferencesKey.shouldSaveRecipientAddressKey),
PreferencesKey.isDarkThemeLegacy:
_sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy)!,
_sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy),
PreferencesKey.currentPinLength:
_sharedPreferences.getInt(PreferencesKey.currentPinLength)!,
_sharedPreferences.getInt(PreferencesKey.currentPinLength),
PreferencesKey.currentTransactionPriorityKeyLegacy: _sharedPreferences
.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy)!,
.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy),
PreferencesKey.allowBiometricalAuthenticationKey: _sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey)!,
.getBool(PreferencesKey.allowBiometricalAuthenticationKey),
PreferencesKey.currentBitcoinElectrumSererIdKey: _sharedPreferences
.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey)!,
.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey),
PreferencesKey.currentLanguageCode:
_sharedPreferences.getString(PreferencesKey.currentLanguageCode)!,
_sharedPreferences.getString(PreferencesKey.currentLanguageCode),
PreferencesKey.displayActionListModeKey:
_sharedPreferences.getInt(PreferencesKey.displayActionListModeKey)!,
_sharedPreferences.getInt(PreferencesKey.displayActionListModeKey),
PreferencesKey.currentTheme:
_sharedPreferences.getInt(PreferencesKey.currentTheme)!,
_sharedPreferences.getInt(PreferencesKey.currentTheme),
PreferencesKey.currentDefaultSettingsMigrationVersion: _sharedPreferences
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion)!,
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion),
PreferencesKey.bitcoinTransactionPriority:
_sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority)!,
_sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority),
PreferencesKey.moneroTransactionPriority:
_sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!,
_sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority),
};
return json.encode(preferences);
@ -374,16 +439,12 @@ class BackupService {
return Uint8List.fromList(bytes);
}
Future<Uint8List> _encrypt(
Uint8List data, String secretKeySource, String nonceBase64) async {
final secretKeyHash = await Cryptography.instance.sha256().hash(utf8.encode(secretKeySource));
final secretKey = SecretKey(secretKeyHash.bytes);
final nonce = base64.decode(nonceBase64).toList();
final box = await _cipher.encrypt(data.toList(), secretKey: secretKey, nonce: nonce);
return Uint8List.fromList(box.cipherText);
}
@Deprecated('Use v2 instead')
Future<Uint8List> _encryptV1(
Uint8List data, String secretKeySource, String nonceBase64) async
=> throw Exception('Deprecated');
Future<Uint8List> _decrypt(
Future<Uint8List> _decryptV1(
Uint8List data, String secretKeySource, String nonceBase64, {int macLength = 16}) async {
final secretKeyHash = await Cryptography.instance.sha256().hash(utf8.encode(secretKeySource));
final secretKey = SecretKey(secretKeyHash.bytes);
@ -395,4 +456,12 @@ class BackupService {
final plainData = await _cipher.decrypt(box, secretKey: secretKey);
return Uint8List.fromList(plainData);
}
Future<Uint8List> _encryptV2(
Uint8List data, String passphrase) async
=> cake_backup.encrypt(passphrase, data, version: _v2);
Future<Uint8List> _decryptV2(
Uint8List data, String passphrase) async
=> cake_backup.decrypt(passphrase, data);
}

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/entities/wake_lock.dart';
import 'package:cake_wallet/ionia/ionia_anypay.dart';
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
import 'package:cake_wallet/ionia/ionia_tip.dart';
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
@ -419,16 +420,16 @@ Future setup(
getIt.get<MoneroAccountEditOrCreateViewModel>()));*/
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
AccountListItem, void>(
(AccountListItem account, _) => MoneroAccountEditOrCreateViewModel(
AccountListItem?, void>(
(AccountListItem? account, _) => MoneroAccountEditOrCreateViewModel(
monero!.getAccountList(getIt.get<AppStore>().wallet!),
haven?.getAccountList(getIt.get<AppStore>().wallet!),
wallet: getIt.get<AppStore>().wallet!,
accountListItem: account));
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem,
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem?,
void>(
(AccountListItem account, _) => MoneroAccountEditOrCreatePage(
(AccountListItem? account, _) => MoneroAccountEditOrCreatePage(
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
@ -482,6 +483,10 @@ Future setup(
getIt.registerFactory(
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
getIt.registerFactory(() => OnRamperPage(
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => ExchangeViewModel(
getIt.get<AppStore>().wallet!,
_tradesSource,
@ -489,6 +494,7 @@ Future setup(
getIt.get<TradesStore>(),
getIt.get<AppStore>().settingsStore,
getIt.get<SharedPreferences>(),
getIt.get<SettingsViewModel>(),
));
getIt.registerFactory(() => ExchangeTradeViewModel(
@ -587,6 +593,9 @@ Future setup(
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
getIt.registerFactory(
() => EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
getIt.registerFactory(
() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
@ -692,6 +701,7 @@ Future setup(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount,
ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>()
);
});

View file

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

View file

@ -1,17 +1,15 @@
// import 'package:barcode_scan/barcode_scan.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
var isQrScannerShown = false;
Future<String> presentQRScanner() async {
isQrScannerShown = true;
// FIX-ME: BarcodeScanner
throw Exception('Unimplemented');
// try {
// final result = await BarcodeScanner.scan();
// isQrScannerShown = false;
// return result.rawContent;
// } catch (e) {
// isQrScannerShown = false;
// rethrow;
// }
try {
final result = await BarcodeScanner.scan();
isQrScannerShown = false;
return result.rawContent;
} catch (e) {
isQrScannerShown = false;
rethrow;
}
}

View file

@ -5,36 +5,50 @@ part 'template.g.dart';
@HiveType(typeId: Template.typeId)
class Template extends HiveObject {
Template({
required this.name,
required this.isCurrencySelected,
required this.address,
required this.cryptoCurrency,
required this.amount,
required this.fiatCurrency,
required this.amountFiat});
required this.nameRaw,
required this.isCurrencySelectedRaw,
required this.addressRaw,
required this.cryptoCurrencyRaw,
required this.amountRaw,
required this.fiatCurrencyRaw,
required this.amountFiatRaw});
static const typeId = 6;
static const boxName = 'Template';
@HiveField(0)
String name;
String? nameRaw;
@HiveField(1)
String address;
String? addressRaw;
@HiveField(2)
String cryptoCurrency;
String? cryptoCurrencyRaw;
@HiveField(3)
String amount;
String? amountRaw;
@HiveField(4)
String fiatCurrency;
String? fiatCurrencyRaw;
@HiveField(5)
bool isCurrencySelected;
bool? isCurrencySelectedRaw;
@HiveField(6)
String amountFiat;
String? amountFiatRaw;
bool get isCurrencySelected => isCurrencySelectedRaw ?? false;
String get fiatCurrency => fiatCurrencyRaw ?? '';
String get amountFiat => amountFiatRaw ?? '';
String get name => nameRaw ?? '';
String get address => addressRaw ?? '';
String get cryptoCurrency => cryptoCurrencyRaw ?? '';
String get amount => amountRaw ?? '';
}

View file

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

View file

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

View file

@ -5,32 +5,44 @@ part 'exchange_template.g.dart';
@HiveType(typeId: ExchangeTemplate.typeId)
class ExchangeTemplate extends HiveObject {
ExchangeTemplate({
required this.amount,
required this.depositCurrency,
required this.receiveCurrency,
required this.provider,
required this.depositAddress,
required this.receiveAddress
required this.amountRaw,
required this.depositCurrencyRaw,
required this.receiveCurrencyRaw,
required this.providerRaw,
required this.depositAddressRaw,
required this.receiveAddressRaw
});
static const typeId = 7;
static const boxName = 'ExchangeTemplate';
@HiveField(0)
String amount;
String? amountRaw;
@HiveField(1)
String depositCurrency;
String? depositCurrencyRaw;
@HiveField(2)
String receiveCurrency;
String? receiveCurrencyRaw;
@HiveField(3)
String provider;
String? providerRaw;
@HiveField(4)
String depositAddress;
String? depositAddressRaw;
@HiveField(5)
String receiveAddress;
String? receiveAddressRaw;
String get amount => amountRaw ?? '';
String get depositCurrency => depositCurrencyRaw ?? '';
String get receiveCurrency => receiveCurrencyRaw ?? '';
String get provider => providerRaw ?? '';
String get depositAddress => depositAddressRaw ?? '';
String get receiveAddress => receiveAddressRaw ?? '';
}

View file

@ -1,5 +1,5 @@
import 'dart:convert';
import 'package:cake_wallet/core/amount_converter.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
import 'package:flutter/foundation.dart';

View file

@ -35,7 +35,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
@override
ExchangeProviderDescription get description =>
ExchangeProviderDescription.simpleSwap;
@override
Future<double> calculateAmount(
{required CryptoCurrency from,
@ -61,7 +61,6 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
if (response.body == null || response.body == "null") return 0.00;
final data = json.decode(response.body) as String;
return double.parse(data);
} catch (_) {
return 0.00;
@ -79,7 +78,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
@override
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
final _request = request as SimpleSwapRequest;
final headers = {
final headers = {
'Content-Type': 'application/json'};
final params = <String, String>{
'api_key': apiKey,
@ -111,7 +110,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
final id = responseJSON['id'] as String;
final inputAddress = responseJSON['address_from'] as String;
final settleAddress = responseJSON['user_refund_address'] as String;
final extraId = responseJSON['extra_id_from'] as String?;
return Trade(
id: id,
provider: description,
@ -119,6 +118,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
to: _request.to,
inputAddress: inputAddress,
refundAddress: settleAddress,
extraId: extraId,
state: TradeState.created,
amount: _request.amount,
createdAt: DateTime.now(),
@ -188,6 +188,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
final to = CryptoCurrency.fromString(toCurrency);
final inputAddress = responseJSON['address_from'] as String;
final expectedSendAmount = responseJSON['expected_amount'].toString();
final extraId = responseJSON['extra_id_from'] as String?;
final status = responseJSON['status'] as String;
final state = TradeState.deserialize(raw: status);
@ -195,6 +196,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
id: id,
from: from,
to: to,
extraId: extraId,
provider: description,
inputAddress: inputAddress,
amount: expectedSendAmount,

View file

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

View file

@ -166,7 +166,7 @@ class CWHaven extends Haven {
@override
TransactionPriority getDefaultTransactionPriority() {
return MoneroTransactionPriority.slow;
return MoneroTransactionPriority.automatic;
}
@override

View file

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

View file

@ -31,9 +31,8 @@ class IoniaService {
// Verify email
Future<void> verifyEmail(String code) async {
final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
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: ioniaUsernameStorageKey, value: credentials.username);
}
@ -41,9 +40,8 @@ class IoniaService {
// Sign In
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: ioniaUsernameStorageKey, value: username);
}
Future<String> getUserEmail() async {

View file

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

View file

@ -130,7 +130,7 @@ Future<void> main() async {
secureStorage: secureStorage,
initialMigrationVersion: 17);
runApp(App());
} catch (e) {
} catch (e, stacktrace) {
runApp(MaterialApp(
debugShowCheckedModeBanner: true,
home: Scaffold(
@ -138,7 +138,7 @@ Future<void> main() async {
margin:
EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
child: Text(
'Error:\n${e.toString()}',
'Error:\n${e.toString()}\nStacktrace: $stacktrace',
style: TextStyle(fontSize: 22),
)))));
}

View file

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

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart';
import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
@ -293,7 +294,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.accountCreation:
return CupertinoPageRoute<String>(
builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>(
param1: settings.arguments as AccountListItem));
param1: settings.arguments as AccountListItem?));
case Routes.addressBook:
return MaterialPageRoute<void>(
@ -471,6 +472,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
param1: paymentInfo,
param2: commitedInfo));
case Routes.onramperPage:
return CupertinoPageRoute<void>(builder: (_) => getIt.get<OnRamperPage>());
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(

View file

@ -76,4 +76,5 @@ class Routes {
static const ioniaPaymentStatusPage = '/ionia_payment_status_page';
static const ioniaMoreOptionsPage = '/ionia_more_options_page';
static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
static const onramperPage = '/onramper';
}

View file

@ -1,5 +1,5 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/utils/show_bar.dart';
// import 'package:flushbar/flushbar.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@ -31,9 +31,8 @@ class AuthPageState extends State<AuthPage> {
final _backArrowImageDarkTheme =
Image.asset('assets/images/close_button.png');
ReactionDisposer? _reaction;
// FIX-ME: replace Flushbar
// Flushbar<void>? _authBar;
// Flushbar<void>? _progressBar;
Flushbar<void>? _authBar;
Flushbar<void>? _progressBar;
@override
void initState() {
@ -48,39 +47,34 @@ class AuthPageState extends State<AuthPage> {
if (state is IsExecutingState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
// FIX-ME: Changes related to flutter upgreade.
// Could be incorrect value for duration of auth bar
// _authBar =
// createBar<void>(S.of(context).authentication, duration: Duration())
// ..show(context);
// null duration to make it indefinite until its disposed
_authBar =
createBar<void>(S.of(context).authentication, duration: null)
..show(context);
});
}
if (state is FailureState) {
print('X');
print(state.error);
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
_pinCodeKey.currentState?.clear();
// _authBar?.dismiss();
dismissFlushBar(_authBar);
showBar<void>(
context, S.of(context).failed_authentication(state.error));
if (widget.onAuthenticationFinished != null) {
widget.onAuthenticationFinished(false, this);
}
widget.onAuthenticationFinished(false, this);
});
}
if (state is AuthenticationBanned) {
WidgetsBinding.instance.addPostFrameCallback((_) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
_pinCodeKey.currentState?.clear();
// _authBar?.dismiss();
dismissFlushBar(_authBar);
showBar<void>(
context, S.of(context).failed_authentication(state.error));
if (widget.onAuthenticationFinished != null) {
widget.onAuthenticationFinished(false, this);
}
widget.onAuthenticationFinished(false, this);
});
}
});
@ -102,26 +96,32 @@ class AuthPageState extends State<AuthPage> {
}
void changeProcessText(String text) {
// _authBar?.dismiss();
// FIX-ME: Changes related to flutter upgreade.
// Could be incorrect value for duration of auth bar
// _progressBar = createBar<void>(text, duration: Duration())
// ..show(_key.currentContext);
dismissFlushBar(_authBar);
_progressBar = createBar<void>(text, duration: null)
..show(_key.currentContext!);
}
void hideProgressText() {
// _progressBar?.dismiss();
// _progressBar = null;
dismissFlushBar(_progressBar);
_progressBar = null;
}
void close() {
Future<void> close({String? route, dynamic arguments}) async {
if (_key.currentContext == null) {
throw Exception('Key context is null. Should be not happened');
}
// _authBar?.dismiss();
// _progressBar?.dismiss();
Navigator.of(_key.currentContext!).pop();
/// not the best scenario, but WidgetsBinding is not behaving correctly on Android
await Future<void>.delayed(Duration(milliseconds: 50));
await _authBar?.dismiss();
await Future<void>.delayed(Duration(milliseconds: 50));
await _progressBar?.dismiss();
await Future<void>.delayed(Duration(milliseconds: 50));
if (route != null) {
Navigator.of(_key.currentContext!).pushReplacementNamed(route, arguments: arguments);
} else {
Navigator.of(_key.currentContext!).pop();
}
}
@override
@ -147,4 +147,10 @@ class AuthPageState extends State<AuthPage> {
body: PinCode((pin, _) => widget.authViewModel.auth(password: pin),
(_) => null, widget.authViewModel.pinLength, false, _pinCodeKey));
}
void dismissFlushBar(Flushbar<dynamic>? bar) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await bar?.dismiss();
});
}
}

View file

@ -1,10 +1,10 @@
import 'dart:io';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
// import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:share_plus/share_plus.dart';
import 'package:cross_file/cross_file.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -103,12 +103,14 @@ class BackupPage extends BasePage {
Navigator.of(dialogContext).pop();
final backup = await backupViewModelBase.exportBackup();
if (backup == null) {
return;
}
if (Platform.isAndroid) {
onExportAndroid(context, backup!);
onExportAndroid(context, backup);
} else {
// FIX-ME: Share esys_flutter_share.dart
// await Share.file(S.of(context).backup_file, backup.name,
// backup.content, 'application/*');
await share(backup);
}
},
actionLeftButton: () => Navigator.of(dialogContext).pop());
@ -136,12 +138,20 @@ class BackupPage extends BasePage {
backup.name, backup.content);
Navigator.of(dialogContext).pop();
},
actionLeftButton: () {
actionLeftButton: () async {
Navigator.of(dialogContext).pop();
// FIX-ME: Share esys_flutter_share.dart
// Share.file(S.of(context).backup_file, backup.name,
// backup.content, 'application/*');
await share(backup);
});
});
}
Future<void> share(BackupExportFile backup) async {
const mimeType = 'application/*';
final path = await backupViewModelBase.saveBackupFileLocally(backup);
await Share.shareXFiles(<XFile>[XFile(
path,
name: backup.name,
mimeType: mimeType)]);
await backupViewModelBase.removeBackupFileLocally(backup);
}
}

View file

@ -0,0 +1,86 @@
import 'dart:io';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
class OnRamperPage extends BasePage {
OnRamperPage({
required this.settingsStore,
required this.wallet});
final SettingsStore settingsStore;
final WalletBase wallet;
@override
String get title => S.current.buy;
@override
Widget body(BuildContext context) {
final darkMode = Theme.of(context).brightness == Brightness.dark;
return OnRamperPageBody(
settingsStore: settingsStore,
wallet: wallet,
darkMode: darkMode,
backgroundColor: darkMode
? backgroundDarkColor
: backgroundLightColor,
supportSell: false,
supportSwap: false);
}
}
class OnRamperPageBody extends StatefulWidget {
OnRamperPageBody({
required this.settingsStore,
required this.wallet,
required this.darkMode,
required this.supportSell,
required this.supportSwap,
required this.backgroundColor});
static const baseUrl = 'widget.onramper.com';
final SettingsStore settingsStore;
final WalletBase wallet;
final Color backgroundColor;
final bool darkMode;
final bool supportSell;
final bool supportSwap;
Uri get uri
=> Uri.https(
baseUrl,
'',
<String, dynamic>{
'apiKey': secrets.onramperApiKey,
'defaultCrypto': wallet.currency.title,
'defaultFiat': settingsStore.fiatCurrency.title,
'wallets': '${wallet.currency.title}:${wallet.walletAddresses.address}',
'darkMode': darkMode.toString(),
'supportSell': supportSell.toString(),
'supportSwap': supportSwap.toString()});
@override
OnRamperPageBodyState createState() => OnRamperPageBodyState();
}
class OnRamperPageBodyState extends State<OnRamperPageBody> {
OnRamperPageBodyState();
@override
void initState() {
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
@override
Widget build(BuildContext context) {
return WebView(
initialUrl: widget.uri.toString(),
backgroundColor: widget.backgroundColor,
javascriptMode: JavascriptMode.unrestricted);
}
}

View file

@ -80,7 +80,7 @@ class PreOrderPage extends BasePage {
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!
keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!
.backgroundColor!,
nextFocus: false,
actions: [
@ -102,10 +102,9 @@ class PreOrderPage extends BasePage {
bottomLeft: Radius.circular(24),
bottomRight: Radius.circular(24)),
gradient: LinearGradient(colors: [
Theme.of(context).primaryTextTheme!.subtitle1!.color!,
Theme.of(context).primaryTextTheme.subtitle1!.color!,
Theme.of(context)
.primaryTextTheme!
.subtitle1!
.primaryTextTheme.subtitle1!
.decorationColor!,
], begin: Alignment.topLeft, end: Alignment.bottomRight),
),
@ -161,11 +160,11 @@ class PreOrderPage extends BasePage {
),
),
hintText: '0.00',
borderColor: Theme.of(context).primaryTextTheme!.bodyText1!.decorationColor!,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.decorationColor!,
borderWidth: 0.5,
textStyle: TextStyle(fontSize: 36, fontWeight: FontWeight.w500, color: Colors.white),
placeholderTextStyle: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline5!.decorationColor!,
color: Theme.of(context).primaryTextTheme.headline5!.decorationColor!,
fontWeight: FontWeight.w500,
fontSize: 36,
),
@ -180,7 +179,7 @@ class PreOrderPage extends BasePage {
S.of(context).buy_with + ':',
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
fontSize: 18,
fontWeight: FontWeight.bold
),
@ -197,11 +196,11 @@ class PreOrderPage extends BasePage {
double achAmount;
int minAmount;
if (snapshot.hasData) {
if (snapshot.hasData && snapshot.data != null) {
sourceAmount = snapshot.data!.sourceAmount;
destAmount = snapshot.data!.destAmount;
minAmount = snapshot.data!.minAmount;
achAmount = snapshot.data!.achSourceAmount!;
achAmount = snapshot.data!.achSourceAmount ?? 0;
} else {
sourceAmount = 0.0;
destAmount = 0.0;
@ -215,7 +214,7 @@ class PreOrderPage extends BasePage {
child: Observer(builder: (_) {
return BuyListItem(
selectedProvider:
buyViewModel.selectedProvider!,
buyViewModel.selectedProvider,
provider: item.provider,
sourceAmount: sourceAmount,
sourceCurrency: buyViewModel.fiatCurrency,
@ -247,7 +246,7 @@ class PreOrderPage extends BasePage {
? S.of(context).buy
: S.of(context).buy_with +
' ${buyViewModel.selectedProvider!.description.title}',
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white,
isLoading: buyViewModel.isRunning,
isDisabled: (buyViewModel.selectedProvider == null) ||

View file

@ -18,7 +18,7 @@ class BuyListItem extends StatelessWidget {
this.onTap
});
final BuyProvider selectedProvider;
final BuyProvider? selectedProvider;
final BuyProvider provider;
final double sourceAmount;
final FiatCurrency sourceCurrency;

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/entities/contact_base.dart';
import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
@ -34,12 +35,12 @@ class ContactListPage extends BasePage {
height: 32.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).accentTextTheme!.caption!.color!),
color: Theme.of(context).accentTextTheme.caption!.color!),
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Icon(Icons.add,
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
size: 22.0),
ButtonTheme(
minWidth: 32.0,
@ -66,9 +67,9 @@ class ContactListPage extends BasePage {
return CollapsibleSectionList(
context: context,
sectionCount: 2,
themeColor: Theme.of(context).primaryTextTheme!.headline6!.color!,
themeColor: Theme.of(context).primaryTextTheme.headline6!.color!,
dividerThemeColor:
Theme.of(context).primaryTextTheme!.caption!.decorationColor!,
Theme.of(context).primaryTextTheme.caption!.decorationColor!,
sectionTitleBuilder: (_, int sectionIndex) {
var title = 'Contacts';
@ -91,37 +92,13 @@ class ContactListPage extends BasePage {
final contact = contactListViewModel.contacts[index];
final content = generateRaw(context, contact);
// FIX-ME: Slidable
return content;
// return !isEditable
// ? content
// : Slidable(
// key: Key('${contact.key}'),
// actionPane: SlidableDrawerActionPane(),
// child: content,
// secondaryActions: <Widget>[
// IconSlideAction(
// caption: S.of(context).edit,
// color: Colors.blue,
// icon: Icons.edit,
// onTap: () async => await Navigator.of(context)
// .pushNamed(Routes.addressBookAddContact,
// arguments: contact),
// ),
// IconSlideAction(
// caption: S.of(context).delete,
// color: Colors.red,
// icon: CupertinoIcons.delete,
// onTap: () async {
// final isDelete =
// await showAlertDialog(context) ?? false;
// if (isDelete) {
// await contactListViewModel.delete(contact);
// }
// },
// ),
// ]);
return !isEditable
? content
: Slidable(
key: Key('${contact.key}'),
endActionPane: _actionPane(context, contact),
child: content,
);
},
);
},
@ -141,7 +118,7 @@ class ContactListPage extends BasePage {
final isCopied = await showNameAndAddressDialog(
context, contact.name, contact.address);
if (isCopied != null && isCopied) {
if (isCopied) {
await Clipboard.setData(ClipboardData(text: contact.address));
await showBar<void>(context, S.of(context).copied_to_clipboard);
}
@ -165,7 +142,7 @@ class ContactListPage extends BasePage {
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).primaryTextTheme!.headline6!.color!),
color: Theme.of(context).primaryTextTheme.headline6!.color!),
),
)
)
@ -266,4 +243,34 @@ class ContactListPage extends BasePage {
actionLeftButton: () => Navigator.of(context).pop(false));
}) ?? false;
}
ActionPane _actionPane(BuildContext context, ContactRecord contact) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.4,
children: [
SlidableAction(
onPressed: (_) async => await Navigator.of(context)
.pushNamed(Routes.addressBookAddContact,
arguments: contact),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
icon: Icons.edit,
label: S.of(context).edit,
),
SlidableAction(
onPressed: (_) async {
final isDelete =
await showAlertDialog(context);
if (isDelete) {
await contactListViewModel.delete(contact);
}
},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
}

View file

@ -271,10 +271,10 @@ class DashboardPage extends BasePage {
switch (walletType) {
case WalletType.bitcoin:
Navigator.of(context).pushNamed(Routes.preOrder);
Navigator.of(context).pushNamed(Routes.onramperPage);
break;
case WalletType.litecoin:
Navigator.of(context).pushNamed(Routes.preOrder);
Navigator.of(context).pushNamed(Routes.onramperPage);
break;
default:
await showPopUp<void>(

View file

@ -42,8 +42,7 @@ class WalletMenu {
Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close();
Navigator.of(auth.context).pushNamed(Routes.showKeys);
auth.close(route: Routes.showKeys);
}
});
}),
@ -52,6 +51,21 @@ class WalletMenu {
image: Image.asset('assets/images/open_book_menu.png',
height: 16, width: 16),
handler: () => Navigator.of(context).pushNamed(Routes.addressBook)),
WalletMenuItem(
title: S.current.backup,
image: Image.asset('assets/images/restore_wallet.png',
height: 16,
width: 16,
color: Palette.darkBlue),
handler: () {
Navigator.of(context).pushNamed(
Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (isAuthenticatedSuccessfully) {
auth.close(route:Routes.backup);
}
});
}),
WalletMenuItem(
title: S.current.settings_title,
image: Image.asset('assets/images/settings_menu.png',

View file

@ -15,6 +15,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart';
import 'package:share_plus/share_plus.dart';
class AddressPage extends BasePage {
AddressPage({
@ -85,6 +86,26 @@ class AddressPage extends BasePage {
], begin: Alignment.topRight, end: Alignment.bottomLeft)),
child: scaffold);
@override
Widget? trailing(BuildContext context) {
final shareImage =
Image.asset('assets/images/share.png',
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!);
return !addressListViewModel.hasAddressList ? Material(
color: Colors.transparent,
child: IconButton(
padding: EdgeInsets.zero,
constraints: BoxConstraints(),
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
iconSize: 25,
onPressed: () => Share.share(addressListViewModel.address.address),
icon: shareImage,
),
) : null;
}
@override
Widget body(BuildContext context) {
autorun((_) async {

View file

@ -111,6 +111,10 @@ class ExchangePage extends BasePage {
WidgetsBinding.instance
.addPostFrameCallback((_) => _setReactions(context, exchangeViewModel));
if (exchangeViewModel.isLowFee) {
_showFeeAlert(context);
}
return KeyboardActions(
disableScroll: true,
config: KeyboardActionsConfig(
@ -794,5 +798,23 @@ class ExchangePage extends BasePage {
return address;
}
void _showFeeAlert(BuildContext context) async {
await Future<void>.delayed(Duration(seconds: 1));
final confirmed = await showPopUp<bool>(
context: context,
builder: (dialogContext) {
return AlertWithTwoActions(
alertTitle: S.of(context).low_fee,
alertContent: S.of(context).low_fee_alert,
leftButtonText: S.of(context).ignor,
rightButtonText: S.of(context).use_suggested,
actionLeftButton: () => Navigator.of(context).pop(false),
actionRightButton: () => Navigator.of(context).pop(true));
}) ?? false;
if (confirmed) {
exchangeViewModel.setDefaultTransactionPriority();
}
}
void disposeBestRateSync() => exchangeViewModel.bestRateSync?.cancel();
}

View file

@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/palette.dart';
import 'currency_picker_widget.dart';
class CurrencyPicker extends StatefulWidget {
@ -104,7 +105,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
style: TextStyle(color: Theme.of(context).primaryTextTheme!.headline6!.color!),
style: TextStyle(color: Palette.darkBlueCraiola),
decoration: InputDecoration(
hintText: widget.hintText,
prefixIcon: Image.asset("assets/images/search_icon.png"),

View file

@ -20,9 +20,12 @@ class PresentProviderPicker extends StatelessWidget {
return TextButton(
onPressed: () => _presentProviderPicker(context),
// FIX-ME: Style
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero),
splashFactory: NoSplash.splashFactory,
foregroundColor: MaterialStateProperty.all(Colors.transparent),
overlayColor: MaterialStateProperty.all(Colors.transparent),
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
@ -46,7 +49,7 @@ class PresentProviderPicker extends StatelessWidget {
style: TextStyle(
fontSize: 10.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).textTheme!.headline5!.color!)))
color: Theme.of(context).textTheme.headline5!.color!)))
],
),
SizedBox(width: 5),

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/palette.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/text_icon_button.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:mobx/mobx.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 {
IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel);
@ -295,73 +295,35 @@ class IoniaBuyGiftCardDetailPage extends BasePage {
final amount = ioniaPurchaseViewModel.invoice!.totalAmount;
final addresses = ioniaPurchaseViewModel.invoice!.outAddresses;
ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount);
ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first;
await showPopUp<void>(
context: context,
builder: (_) {
return IoniaConfirmModal(
return ConfirmSendingAlert(
alertTitle: S.of(context).confirm_sending,
alertContent: Container(
height: 200,
padding: EdgeInsets.all(15),
child: Column(children: [
Row(children: [
Text(S.of(context).payment_id,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.pigeonBlue,
decoration: TextDecoration.none)),
Text(ioniaPurchaseViewModel.invoice!.paymentId,
style: TextStyle(
fontSize: 16,
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()))
])),
paymentId: S.of(context).payment_id,
paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId,
amount: S.of(context).send_amount,
amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}',
fiatAmountValue:
'~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} '
'${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
fee: S.of(context).send_fee,
feeValue:
'${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} '
'${ioniaPurchaseViewModel.invoice!.chain}',
feeFiatAmount:
'${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} '
'${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
outputs: ioniaPurchaseViewModel.sendViewModel.outputs,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
leftActionColor: Color(0xffFF6600),
rightActionColor: Theme.of(context).accentTextTheme!.bodyText1!.color!,
alertLeftActionButtonTextColor: Colors.white,
alertRightActionButtonTextColor: Colors.white,
alertLeftActionButtonColor: Palette.brightOrange,
alertRightActionButtonColor: Theme.of(context).textTheme!.subtitle2!.color,
actionRightButton: () async {
Navigator.of(context).pop();
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

@ -1,15 +1,6 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
// import 'package:flushbar/flushbar.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
@ -67,8 +58,6 @@ class WalletTypeFormState extends State<WalletTypeForm> {
WalletType? selected;
List<WalletType> types;
// FIX-ME: Replace Flushbar
// Flushbar<void>? _progressBar;
@override
void initState() {
@ -97,7 +86,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme!.headline6!.color!),
color: Theme.of(context).primaryTextTheme.headline6!.color!),
),
),
...types.map((type) => Padding(
@ -114,7 +103,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
bottomSection: PrimaryButton(
onPressed: () => onTypeSelected(),
text: S.of(context).seed_language_next,
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
textColor: Colors.white,
isDisabled: selected == null,
),

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/node.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -26,7 +27,7 @@ class NodeListPage extends BasePage {
height: 32,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
color: Theme.of(context).accentTextTheme!.caption!.color!),
color: Theme.of(context).accentTextTheme.caption!.color!),
child: ButtonTheme(
minWidth: double.minPositive,
child: TextButton(
@ -85,7 +86,7 @@ class NodeListPage extends BasePage {
final node = nodeListViewModel.nodes[index];
final isSelected =
node.keyIndex == nodeListViewModel.currentNode?.keyIndex;
node.keyIndex == nodeListViewModel.currentNode.keyIndex;
final nodeListRow = NodeListRow(
title: node.uriRaw,
isSelected: isSelected,
@ -114,45 +115,52 @@ class NodeListPage extends BasePage {
});
});
});
// FIX-ME: Slidable
// final dismissibleRow = Slidable(
// key: Key('${node.keyIndex}'),
// actionPane: SlidableDrawerActionPane(),
// child: nodeListRow,
// secondaryActions: <Widget>[
// IconSlideAction(
// caption: S.of(context).delete,
// color: Colors.red,
// icon: CupertinoIcons.delete,
// onTap: () async {
// final confirmed = await showPopUp<bool>(
// context: context,
// builder: (BuildContext context) {
// return AlertWithTwoActions(
// alertTitle: S.of(context).remove_node,
// alertContent:
// S.of(context).remove_node_message,
// rightButtonText: S.of(context).remove,
// leftButtonText: S.of(context).cancel,
// actionRightButton: () =>
// Navigator.pop(context, true),
// actionLeftButton: () =>
// Navigator.pop(context, false));
// }) ??
// false;
// if (confirmed) {
// await nodeListViewModel.delete(node);
// }
// },
// ),
// ]);
final dismissibleRow = Slidable(
key: Key('${node.keyIndex}'),
startActionPane: _actionPane(context, node),
endActionPane: _actionPane(context, node),
child: nodeListRow,
);
return nodeListRow;
// return isSelected ? nodeListRow : dismissibleRow;
return isSelected ? nodeListRow : dismissibleRow;
});
},
),
);
}
ActionPane _actionPane(BuildContext context, Node node) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (context) async {
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).remove_node,
alertContent:
S.of(context).remove_node_message,
rightButtonText: S.of(context).remove,
leftButtonText: S.of(context).cancel,
actionRightButton: () =>
Navigator.pop(context, true),
actionLeftButton: () =>
Navigator.pop(context, false));
}) ??
false;
if (confirmed) {
await nodeListViewModel.delete(node);
}
},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
}

View file

@ -1,7 +1,6 @@
import 'package:cake_wallet/utils/show_bar.dart';
// import 'package:flushbar/flushbar.dart';
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
class PinCodeWidget extends StatefulWidget {
@ -40,8 +39,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
String pin;
String title;
double _aspectRatio;
// FIX-ME: Replace Flushbar
// Flushbar<void>? _progressBar;
Flushbar<void>? _progressBar;
int currentPinLength() => pin.length;
@ -91,19 +89,18 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
void changeProcessText(String text) {
hideProgressText();
// FIX-ME: Empty Duration,
// _progressBar = createBar<void>(text, duration: Duration())
// ..show(_key.currentContext);
_progressBar = createBar<void>(text, duration: null)
..show(_key.currentContext!);
}
void close() {
// _progressBar?.dismiss();
_progressBar?.dismiss();
Navigator.of(_key.currentContext!).pop();
}
void hideProgressText() {
// _progressBar?.dismiss();
// _progressBar = null;
_progressBar?.dismiss();
_progressBar = null;
}
@override

View file

@ -6,7 +6,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
// import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:share_plus/share_plus.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/di.dart';
@ -92,23 +92,17 @@ class ReceivePage extends BasePage {
Image.asset('assets/images/share.png',
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!);
return SizedBox(
height: 20.0,
width: 20.0,
child: ButtonTheme(
minWidth: double.minPositive,
child: TextButton(
// FIX-ME: Style
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
//padding: EdgeInsets.all(0),
onPressed: () {
// FIX-ME: Share esys_flutter_share.dart
// Share.text(S.current.share_address,
// addressListViewModel.address.address, 'text/plain')
},
child: shareImage),
),
return Material(
color: Colors.transparent,
child: IconButton(
padding: EdgeInsets.zero,
constraints: BoxConstraints(),
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
iconSize: 25,
onPressed: () => Share.share(addressListViewModel.address.address),
icon: shareImage
)
);
}

View file

@ -57,6 +57,7 @@ class AddressCell extends StatelessWidget {
final Widget cell = InkWell(
onTap: () => onTap?.call(address),
child: Container(
width: double.infinity,
color: backgroundColor,
padding: EdgeInsets.only(left: 24, right: 24, top: 28, bottom: 28),
child: Text(
@ -69,20 +70,25 @@ class AddressCell extends StatelessWidget {
),
),
));
// FIX-ME: Slidable
return cell;
// return Container(
// color: backgroundColor,
// child: Slidable(
// key: Key(address),
// actionPane: SlidableDrawerActionPane(),
// child: cell,
// secondaryActions: <Widget>[
// IconSlideAction(
// caption: S.of(context).edit,
// color: Colors.blue,
// icon: Icons.edit,
// onTap: () => onEdit?.call())
// ]));
return Slidable(
key: Key(address),
startActionPane: _actionPane(context),
endActionPane: _actionPane(context),
child: cell,
);
}
ActionPane _actionPane(BuildContext context) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (_) => onEdit?.call(),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
icon: Icons.edit,
label: S.of(context).edit,
),
],
);
}

View file

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

View file

@ -6,7 +6,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// import 'package:esys_flutter_share/esys_flutter_share.dart';
import 'package:share_plus/share_plus.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
@ -159,13 +159,8 @@ class WalletSeedPage extends BasePage {
child: Container(
padding: EdgeInsets.only(right: 8.0),
child: PrimaryButton(
onPressed: () {
// FIX-ME: Share esys_flutter_share
// Share.text(
// S.of(context).seed_share,
// walletSeedViewModel.seed,
// 'text/plain')
},
onPressed: () =>
Share.share(walletSeedViewModel.seed),
text: S.of(context).save,
color: Colors.green,
textColor: Colors.white),

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/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
import 'package:flutter/scheduler.dart';
class ConfirmSendingAlert extends BaseAlertDialog {
ConfirmSendingAlert({
required this.alertTitle,
this.paymentId,
this.paymentIdValue,
required this.amount,
required this.amountValue,
required this.fiatAmountValue,
@ -19,9 +22,15 @@ class ConfirmSendingAlert extends BaseAlertDialog {
required this.rightButtonText,
required this.actionLeftButton,
required this.actionRightButton,
this.alertBarrierDismissible = true});
this.alertBarrierDismissible = true,
this.alertLeftActionButtonTextColor,
this.alertRightActionButtonTextColor,
this.alertLeftActionButtonColor,
this.alertRightActionButtonColor});
final String alertTitle;
final String? paymentId;
final String? paymentIdValue;
final String amount;
final String amountValue;
final String fiatAmountValue;
@ -34,6 +43,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
final VoidCallback actionLeftButton;
final VoidCallback actionRightButton;
final bool alertBarrierDismissible;
final Color? alertLeftActionButtonTextColor;
final Color? alertRightActionButtonTextColor;
final Color? alertLeftActionButtonColor;
final Color? alertRightActionButtonColor;
@override
String get titleText => alertTitle;
@ -56,8 +69,22 @@ class ConfirmSendingAlert extends BaseAlertDialog {
@override
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
Widget content(BuildContext context) => ConfirmSendingAlertContent(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount,
amountValue: amountValue,
fiatAmountValue: fiatAmountValue,
@ -70,6 +97,8 @@ class ConfirmSendingAlert extends BaseAlertDialog {
class ConfirmSendingAlertContent extends StatefulWidget {
ConfirmSendingAlertContent({
this.paymentId,
this.paymentIdValue,
required this.amount,
required this.amountValue,
required this.fiatAmountValue,
@ -78,6 +107,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
required this.feeFiatAmount,
required this.outputs});
final String? paymentId;
final String? paymentIdValue;
final String amount;
final String amountValue;
final String fiatAmountValue;
@ -88,6 +119,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
@override
ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState(
paymentId: paymentId,
paymentIdValue: paymentIdValue,
amount: amount,
amountValue: amountValue,
fiatAmountValue: fiatAmountValue,
@ -100,6 +133,8 @@ class ConfirmSendingAlertContent extends StatefulWidget {
class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> {
ConfirmSendingAlertContentState({
this.paymentId,
this.paymentIdValue,
required this.amount,
required this.amountValue,
required this.fiatAmountValue,
@ -115,6 +150,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
: S.current.recipient_address;
}
final String? paymentId;
final String? paymentIdValue;
final String amount;
final String amountValue;
final String fiatAmountValue;
@ -129,6 +166,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
double fromTop = 0;
String recipientTitle;
int itemCount;
bool showScrollbar = false;
@override
Widget build(BuildContext context) {
@ -140,6 +178,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
setState(() {});
});
SchedulerBinding.instance.addPostFrameCallback((_) {
setState(() {
showScrollbar = controller.position.maxScrollExtent > 0;
});
});
return Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
@ -150,6 +194,44 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
controller: controller,
child: Column(
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(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -365,7 +447,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
)
)
),
if (itemCount > 1) CakeScrollbar(
if (showScrollbar) CakeScrollbar(
backgroundHeight: backgroundHeight,
thumbHeight: thumbHeight,
fromTop: fromTop,

View file

@ -20,7 +20,7 @@ class SettingsLinkProviderCell extends StandardListRow {
@override
Widget? buildLeading(BuildContext context) =>
icon != null ? Image.asset(icon!, color: iconColor, height: 30, width: 30) : null;
icon != null ? Image.asset(icon!, color: iconColor, height: 24, width: 24) : null;
@override
Widget buildTrailing(BuildContext context) => Text(linkTitle,

View file

@ -1,3 +1,4 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@ -18,7 +19,36 @@ class WalletKeysPage extends BasePage {
@override
Widget body(BuildContext context) {
return Container(
return Column(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).accentTextTheme!.caption!.color!,
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: AutoSizeText(
S.of(context).do_not_share_warning_text.toUpperCase(),
textAlign: TextAlign.center,
maxLines: 4,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.red)),
),
),
),
),
),
Expanded(
flex: 7,
child: Container(
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Observer(
builder: (_) {
@ -48,6 +78,6 @@ class WalletKeysPage extends BasePage {
);
});
},
));
)))]);
}
}

View file

@ -3,7 +3,7 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
// import 'package:flushbar/flushbar.dart';
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -49,7 +49,7 @@ class WalletListBodyState extends State<WalletListBody> {
Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
final scrollController = ScrollController();
final double tileHeight = 60;
// Flushbar<void>? _progressBar;
Flushbar<void>? _progressBar;
@override
Widget build(BuildContext context) {
@ -232,7 +232,9 @@ class WalletListBodyState extends State<WalletListBody> {
await widget.walletListViewModel.loadWallet(wallet);
auth.hideProgressText();
auth.close();
Navigator.of(context).pop();
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pop();
});
} catch (e) {
auth.changeProcessText(S
.of(context)
@ -283,13 +285,12 @@ class WalletListBodyState extends State<WalletListBody> {
}
void changeProcessText(String text) {
// FIX-ME: Duration
// _progressBar = createBar<void>(text, duration: Duration())..show(context);
_progressBar = createBar<void>(text, duration: null)..show(context);
}
void hideProgressText() {
// _progressBar?.dismiss();
// _progressBar = null;
_progressBar?.dismiss();
_progressBar = null;
}
ActionPane _actionPane(WalletListItem wallet) => ActionPane(

View file

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

View file

@ -24,7 +24,7 @@ abstract class ExchangeTemplateBase with Store {
templates.replaceRange(0, templates.length, templateSource.values.toList());
@action
Future addTemplate({
Future<void> addTemplate({
required String amount,
required String depositCurrency,
required String receiveCurrency,
@ -32,15 +32,15 @@ abstract class ExchangeTemplateBase with Store {
required String depositAddress,
required String receiveAddress}) async {
final template = ExchangeTemplate(
amount: amount,
depositCurrency: depositCurrency,
receiveCurrency: receiveCurrency,
provider: provider,
depositAddress: depositAddress,
receiveAddress: receiveAddress);
amountRaw: amount,
depositCurrencyRaw: depositCurrency,
receiveCurrencyRaw: receiveCurrency,
providerRaw: provider,
depositAddressRaw: depositAddress,
receiveAddressRaw: receiveAddress);
await templateSource.add(template);
}
@action
Future remove({required ExchangeTemplate template}) async => await template.delete();
Future<void> remove({required ExchangeTemplate template}) async => await template.delete();
}

View file

@ -23,7 +23,7 @@ abstract class SendTemplateBase with Store {
templates.replaceRange(0, templates.length, templateSource.values.toList());
@action
Future addTemplate({
Future<void> addTemplate({
required String name,
required bool isCurrencySelected,
required String address,
@ -32,16 +32,16 @@ abstract class SendTemplateBase with Store {
required String amount,
required String amountFiat}) async {
final template = Template(
name: name,
isCurrencySelected: isCurrencySelected,
address: address,
cryptoCurrency: cryptoCurrency,
fiatCurrency: fiatCurrency,
amount: amount,
amountFiat: amountFiat);
nameRaw: name,
isCurrencySelectedRaw: isCurrencySelected,
addressRaw: address,
cryptoCurrencyRaw: cryptoCurrency,
fiatCurrencyRaw: fiatCurrency,
amountRaw: amount,
amountFiatRaw: amountFiat);
await templateSource.add(template);
}
@action
Future remove({required Template template}) async => await template.delete();
Future<void> remove({required Template template}) async => await template.delete();
}

View file

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

View file

@ -1,58 +1,71 @@
// import 'package:flushbar/flushbar.dart';
import 'package:flutter/cupertino.dart';
import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart';
Future<T?> showBar<T>(BuildContext context, String messageText,
{bool isDark = false,
Duration duration = const Duration(seconds: 1),
bool isDismissible = true,
String? titleText}) async {
// FIX-ME: Unimplemented Flushbar
// final bar = Flushbar<T>(
// boxShadows: [
// BoxShadow(
// color: Colors.black.withOpacity(0.09),
// blurRadius: 8,
// offset: Offset(0, 2))
// ],
// backgroundColor: isDark ? Colors.black : Colors.white,
// borderRadius: 35,
// margin: EdgeInsets.all(50),
// titleText: titleText != null
// ? Text(titleText,
// textAlign: TextAlign.center,
// style: TextStyle(color: isDark ? Colors.white : Colors.black, fontWeight: FontWeight.bold, fontSize: 24.0))
// : null,
// messageText: Text(messageText,
// textAlign: TextAlign.center,
// style: TextStyle(color: isDark ? Colors.white : Colors.black, fontSize: 16)),
// duration: duration,
// isDismissible: isDismissible,
// flushbarPosition: FlushbarPosition.TOP,
// flushbarStyle: FlushbarStyle.FLOATING);
Duration? duration = const Duration(seconds: 1), // pass explicitly by null to make the duration indefinite
bool isDismissible = true,
String? titleText}) async {
final bar = Flushbar<T>(
boxShadows: [
BoxShadow(
color: Colors.black.withOpacity(0.09),
blurRadius: 8,
offset: Offset(0, 2),
)
],
backgroundColor: isDark ? Colors.black : Colors.white,
borderRadius: BorderRadius.circular(35),
margin: EdgeInsets.all(50),
titleText: titleText != null
? Text(
titleText,
textAlign: TextAlign.center,
style: TextStyle(
color: isDark ? Colors.white : Colors.black,
fontWeight: FontWeight.bold,
fontSize: 24.0,
),
)
: null,
messageText: Text(
messageText,
textAlign: TextAlign.center,
style: TextStyle(
color: isDark ? Colors.white : Colors.black,
fontSize: 16,
),
),
duration: duration,
isDismissible: isDismissible,
flushbarPosition: FlushbarPosition.TOP,
flushbarStyle: FlushbarStyle.FLOATING,
);
// return bar.show(context);
return null;
return bar.show(context);
}
// FIX-ME: Unimplemented Flushbar
// Flushbar<T> createBar<T>(String text,
// {bool isDark = false, Duration duration = const Duration(seconds: 1), bool isDismissible = true}) {
// return Flushbar<T>(
// boxShadows: [
// BoxShadow(
// color: Colors.black.withOpacity(0.09),
// blurRadius: 8,
// offset: Offset(0, 2))
// ],
// backgroundColor: isDark ? Colors.black : Colors.white,
// borderRadius: 35,
// margin: EdgeInsets.all(50),
// messageText: Text(text,
// textAlign: TextAlign.center,
// style: TextStyle(color: isDark ? Colors.white : Colors.black)),
// duration: duration,
// isDismissible: isDismissible,
// flushbarPosition: FlushbarPosition.TOP,
// flushbarStyle: FlushbarStyle.FLOATING);
// }
Flushbar<T> createBar<T>(String text,
{bool isDark = false,
Duration? duration = const Duration(seconds: 1), // pass explicitly by null to make the duration indefinite
bool isDismissible = true}) {
return Flushbar<T>(
boxShadows: [
BoxShadow(
color: Colors.black.withOpacity(0.09),
blurRadius: 8,
offset: Offset(0, 2),
)
],
backgroundColor: isDark ? Colors.black : Colors.white,
borderRadius: BorderRadius.circular(35),
margin: EdgeInsets.all(50),
messageText: Text(text,
textAlign: TextAlign.center,
style: TextStyle(color: isDark ? Colors.white : Colors.black)),
duration: duration,
isDismissible: isDismissible,
flushbarPosition: FlushbarPosition.TOP,
flushbarStyle: FlushbarStyle.FLOATING,
);
}

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/view_model/auth_state.dart';
@ -55,8 +56,10 @@ abstract class AuthViewModelBase with Store {
final isSuccessfulAuthenticated = await _authService.authenticate(password);
if (isSuccessfulAuthenticated) {
state = ExecutedSuccessfullyState();
_failureCounter = 0;
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
state = ExecutedSuccessfullyState();
_failureCounter = 0;
});
} else {
_failureCounter += 1;

View file

@ -8,6 +8,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:mobx/mobx.dart';
import 'package:intl/intl.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:path_provider/path_provider.dart';
part 'backup_view_model.g.dart';
@ -71,6 +72,21 @@ abstract class BackupViewModelBase with Store {
}
}
Future<String> saveBackupFileLocally(BackupExportFile backup) async {
final appDir = await getApplicationDocumentsDirectory();
final path = '${appDir.path}/${backup.name}';
final backupFile = File(path);
await backupFile.writeAsBytes(backup.content);
return path;
}
Future<void> removeBackupFileLocally(BackupExportFile backup) async {
final appDir = await getApplicationDocumentsDirectory();
final path = '${appDir.path}/${backup.name}';
final backupFile = File(path);
await backupFile.delete();
}
@action
void showMasterPassword() => isBackupPasswordVisible = true;

View file

@ -6,7 +6,6 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/buy/buy_item.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
@ -103,7 +102,7 @@ abstract class BuyViewModelBase with Store {
print(e.toString());
}
if (isMoonPayEnabled ?? false) {
if (isMoonPayEnabled) {
_providerList.add(MoonPayBuyProvider(wallet: wallet));
}

View file

@ -6,12 +6,15 @@ import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart';
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_type.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/limits.dart';
import 'package:cake_wallet/exchange/trade.dart';
@ -40,7 +43,7 @@ class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
abstract class ExchangeViewModelBase with Store {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
this.tradesStore, this._settingsStore, this.sharedPreferences)
this.tradesStore, this._settingsStore, this.sharedPreferences, this._settingsViewModel)
: _cryptoNumberFormat = NumberFormat(),
isReverse = false,
isFixedRateMode = false,
@ -192,6 +195,20 @@ abstract class ExchangeViewModelBase with Store {
bool get isMoneroWallet => wallet.type == WalletType.monero;
bool get isLowFee {
switch (wallet.type) {
case WalletType.monero:
case WalletType.haven:
return _settingsViewModel.transactionPriority == monero!.getMoneroTransactionPrioritySlow();
case WalletType.bitcoin:
return _settingsViewModel.transactionPriority == bitcoin!.getBitcoinTransactionPrioritySlow();
case WalletType.litecoin:
return _settingsViewModel.transactionPriority == bitcoin!.getLitecoinTransactionPrioritySlow();
default:
return false;
}
}
List<CryptoCurrency> receiveCurrencies;
List<CryptoCurrency> depositCurrencies;
@ -204,6 +221,8 @@ abstract class ExchangeViewModelBase with Store {
final SettingsStore _settingsStore;
final SettingsViewModel _settingsViewModel;
double _bestRate = 0.0;
late Timer bestRateSync;
@ -611,4 +630,22 @@ abstract class ExchangeViewModelBase with Store {
selectedProviders
.where((provider) => providersForCurrentPair().contains(provider)));
}
@action
void setDefaultTransactionPriority() {
switch (wallet.type) {
case WalletType.monero:
case WalletType.haven:
_settingsStore.priority[wallet.type] = monero!.getMoneroTransactionPriorityAutomatic();
break;
case WalletType.bitcoin:
_settingsStore.priority[wallet.type] = bitcoin!.getBitcoinTransactionPriorityMedium();
break;
case WalletType.litecoin:
_settingsStore.priority[wallet.type] = bitcoin!.getLitecoinTransactionPriorityMedium();
break;
default:
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_tip.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';
@ -17,6 +18,7 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
required this.ioniaAnyPayService,
required this.amount,
required this.ioniaMerchant,
required this.sendViewModel,
}) : tipAmount = 0.0,
percentage = 0.0,
invoiceCreationState = InitialExecutionState(),
@ -40,6 +42,8 @@ abstract class IoniaMerchPurchaseViewModelBase with Store {
final IoniaMerchant ioniaMerchant;
final SendViewModel sendViewModel;
final IoniaAnyPay ioniaAnyPayService;
IoniaAnyPayPaymentInfo? paymentInfo;

View file

@ -1,7 +1,6 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
@ -276,7 +275,7 @@ abstract class SendViewModelBase with Store {
if (isElectrumWallet) {
final rate = bitcoin!.getFeeRate(wallet, _priority);
return '${(priority as BitcoinTransactionPriority).labelWithRate(rate)}';
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate);
}
return priority.toString();

View file

@ -1,7 +1,6 @@
import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:flutter/cupertino.dart';
import 'package:mobx/mobx.dart';
import 'package:package_info/package_info.dart';
@ -137,7 +136,7 @@ abstract class SettingsViewModelBase with Store {
if (wallet.type == WalletType.bitcoin
|| wallet.type == WalletType.litecoin) {
final rate = bitcoin!.getFeeRate(wallet, _priority);
return '${(priority as BitcoinTransactionPriority).labelWithRate(rate)}';
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate);
}
return priority.toString();
@ -157,13 +156,13 @@ abstract class SettingsViewModelBase with Store {
handler: (BuildContext context) {
Navigator.of(context).pushNamed(Routes.auth, arguments:
(bool isAuthenticatedSuccessfully, AuthPageState auth) {
auth.close();
if (isAuthenticatedSuccessfully) {
Navigator.of(context).pushNamed(Routes.setupPin, arguments:
(PinCodeState<PinCodeWidget> setupPinContext, String _) {
auth.close(
route: isAuthenticatedSuccessfully ? Routes.setupPin : null,
arguments: (PinCodeState<PinCodeWidget> setupPinContext,
String _) {
setupPinContext.close();
});
}
},
);
});
}),
PickerListItem(

View file

@ -53,6 +53,16 @@ abstract class SupportViewModelBase with Store {
icon: 'assets/images/change_now.png',
linkTitle: 'support@changenow.io',
link: 'mailto:support@changenow.io'),
LinkListItem(
title: 'SideShift',
icon: 'assets/images/sideshift.png',
linkTitle: S.current.help,
link: 'https://help.sideshift.ai/en/'),
LinkListItem(
title: 'SimpleSwap',
icon: 'assets/images/simpleSwap.png',
linkTitle: 'support@simpleswap.io',
link: 'mailto:support@simpleswap.io'),
if (!isMoneroOnly) ... [
LinkListItem(
title: 'Wyre',

View file

@ -25,9 +25,7 @@ dependencies:
mobx: ^2.0.7+4
flutter_mobx: ^2.0.6+1
flutter_slidable: ^2.0.0
share: ^2.0.1
# share_plus: ^4.0.10
# esys_flutter_share: ^1.0.2
share_plus: ^4.0.10
# date_range_picker: ^1.0.6
#https://api.flutter.dev/flutter/material/showDateRangePicker.html
dio: ^4.0.6
@ -54,8 +52,7 @@ dependencies:
connectivity: ^3.0.3
# connectivity_plus: ^2.3.5
keyboard_actions: ^4.0.1
flushbar: ^1.10.4
# check flushbar for replace
another_flushbar: ^1.12.29
archive: ^3.3.0
cryptography: ^2.0.5
file_picker: ^4.6.1
@ -64,6 +61,11 @@ dependencies:
permission_handler: ^10.0.0
device_display_brightness: ^0.0.6
platform_device_id: ^1.0.1
cake_backup:
git:
url: https://github.com/cake-tech/cake_backup.git
ref: main
version: 1.0.0
dev_dependencies:
flutter_test:

View file

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

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Add Custom Redemption",
"remaining": "remaining",
"delete_wallet": "Delete wallet",
"delete_wallet_confirm_message" : "Are you sure that you want to delete ${wallet_name} wallet?"
"delete_wallet_confirm_message" : "Are you sure that you want to delete ${wallet_name} wallet?",
"low_fee": "Low fee",
"low_fee_alert": "You currently are using a low network fee priority. This could cause long waits, different rates, or canceled trades. We recommend setting a higher fee for a better experience.",
"ignor": "Ignore",
"use_suggested": "Use Suggested",
"do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!",
"help": "help"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Agregar redención personalizada",
"remaining": "restante",
"delete_wallet": "Eliminar billetera",
"delete_wallet_confirm_message" : "¿Está seguro de que desea eliminar la billetera ${wallet_name}?"
"delete_wallet_confirm_message" : "¿Está seguro de que desea eliminar la billetera ${wallet_name}?",
"low_fee": "Tarifa baja",
"low_fee_alert": "Actualmente está utilizando una prioridad de tarifa de red baja. Esto podría causar largas esperas, tarifas diferentes o transacciones canceladas. Recomendamos establecer una tarifa más alta para una mejor experiencia.",
"ignor": "Pasar por alto",
"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!",
"help": "ayuda"
}

View file

@ -643,5 +643,11 @@
"add_custom_redemption": "Ajouter un remboursement personnalisé",
"remaining": "restant",
"delete_wallet": "Supprimer le portefeuille",
"delete_wallet_confirm_message" : "Êtes-vous sûr de vouloir supprimer le portefeuille ${wallet_name}?"
"delete_wallet_confirm_message" : "Êtes-vous sûr de vouloir supprimer le portefeuille ${wallet_name}?",
"low_fee": "Frais modiques",
"low_fee_alert": "Vous utilisez actuellement une priorité de frais de réseau peu élevés. Cela pourrait entraîner de longues attentes, des taux différents ou des transactions annulées. Nous vous recommandons de fixer des frais plus élevés pour une meilleure expérience.",
"ignor": "Ignorer",
"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!",
"help": "aider"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "कस्टम रिडेम्पशन जोड़ें",
"remaining": "शेष",
"delete_wallet": "वॉलेट हटाएं",
"delete_wallet_confirm_message" : "क्या आप वाकई ${wallet_name} वॉलेट हटाना चाहते हैं?"
"delete_wallet_confirm_message" : "क्या आप वाकई ${wallet_name} वॉलेट हटाना चाहते हैं?",
"low_fee": "कम शुल्क",
"low_fee_alert": "आप वर्तमान में कम नेटवर्क शुल्क प्राथमिकता का उपयोग कर रहे हैं। यह लंबे इंतजार, अलग-अलग दरों या रद्द किए गए ट्रेडों का कारण बन सकता है। हम बेहतर अनुभव के लिए अधिक शुल्क निर्धारित करने की सलाह देते हैं।",
"ignor": "नज़रअंदाज़ करना",
"use_suggested": "सुझाए गए का प्रयोग करें",
"do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!",
"help": "मदद करना"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Dodaj prilagođeni otkup",
"remaining": "preostalo",
"delete_wallet": "Izbriši novčanik",
"delete_wallet_confirm_message" : "Jeste li sigurni da želite izbrisati ${wallet_name} novčanik?"
"delete_wallet_confirm_message" : "Jeste li sigurni da želite izbrisati ${wallet_name} novčanik?",
"low_fee": "Niska naknada",
"low_fee_alert": "Trenutačno koristite niski prioritet mrežne naknade. To bi moglo uzrokovati duga čekanja, različite tečajeve ili otkazane trgovine. Preporučujemo postavljanje veće naknade za bolje iskustvo.",
"ignor": "Zanemariti",
"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!",
"help": "pomozite"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Aggiungi riscatto personalizzato",
"remaining": "rimanente",
"delete_wallet": "Elimina portafoglio",
"delete_wallet_confirm_message" : "Sei sicuro di voler eliminare il portafoglio ${wallet_name}?"
"delete_wallet_confirm_message" : "Sei sicuro di voler eliminare il portafoglio ${wallet_name}?",
"low_fee": "Tariffa bassa",
"low_fee_alert": "Attualmente stai utilizzando una priorità a tariffa di rete bassa. Ciò potrebbe causare lunghe attese, tariffe diverse o operazioni annullate. Ti consigliamo di impostare una tariffa più alta per un'esperienza migliore.",
"ignor": "Ignorare",
"use_suggested": "Usa suggerito",
"do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!",
"help": "aiuto"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "カスタム引き換えを追加",
"remaining": "残り",
"delete_wallet": "ウォレットを削除",
"delete_wallet_confirm_message" : "${wallet_name} ウォレットを削除してもよろしいですか?"
"delete_wallet_confirm_message" : "${wallet_name} ウォレットを削除してもよろしいですか?",
"low_fee": "低料金",
"low_fee_alert": "現在、低ネットワーク料金優先度を使用しています。これにより、長い待ち時間、異なるレート、またはキャンセルされた取引が発生する可能性があります。より良い体験のために、より高い料金を設定することをお勧めします。",
"ignor": "無視",
"use_suggested": "推奨を使用",
"do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます",
"help": "ヘルプ"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "사용자 지정 상환 추가",
"remaining": "남은",
"delete_wallet": "지갑 삭제",
"delete_wallet_confirm_message" : "${wallet_name} 지갑을 삭제하시겠습니까?"
"delete_wallet_confirm_message" : "${wallet_name} 지갑을 삭제하시겠습니까?",
"low_fee": "낮은 수수료",
"low_fee_alert": "현재 낮은 네트워크 요금 우선 순위를 사용하고 있습니다. 이로 인해 긴 대기 시간, 다른 요금 또는 취소된 거래가 발생할 수 있습니다. 더 나은 경험을 위해 더 높은 요금을 설정하는 것이 좋습니다.",
"ignor": "무시하다",
"use_suggested": "추천 사용",
"do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!",
"help": "돕다"
}

View file

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

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Dodaj niestandardowe wykorzystanie",
"remaining": "pozostałe",
"delete_wallet": "Usuń portfel",
"delete_wallet_confirm_message" : "Czy na pewno chcesz usunąć portfel ${wallet_name}?"
"delete_wallet_confirm_message" : "Czy na pewno chcesz usunąć portfel ${wallet_name}?",
"low_fee": "Niska opłata",
"low_fee_alert": "Obecnie korzystasz z niskiego priorytetu opłaty sieciowej. Może to spowodować długie oczekiwanie, różne stawki lub anulowane transakcje. Zalecamy ustawienie wyższej opłaty, aby zapewnić lepsze wrażenia.",
"ignor": "Ignorować",
"use_suggested": "Użyj sugerowane",
"do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!",
"help": "pomoc"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Adicionar resgate personalizado",
"remaining": "restante",
"delete_wallet": "Excluir carteira",
"delete_wallet_confirm_message" : "Tem certeza de que deseja excluir a carteira ${wallet_name}?"
"delete_wallet_confirm_message" : "Tem certeza de que deseja excluir a carteira ${wallet_name}?",
"low_fee": "Taxa baixa",
"low_fee_alert": "No momento, você está usando uma prioridade de taxa de rede baixa. Isso pode causar longas esperas, taxas diferentes ou negociações canceladas. Recomendamos definir uma taxa mais alta para uma melhor experiência.",
"ignor": "Ignorar",
"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!",
"help": "ajuda"
}

View file

@ -645,5 +645,11 @@
"add_custom_redemption": "Добавить пользовательское погашение",
"remaining": "осталось",
"delete_wallet": "Удалить кошелек",
"delete_wallet_confirm_message" : "Вы уверены, что хотите удалить кошелек ${wallet_name}?"
"delete_wallet_confirm_message" : "Вы уверены, что хотите удалить кошелек ${wallet_name}?",
"low_fee": "Низкая комиссия",
"low_fee_alert": "В настоящее время вы используете низкий приоритет платы за сеть. Это может привести к длительному ожиданию, изменению ставок или отмене сделок. Мы рекомендуем установить более высокую плату для лучшего опыта.",
"ignor": "Игнорировать",
"use_suggested": "Использовать предложенный",
"do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!",
"help": "помощь"
}

View file

@ -644,5 +644,11 @@
"add_custom_redemption": "Додати спеціальне погашення",
"remaining": "залишилося",
"delete_wallet": "Видалити гаманець",
"delete_wallet_confirm_message" : "Ви впевнені, що хочете видалити гаманець ${wallet_name}?"
"delete_wallet_confirm_message" : "Ви впевнені, що хочете видалити гаманець ${wallet_name}?",
"low_fee": "Низька плата",
"low_fee_alert": "Зараз ви використовуєте низький пріоритет плати за мережу. Це може спричинити тривале очікування, інший курс або скасування угод. Ми рекомендуємо встановити вищу плату для кращого досвіду.",
"ignor": "Ігнорувати",
"use_suggested": "Використати запропоноване",
"do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!",
"help": "допомога"
}

View file

@ -643,5 +643,11 @@
"add_custom_redemption": "添加自定义兑换",
"remaining": "剩余",
"delete_wallet": "删除钱包",
"delete_wallet_confirm_message" : "您确定要删除 ${wallet_name} 钱包吗?"
"delete_wallet_confirm_message" : "您确定要删除 ${wallet_name} 钱包吗?",
"low_fee": "费用低",
"low_fee_alert": "您当前正在使用低网络费用优先级。这可能会导致长时间等待、不同的费率或取消交易。我们建议设置更高的费用以获得更好的体验。",
"ignor": "忽视",
"use_suggested": "使用建议",
"do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢",
"help": "帮助"
}

8
scripts/android/app_env.sh Executable file → Normal file
View file

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

8
scripts/ios/app_env.sh Executable file → Normal file
View file

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

View file

@ -86,11 +86,16 @@ abstract class Bitcoin {
String formatterBitcoinAmountToString({required int amount});
double formatterBitcoinAmountToDouble({required int amount});
int formatterStringDoubleToBitcoinAmount(String amount);
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate);
List<Unspent> getUnspents(Object wallet);
void updateUnspents(Object wallet);
WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
TransactionPriority getBitcoinTransactionPriorityMedium();
TransactionPriority getLitecoinTransactionPriorityMedium();
TransactionPriority getBitcoinTransactionPrioritySlow();
TransactionPriority getLitecoinTransactionPrioritySlow();
}
""";
@ -217,6 +222,8 @@ abstract class Monero {
int getHeigthByDate({required DateTime date});
TransactionPriority getDefaultTransactionPriority();
TransactionPriority getMoneroTransactionPrioritySlow();
TransactionPriority getMoneroTransactionPriorityAutomatic();
TransactionPriority deserializeMoneroTransactionPriority({required int raw});
List<TransactionPriority> getTransactionPriorities();
List<String> getMoneroWordList(String language);

View file

@ -25,7 +25,9 @@ class SecretKey {
SecretKey('moonPaySecretKey', () => ''),
SecretKey('sideShiftAffiliateId', () => ''),
SecretKey('sideShiftApiKey', () => ''),
SecretKey('simpleSwapApiKey', () => '')
SecretKey('simpleSwapApiKey', () => ''),
SecretKey('anypayToken', () => ''),
SecretKey('onramperApiKey', () => ''),
];
final String name;