Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-78-Ethereum

 Conflicts:
	lib/di.dart
	lib/store/settings_store.dart
This commit is contained in:
OmarHatem 2023-05-23 22:56:22 +03:00
commit 0a76686c96
112 changed files with 4654 additions and 1288 deletions

View file

@ -5,9 +5,10 @@
## Links
* Website: https://cakewallet.com
* App Store: https://cakewallet.com/ios
* App Store (iOS / MacOS): https://cakewallet.com/ios
* Google Play: https://cakewallet.com/gp
* APK: https://github.com/cake-tech/cake_wallet/releases
* Linux: https://github.com/cake-tech/cake_wallet/releases
## Features
@ -15,18 +16,22 @@
* Completely noncustodial. *Your keys, your coins.*
* Built-in exchange for dozens of pairs
* Buy cryptocurrency with credit/debit/bank
* Easily pay cryptocurrency invoices with fixed rate exchanges
* Buy cryptocurrency (BTC/LTC/XMR) with credit/debit/bank
* Sell cryptocurrency by bank transfer
* Purchase gift cards at a discount using only an email with [Cake Pay](https://cakepay.com), available in-app
* Scan QR codes for easy cryptocurrency transfers
* Create several wallets
* Select your own custom nodes/servers
* Address book
* Backup to external location or iCloud
* Send to OpenAlias, Unstoppable Domains, Yats, and FIO Crypto Handles
* Set custom fee levels
* Set desired network fee level
* Store local transaction notes
* Extremely simple user experience
* Convenient exchange and sending templates for recurring payments
* Create donation links and invoices in the receive screen
* Robust privacy settings (eg: Tor-only connections)
### Monero Specific Features
@ -34,13 +39,13 @@
* Full support for Monero subaddresses and accounts
* Specify restore height for faster syncing
* Specify multiple recipients for batch sending
* Optionally set Monero nodes as trusted for faster syncing
### Bitcoin Specific Features
* Bitcoin coin control (specify specific outputs to spend)
* Automatically generate new addresses
* Specify multiple recipients for batch sending
* Buy BTC with over a dozen fiat currencies
* Sell BTC for USD
### Litecoin Specific Features
@ -48,7 +53,6 @@
* Litecoin coin control (specify specific outputs to spend)
* Automatically generate new addresses
* Specify multiple recipients for batch sending
* Buy LTC with over a dozen fiat currencies
### Haven Specific Features
@ -63,7 +67,7 @@
## Links
* Website: https://monero.com
* App Store: https://apps.apple.com/app/id1601990386
* App Store (iOS): https://apps.apple.com/app/id1601990386
* Google Play: https://play.google.com/store/apps/details?id=com.monero.app
* APK: https://github.com/cake-tech/cake_wallet/releases
@ -71,6 +75,8 @@
We have 24/7 free support. Please contact support@cakewallet.com
We have excellent user guides, which are also open-source and open for contributions: https://guides.cakewallet.com
# Build Instructions
More instructions to follow
@ -136,3 +142,7 @@ The only parts to be translated, if needed, are the values m and s after the var
3. Add the raw mapping underneath in `lib/entities/fiat_currency.dart` following the same format as the others.
4. Add a flag of the issuing country or organization to `assets/images/flags/XXXX.png`, replacing XXXX with the ISO 3166-1 alpha-3 code used above (eg: `usa.png`, `eur.png`). Do not add this if the flag with the same name already exists. The image must be 42x26 pixels with a 3 pixels of transparent margin on all 4 sides.
---
Copyright (C) 2018-2023 Cake Labs LLC

View file

@ -46,8 +46,14 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bitcoin" />
<data android:scheme="bitcoin-wallet" />
<data android:scheme="bitcoin_wallet" />
<data android:scheme="monero" />
<data android:scheme="monero-wallet" />
<data android:scheme="monero_wallet" />
<data android:scheme="litecoin" />
<data android:scheme="litecoin-wallet" />
<data android:scheme="litecoin_wallet" />
</intent-filter>
</activity>
<meta-data

BIN
assets/images/flags/hau.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1 +1,3 @@
Fix Restore from QR code
Reliability fixes for PIN login, transaction appearance, keyboard inputs, and QR codes
Show amount received by each Monero account in account overview
Other bugfixes

View file

@ -1,4 +1,3 @@
Fix for QR codes
Fix for creating sub-addresses
Fix Add/Edit nodes
Fix issues with text/amount fields
Reliability fixes for PIN login, transaction appearance, keyboard inputs, and QR codes
Show amount received by each Monero account in account overview
Other bugfixes

View file

@ -88,7 +88,7 @@ class ElectrumClient {
unterminatedString = '';
}
} on TypeError catch (e) {
if (!e.toString().contains('Map<String, Object>') || !e.toString().contains('Map<String, dynamic>')) {
if (!e.toString().contains('Map<String, Object>') && !e.toString().contains('Map<String, dynamic>')) {
return;
}

View file

@ -1,10 +1,12 @@
class Account {
Account({required this.id, required this.label});
Account({required this.id, required this.label, this.balance});
Account.fromMap(Map<String, Object> map)
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
this.label = (map['label'] ?? '') as String;
this.label = (map['label'] ?? '') as String,
this.balance = (map['balance'] ?? '0.00') as String;
final int id;
final String label;
final String? balance;
}

View file

@ -2,5 +2,6 @@ import 'package:flutter/services.dart';
const utils = const MethodChannel('com.cake_wallet/native_utils');
void setIsAppSecureNative(bool isAppSecure) =>
utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
void setIsAppSecureNative(bool isAppSecure) {
utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
}

View file

@ -1,6 +1,8 @@
import 'package:cw_core/monero_amount_format.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/account.dart';
import 'package:cw_monero/api/account_list.dart' as account_list;
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
part 'monero_account_list.g.dart';
@ -41,12 +43,16 @@ abstract class MoneroAccountListBase with Store {
}
}
List<Account> getAll() => account_list
.getAllAccount()
.map((accountRow) => Account(
id: accountRow.getId(),
label: accountRow.getLabel()))
.toList();
List<Account> getAll() => account_list.getAllAccount().map((accountRow) {
final accountIndex = accountRow.getId();
final balance = monero_wallet.getFullBalance(accountIndex: accountIndex);
return Account(
id: accountRow.getId(),
label: accountRow.getLabel(),
balance: moneroAmountToString(amount: balance),
);
}).toList();
Future<void> addAccount({required String label}) async {
await account_list.addAccount(label: label);
@ -54,8 +60,7 @@ abstract class MoneroAccountListBase with Store {
}
Future<void> setLabelAccount({required int accountIndex, required String label}) async {
await account_list.setLabelForAccount(
accountIndex: accountIndex, label: label);
await account_list.setLabelForAccount(accountIndex: accountIndex, label: label);
update();
}

View file

@ -113,7 +113,7 @@ PODS:
- OrderedSet (~> 5.0)
- flutter_mailer (0.0.1):
- Flutter
- flutter_secure_storage (3.3.1):
- flutter_secure_storage (6.0.0):
- Flutter
- in_app_review (0.2.0):
- Flutter
@ -264,19 +264,19 @@ SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
SDWebImage: fd7e1a22f00303e058058278639bf6196ee431fe
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
SwiftProtobuf: afced68785854575756db965e9da52bbf3dc45e7
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a

View file

@ -15,6 +15,8 @@ import UnstoppableDomainsResolution
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
makeSecure()
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let legacyMigrationChannel = FlutterMethodChannel(
@ -96,21 +98,39 @@ import UnstoppableDomainsResolution
result(address)
}
case "setIsAppSecure":
guard let args = call.arguments as? Dictionary<String, Bool>,
let isAppSecure = args["isAppSecure"] else {
result(nil)
return
}
if isAppSecure {
self?.textField.isSecureTextEntry = true
} else {
self?.textField.isSecureTextEntry = false
}
result(nil)
default:
result(FlutterMethodNotImplemented)
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private var textField = UITextField()
private func makeSecure() {
if (!self.window.subviews.contains(textField)) {
self.window.addSubview(textField)
textField.centerYAnchor.constraint(equalTo: self.window.centerYAnchor).isActive = true
textField.centerXAnchor.constraint(equalTo: self.window.centerXAnchor).isActive = true
self.window.layer.superlayer?.addSublayer(textField.layer)
textField.layer.sublayers?.first?.addSublayer(self.window.layer)
}
}
override func applicationWillResignActive(_: UIApplication ) {
self.window?.isHidden = true;
}
override func applicationDidBecomeActive(_: UIApplication) {
self.window?.isHidden = false;
}
}

View file

@ -42,6 +42,16 @@
<string>bitcoin</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>bitcoin-wallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>bitcoin-wallet</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
@ -52,6 +62,16 @@
<string>monero</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>monero-wallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>monero-wallet</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
@ -62,6 +82,16 @@
<string>litecoin</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>CFBundleURLName</key>
<string>litecoin-wallet</string>
<key>CFBundleURLSchemes</key>
<array>
<string>litecoin-wallet</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
class OnRamperBuyProvider {
@ -13,7 +14,16 @@ class OnRamperBuyProvider {
static const _baseUrl = 'buy.onramper.com';
static String get _apiKey => secrets.onramperApiKey;
String get _apiKey => secrets.onramperApiKey;
String get _normalizeCryptoCurrency {
switch (_wallet.currency) {
case CryptoCurrency.ltc:
return "LTC_LITECOIN";
default:
return _wallet.currency.title;
}
}
Uri requestUrl() {
String primaryColor,
@ -53,7 +63,7 @@ class OnRamperBuyProvider {
return Uri.https(_baseUrl, '', <String, dynamic>{
'apiKey': _apiKey,
'defaultCrypto': _wallet.currency.title,
'defaultCrypto': _normalizeCryptoCurrency,
'defaultFiat': _settingsStore.fiatCurrency.title,
'wallets': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
'supportSell': "false",

View file

@ -1,4 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/validator.dart';
import 'package:cw_core/crypto_currency.dart';
@ -7,6 +7,9 @@ class AddressValidator extends TextValidator {
AddressValidator({required CryptoCurrency type})
: super(
errorMessage: S.current.error_text_address,
useAdditionalValidation: type == CryptoCurrency.btc
? bitcoin.Address.validateAddress
: null,
pattern: getPattern(type),
length: getLength(type));
@ -18,8 +21,7 @@ class AddressValidator extends TextValidator {
return '^[0-9a-zA-Z]{59}\$|^[0-9a-zA-Z]{92}\$|^[0-9a-zA-Z]{104}\$'
'|^[0-9a-zA-Z]{105}\$|^addr1[0-9a-zA-Z]{98}\$';
case CryptoCurrency.btc:
return '^1[0-9a-zA-Z]{32}\$|^1[0-9a-zA-Z]{33}\$|^3[0-9a-zA-Z]{32}\$'
'|^3[0-9a-zA-Z]{33}\$|^bc1[0-9a-zA-Z]{39}\$|^bc1[0-9a-zA-Z]{59}\$';
return '^3[0-9a-zA-Z]{32}\$|^3[0-9a-zA-Z]{33}\$|^bc1[0-9a-zA-Z]{59}\$';
case CryptoCurrency.nano:
return '[0-9a-zA-Z_]';
case CryptoCurrency.usdc:
@ -63,7 +65,7 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.bch:
case CryptoCurrency.bnb:
return '[0-9a-zA-Z]';
case CryptoCurrency.hbar:
case CryptoCurrency.hbar:
return '[0-9a-zA-Z.]';
case CryptoCurrency.zaddr:
return '^zs[0-9a-zA-Z]{75}';
@ -165,9 +167,9 @@ class AddressValidator extends TextValidator {
return [34];
case CryptoCurrency.hbar:
return [4, 5, 6, 7, 8, 9, 10, 11];
case CryptoCurrency.xvg:
case CryptoCurrency.xvg:
return [34];
case CryptoCurrency.zen:
case CryptoCurrency.zen:
return [35];
case CryptoCurrency.zaddr:
return null;

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:flutter/material.dart';
@ -9,6 +10,8 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/store/settings_store.dart';
import '../src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
class AuthService with Store {
AuthService({
required this.secureStorage,
@ -20,6 +23,8 @@ class AuthService with Store {
Routes.showKeys,
Routes.backup,
Routes.setupPin,
Routes.setup_2faPage,
Routes.modify2FAPage,
];
final FlutterSecureStorage secureStorage;
@ -79,6 +84,7 @@ class AuthService with Store {
{Function(bool)? onAuthSuccess, String? route, Object? arguments}) async {
assert(route != null || onAuthSuccess != null,
'Either route or onAuthSuccess param must be passed.');
if (!requireAuth() && !_alwaysAuthenticateRoutes.contains(route)) {
if (onAuthSuccess != null) {
onAuthSuccess(true);
@ -90,17 +96,43 @@ class AuthService with Store {
}
return;
}
Navigator.of(context).pushNamed(Routes.auth,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
if (!isAuthenticatedSuccessfully) {
onAuthSuccess?.call(false);
return;
}
if (onAuthSuccess != null) {
auth.close().then((value) => onAuthSuccess.call(true));
} else {
auth.close(route: route, arguments: arguments);
if (settingsStore.useTOTP2FA) {
auth.close(
route: Routes.totpAuthCodePage,
arguments: TotpAuthArgumentsModel(
isForSetup: !settingsStore.useTOTP2FA,
onTotpAuthenticationFinished:
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) async {
if (!isAuthenticatedSuccessfully) {
onAuthSuccess?.call(false);
return;
}
if (onAuthSuccess != null) {
totpAuth.close().then((value) => onAuthSuccess.call(true));
} else {
totpAuth.close(route: route, arguments: arguments);
}
},
),
);
} else {
if (onAuthSuccess != null) {
auth.close().then((value) => onAuthSuccess.call(true));
} else {
auth.close(route: route, arguments: arguments);
}
}
}
});
});
}
}

View file

@ -210,6 +210,8 @@ class BackupService {
final currentFiatCurrency = data[PreferencesKey.currentFiatCurrencyKey] as String?;
final shouldSaveRecipientAddress = data[PreferencesKey.shouldSaveRecipientAddressKey] as bool?;
final isAppSecure = data[PreferencesKey.isAppSecureKey] as bool?;
final disableBuy = data[PreferencesKey.disableBuyKey] as bool?;
final disableSell = data[PreferencesKey.disableSellKey] as bool?;
final currentTransactionPriorityKeyLegacy = data[PreferencesKey.currentTransactionPriorityKeyLegacy] as int?;
final allowBiometricalAuthentication = data[PreferencesKey.allowBiometricalAuthenticationKey] as bool?;
final currentBitcoinElectrumSererId = data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int?;
@ -251,6 +253,16 @@ class BackupService {
PreferencesKey.isAppSecureKey,
isAppSecure);
if (disableBuy != null)
await _sharedPreferences.setBool(
PreferencesKey.disableBuyKey,
disableBuy);
if (disableSell != null)
await _sharedPreferences.setBool(
PreferencesKey.disableSellKey,
disableSell);
if (currentTransactionPriorityKeyLegacy != null)
await _sharedPreferences.setInt(
PreferencesKey.currentTransactionPriorityKeyLegacy,
@ -421,6 +433,10 @@ class BackupService {
_sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey),
PreferencesKey.shouldSaveRecipientAddressKey: _sharedPreferences
.getBool(PreferencesKey.shouldSaveRecipientAddressKey),
PreferencesKey.disableBuyKey: _sharedPreferences
.getBool(PreferencesKey.disableBuyKey),
PreferencesKey.disableSellKey: _sharedPreferences
.getBool(PreferencesKey.disableSellKey),
PreferencesKey.isDarkThemeLegacy:
_sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy),
PreferencesKey.currentPinLength:

View file

@ -0,0 +1,13 @@
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
class TotpAuthArgumentsModel {
final bool? isForSetup;
final bool? isClosable;
final OnTotpAuthenticationFinished? onTotpAuthenticationFinished;
TotpAuthArgumentsModel({
this.isForSetup,
this.isClosable,
this.onTotpAuthenticationFinished,
});
}

View file

@ -1,24 +1,26 @@
import 'package:flutter/foundation.dart';
abstract class Validator<T> {
Validator({required this.errorMessage});
Validator({required this.errorMessage, this.useAdditionalValidation});
final String errorMessage;
final bool Function(T)? useAdditionalValidation;
bool isValid(T? value);
String? call(T? value) => !isValid(value) ? errorMessage : null;
String? call(T? value) => !isValid(value) ? errorMessage : null;
}
class TextValidator extends Validator<String> {
TextValidator(
{this.minLength,
this.maxLength,
this.pattern,
String errorMessage = '',
this.length,
this.isAutovalidate = false})
: super(errorMessage: errorMessage);
TextValidator({
bool Function(String)? useAdditionalValidation,
this.minLength,
this.maxLength,
this.pattern,
String errorMessage = '',
this.length,
this.isAutovalidate = false,
}) : super(
errorMessage: errorMessage,
useAdditionalValidation: useAdditionalValidation);
final int? minLength;
final int? maxLength;
@ -32,11 +34,26 @@ class TextValidator extends Validator<String> {
return isAutovalidate ? true : false;
}
return value.length > (minLength ?? 0) &&
(length?.contains(value.length) ?? true) &&
((maxLength ?? 0) > 0 ? (value.length <= maxLength!) : true) &&
(pattern != null ? match(value) : true);
final greaterThanMinLength = value.length > (minLength ?? 0);
if (!greaterThanMinLength) return false;
final lengthMatched = length?.contains(value.length) ?? true;
if (!lengthMatched) return false;
final lowerThanMaxLength =
(maxLength ?? 0) > 0 ? (value.length <= maxLength!) : true;
if (!lowerThanMaxLength) return false;
if (pattern == null) return true;
final valueMatched = match(value);
final valueValidated = useAdditionalValidation != null
? useAdditionalValidation!(value) || valueMatched
: valueMatched;
return valueValidated;
}
bool match(String value) => pattern != null ? RegExp(pattern!).hasMatch(value) : false;
bool match(String value) =>
pattern != null ? RegExp(pattern!).hasMatch(value) : false;
}

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/ethereum/ethereum.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/routes.dart';
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
@ -28,6 +29,10 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
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';
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
import 'package:cake_wallet/themes/theme_list.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
@ -54,8 +59,8 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
@ -188,6 +193,8 @@ import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/qr_view_data.dart';
import 'core/totp_request_details.dart';
final getIt = GetIt.instance;
var _isSetupFinished = false;
@ -202,18 +209,18 @@ late Box<Order> _ordersSource;
late Box<UnspentCoinsInfo>? _unspentCoinsInfoSource;
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
Future setup(
{required Box<WalletInfo> walletInfoSource,
required Box<Node> nodeSource,
required Box<Contact> contactSource,
required Box<Trade> tradesSource,
required Box<Template> templates,
required Box<ExchangeTemplate> exchangeTemplates,
required Box<TransactionDescription> transactionDescriptionBox,
required Box<Order> ordersSource,
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
}) async {
Future setup({
required Box<WalletInfo> walletInfoSource,
required Box<Node> nodeSource,
required Box<Contact> contactSource,
required Box<Trade> tradesSource,
required Box<Template> templates,
required Box<ExchangeTemplate> exchangeTemplates,
required Box<TransactionDescription> transactionDescriptionBox,
required Box<Order> ordersSource,
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
}) async {
_walletInfoSource = walletInfoSource;
_nodeSource = nodeSource;
_contactSource = contactSource;
@ -226,8 +233,7 @@ Future setup(
_anonpayInvoiceInfoSource = anonpayInvoiceInfoSource;
if (!_isSetupFinished) {
getIt.registerSingletonAsync<SharedPreferences>(
() => SharedPreferences.getInstance());
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
}
final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty ?? false) &&
@ -257,84 +263,73 @@ Future setup(
walletList: getIt.get<WalletListStore>(),
settingsStore: getIt.get<SettingsStore>(),
nodeListStore: getIt.get<NodeListStore>()));
getIt.registerSingleton<TradesStore>(TradesStore(
tradesSource: _tradesSource, settingsStore: getIt.get<SettingsStore>()));
getIt.registerSingleton<OrdersStore>(OrdersStore(
ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
getIt.registerSingleton<TradesStore>(
TradesStore(tradesSource: _tradesSource, settingsStore: getIt.get<SettingsStore>()));
getIt.registerSingleton<OrdersStore>(
OrdersStore(ordersSource: _ordersSource, settingsStore: getIt.get<SettingsStore>()));
getIt.registerSingleton<TradeFilterStore>(TradeFilterStore());
getIt.registerSingleton<TransactionFilterStore>(TransactionFilterStore());
getIt.registerSingleton<FiatConversionStore>(FiatConversionStore());
getIt.registerSingleton<SendTemplateStore>(
SendTemplateStore(templateSource: _templates));
getIt.registerSingleton<SendTemplateStore>(SendTemplateStore(templateSource: _templates));
getIt.registerSingleton<ExchangeTemplateStore>(
ExchangeTemplateStore(templateSource: _exchangeTemplates));
getIt.registerSingleton<YatStore>(YatStore(
appStore: getIt.get<AppStore>(),
secureStorage: getIt.get<FlutterSecureStorage>())
..init());
getIt.registerSingleton<AnonpayTransactionsStore>(AnonpayTransactionsStore(
anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
getIt.registerSingleton<YatStore>(
YatStore(appStore: getIt.get<AppStore>(), secureStorage: getIt.get<FlutterSecureStorage>())
..init());
getIt.registerSingleton<AnonpayTransactionsStore>(
AnonpayTransactionsStore(anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
final secretStore =
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
final secretStore = await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
getIt.registerSingleton<SecretStore>(secretStore);
getIt.registerFactory<KeyService>(
() => KeyService(getIt.get<FlutterSecureStorage>()));
getIt.registerFactory<KeyService>(() => KeyService(getIt.get<FlutterSecureStorage>()));
getIt.registerFactoryParam<WalletCreationService, WalletType, void>(
(type, _) => WalletCreationService(
getIt.registerFactoryParam<WalletCreationService, WalletType, void>((type, _) =>
WalletCreationService(
initialType: type,
keyService: getIt.get<KeyService>(),
secureStorage: getIt.get<FlutterSecureStorage>(),
sharedPreferences: getIt.get<SharedPreferences>(),
walletInfoSource: _walletInfoSource));
getIt.registerFactory<WalletLoadingService>(
() => WalletLoadingService(
getIt.registerFactory<WalletLoadingService>(() => WalletLoadingService(
getIt.get<SharedPreferences>(),
getIt.get<KeyService>(),
(WalletType type) => getIt.get<WalletService>(param1: type)));
getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) =>
WalletNewVM(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
type: type));
getIt.registerFactoryParam<WalletNewVM, WalletType, void>((type, _) => WalletNewVM(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
type: type));
getIt
.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) {
getIt.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) {
final type = args.first as WalletType;
final language = args[1] as String;
final mnemonic = args[2] as String;
return WalletRestorationFromSeedVM(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
return WalletRestorationFromSeedVM(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
type: type, language: language, seed: mnemonic);
});
getIt
.registerFactoryParam<WalletRestorationFromKeysVM, List, void>((args, _) {
getIt.registerFactoryParam<WalletRestorationFromKeysVM, List, void>((args, _) {
final type = args.first as WalletType;
final language = args[1] as String;
return WalletRestorationFromKeysVM(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
return WalletRestorationFromKeysVM(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
type: type, language: language);
});
getIt
.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type),
_walletInfoSource, type);
getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
});
getIt.registerFactory<WalletAddressListViewModel>(() =>
WalletAddressListViewModel(
appStore: getIt.get<AppStore>(), yatStore: getIt.get<YatStore>(),
fiatConversionStore: getIt.get<FiatConversionStore>()
));
getIt.registerFactory<WalletAddressListViewModel>(() => WalletAddressListViewModel(
appStore: getIt.get<AppStore>(),
yatStore: getIt.get<YatStore>(),
fiatConversionStore: getIt.get<FiatConversionStore>()));
getIt.registerFactory(() => BalanceViewModel(
appStore: getIt.get<AppStore>(),
@ -350,65 +345,108 @@ Future setup(
settingsStore: settingsStore,
yatStore: getIt.get<YatStore>(),
ordersStore: getIt.get<OrdersStore>(),
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>())
);
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>()));
getIt.registerFactory<AuthService>(() => AuthService(
getIt.registerFactory<AuthService>(
() => AuthService(
secureStorage: getIt.get<FlutterSecureStorage>(),
sharedPreferences: getIt.get<SharedPreferences>(),
settingsStore: getIt.get<SettingsStore>(),
),
);
),
);
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(
getIt.get<AuthService>(),
getIt.get<SharedPreferences>(),
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(getIt.get<AuthService>(),
getIt.get<SharedPreferences>(), getIt.get<SettingsStore>(), BiometricAuth()));
getIt.registerFactoryParam<AuthPage, void Function(bool, AuthPageState), bool>(
(onAuthFinished, closable) => AuthPage(getIt.get<AuthViewModel>(),
onAuthenticationFinished: onAuthFinished, closable: closable));
getIt.registerFactory<Setup2FAViewModel>(
() => Setup2FAViewModel(
getIt.get<SettingsStore>(),
BiometricAuth()));
getIt.get<SharedPreferences>(),
getIt.get<AuthService>(),
),
);
getIt.registerFactory<AuthPage>(
() => AuthPage(getIt.get<AuthViewModel>(), onAuthenticationFinished:
(isAuthenticated, AuthPageState authPageState) {
if (!isAuthenticated) {
return;
}
final authStore = getIt.get<AuthenticationStore>();
final appStore = getIt.get<AppStore>();
getIt.registerFactoryParam<TotpAuthCodePage, TotpAuthArgumentsModel, void>(
(totpAuthPageArguments, _) => TotpAuthCodePage(
getIt.get<Setup2FAViewModel>(),
totpArguments: totpAuthPageArguments,
),
);
if (appStore.wallet != null) {
authStore.allowed();
return;
}
getIt.registerFactory<AuthPage>(() {
return AuthPage(getIt.get<AuthViewModel>(),
onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) {
if (!isAuthenticated) {
return;
} else {
final authStore = getIt.get<AuthenticationStore>();
final appStore = getIt.get<AppStore>();
final useTotp = appStore.settingsStore.useTOTP2FA;
if (useTotp) {
authPageState.close(
route: Routes.totpAuthCodePage,
arguments: TotpAuthArgumentsModel(
isForSetup: false,
isClosable: false,
onTotpAuthenticationFinished: (bool isAuthenticatedSuccessfully,
TotpAuthCodePageState totpAuthPageState) async {
if (!isAuthenticatedSuccessfully) {
return;
}
if (appStore.wallet != null) {
authStore.allowed();
return;
}
authPageState.changeProcessText('Loading the wallet');
totpAuthPageState.changeProcessText('Loading the wallet');
if (loginError != null) {
authPageState
.changeProcessText('ERROR: ${loginError.toString()}');
}
if (loginError != null) {
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
}
ReactionDisposer? _reaction;
_reaction = reaction((_) => appStore.wallet, (Object? _) {
_reaction?.reaction.dispose();
authStore.allowed();
});
}, closable: false),
instanceName: 'login');
ReactionDisposer? _reaction;
_reaction = reaction((_) => appStore.wallet, (Object? _) {
_reaction?.reaction.dispose();
authStore.allowed();
});
},
),
);
} else {
if (appStore.wallet != null) {
authStore.allowed();
return;
}
getIt
.registerFactoryParam<AuthPage, void Function(bool, AuthPageState), bool>(
(onAuthFinished, closable) => AuthPage(getIt.get<AuthViewModel>(),
onAuthenticationFinished: onAuthFinished,
closable: closable));
authPageState.changeProcessText('Loading the wallet');
getIt.registerFactory(() =>
BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
if (loginError != null) {
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
}
ReactionDisposer? _reaction;
_reaction = reaction((_) => appStore.wallet, (Object? _) {
_reaction?.reaction.dispose();
authStore.allowed();
});
}
}
}, closable: false);
}, instanceName: 'login');
getIt.registerFactory(() => BalancePage(
dashboardViewModel: getIt.get<DashboardViewModel>(),
settingsStore: getIt.get<SettingsStore>()));
getIt.registerFactory<DashboardPage>(() => DashboardPage(
balancePage: getIt.get<BalancePage>(),
dashboardViewModel: getIt.get<DashboardViewModel>(),
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
));
balancePage: getIt.get<BalancePage>(),
dashboardViewModel: getIt.get<DashboardViewModel>(),
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
));
getIt.registerFactory<DesktopSidebarWrapper>(() {
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
@ -421,16 +459,26 @@ Future setup(
});
getIt.registerFactoryParam<DesktopDashboardPage, GlobalKey<NavigatorState>, void>(
(desktopKey, _) => DesktopDashboardPage(
balancePage: getIt.get<BalancePage>(),
dashboardViewModel: getIt.get<DashboardViewModel>(),
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
desktopKey: desktopKey,
));
balancePage: getIt.get<BalancePage>(),
dashboardViewModel: getIt.get<DashboardViewModel>(),
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
desktopKey: desktopKey,
));
getIt.registerFactory<TransactionsPage>(() => TransactionsPage(dashboardViewModel: getIt.get<DashboardViewModel>()));
getIt.registerFactory<TransactionsPage>(
() => TransactionsPage(dashboardViewModel: getIt.get<DashboardViewModel>()));
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>((pageOption, _) => ReceiveOptionViewModel(
getIt.get<AppStore>().wallet!, pageOption));
getIt.registerFactory<Setup2FAPage>(
() => Setup2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
getIt.registerFactory<Setup2FAQRPage>(
() => Setup2FAQRPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
getIt.registerFactory<Modify2FAPage>(
() => Modify2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>(
(pageOption, _) => ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, pageOption));
getIt.registerFactoryParam<AnonInvoicePageViewModel, List<dynamic>, void>((args, _) {
final address = args.first as String;
@ -444,28 +492,27 @@ Future setup(
getIt.get<SharedPreferences>(),
pageOption,
);
});
});
getIt.registerFactoryParam<AnonPayInvoicePage, List<dynamic>, void>((List<dynamic> args, _) {
final pageOption = args.last as ReceivePageOption;
return AnonPayInvoicePage(
getIt.get<AnonInvoicePageViewModel>(param1: args),
getIt.get<ReceiveOptionViewModel>(param1: pageOption));
});
return AnonPayInvoicePage(getIt.get<AnonInvoicePageViewModel>(param1: args),
getIt.get<ReceiveOptionViewModel>(param1: pageOption));
});
getIt.registerFactory<ReceivePage>(() => ReceivePage(
addressListViewModel: getIt.get<WalletAddressListViewModel>()));
getIt.registerFactory<ReceivePage>(
() => ReceivePage(addressListViewModel: getIt.get<WalletAddressListViewModel>()));
getIt.registerFactory<AddressPage>(() => AddressPage(
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
dashboardViewModel: getIt.get<DashboardViewModel>(),
receiveOptionViewModel: getIt.get<ReceiveOptionViewModel>()));
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
(WalletAddressListItem? item, _) => WalletAddressEditOrCreateViewModel(
wallet: getIt.get<AppStore>().wallet!, item: item));
(WalletAddressListItem? item, _) =>
WalletAddressEditOrCreateViewModel(wallet: getIt.get<AppStore>().wallet!, item: item));
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
(dynamic item, _) => AddressEditOrCreatePage(
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>((dynamic item, _) =>
AddressEditOrCreatePage(
addressEditOrCreateViewModel:
getIt.get<WalletAddressEditOrCreateViewModel>(param1: item)));
@ -485,15 +532,16 @@ Future setup(
getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
(PaymentRequest? initialPaymentRequest, _) => SendPage(
sendViewModel: getIt.get<SendViewModel>(),
initialPaymentRequest: initialPaymentRequest,
));
sendViewModel: getIt.get<SendViewModel>(),
initialPaymentRequest: initialPaymentRequest,
));
getIt.registerFactory(() => SendTemplatePage(
sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
getIt.registerFactory(
() => SendTemplatePage(sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
if (DeviceInfo.instance.isMobile) {
getIt.registerFactory(() => WalletListViewModel(
getIt.registerFactory(
() => WalletListViewModel(
_walletInfoSource,
getIt.get<AppStore>(),
getIt.get<WalletLoadingService>(),
@ -503,7 +551,8 @@ Future setup(
} else {
// register wallet list view model as singleton on desktop since it can be accessed
// from multiple places at the same time (Wallets DropDown, Wallets List in settings)
getIt.registerLazySingleton(() => WalletListViewModel(
getIt.registerLazySingleton(
() => WalletListViewModel(
_walletInfoSource,
getIt.get<AppStore>(),
getIt.get<WalletLoadingService>(),
@ -512,8 +561,10 @@ Future setup(
);
}
getIt.registerFactory(() =>
WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>(), authService: getIt.get<AuthService>(),));
getIt.registerFactory(() => WalletListPage(
walletListViewModel: getIt.get<WalletListViewModel>(),
authService: getIt.get<AuthService>(),
));
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet!;
@ -522,11 +573,12 @@ Future setup(
return MoneroAccountListViewModel(wallet);
}
throw Exception('Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel');
throw Exception(
'Unexpected wallet type: ${wallet.type} for generate MoneroAccountListViewModel');
});
getIt.registerFactory(() => MoneroAccountListPage(
accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
getIt.registerFactory(
() => MoneroAccountListPage(accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
/*getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
@ -543,16 +595,14 @@ Future setup(
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>()));*/
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
AccountListItem?, void>(
getIt.registerFactoryParam<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?,
void>(
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem?, void>(
(AccountListItem? account, _) => MoneroAccountEditOrCreatePage(
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
@ -573,41 +623,37 @@ Future setup(
return SecuritySettingsViewModel(getIt.get<SettingsStore>(), getIt.get<AuthService>());
});
getIt
.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
getIt.registerFactoryParam<WalletSeedPage, bool, void>(
(bool isWalletCreated, _) => WalletSeedPage(
getIt.get<WalletSeedViewModel>(),
isNewWalletCreated: isWalletCreated));
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
getIt
.registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>()));
getIt.registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>()));
getIt.registerFactory(() => WalletKeysPage(getIt.get<WalletKeysViewModel>()));
getIt.registerFactoryParam<ContactViewModel, ContactRecord?, void>(
(ContactRecord? contact, _) =>
ContactViewModel(_contactSource, contact: contact));
(ContactRecord? contact, _) => ContactViewModel(_contactSource, contact: contact));
getIt.registerFactoryParam<ContactListViewModel, CryptoCurrency?, void>(
(CryptoCurrency? cur, _) => ContactListViewModel(_contactSource, _walletInfoSource, cur));
getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>((CryptoCurrency? cur, _)
=> ContactListPage(getIt.get<ContactListViewModel>(param1: cur)));
getIt.registerFactoryParam<ContactListPage, CryptoCurrency?, void>(
(CryptoCurrency? cur, _) => ContactListPage(getIt.get<ContactListViewModel>(param1: cur)));
getIt.registerFactoryParam<ContactPage, ContactRecord?, void>(
(ContactRecord? contact, _) =>
ContactPage(getIt.get<ContactViewModel>(param1: contact)));
(ContactRecord? contact, _) => ContactPage(getIt.get<ContactViewModel>(param1: contact)));
getIt.registerFactory(() {
final appStore = getIt.get<AppStore>();
return NodeListViewModel(_nodeSource, appStore);
});
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
getIt.registerFactory(
() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
getIt.registerFactory(() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
getIt.registerFactory(
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
@ -615,41 +661,38 @@ Future setup(
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>(
(WalletType? type, _) => NodeCreateOrEditViewModel(
_nodeSource,
type ?? getIt.get<AppStore>().wallet!.type,
getIt.get<SettingsStore>()
));
getIt.registerFactoryParam<NodeCreateOrEditViewModel, WalletType?, void>((WalletType? type, _) =>
NodeCreateOrEditViewModel(
_nodeSource, type ?? getIt.get<AppStore>().wallet!.type, getIt.get<SettingsStore>()));
getIt.registerFactoryParam<NodeCreateOrEditPage, Node?, bool?>(
(Node? editingNode, bool? isSelected) => NodeCreateOrEditPage(
(Node? editingNode, bool? isSelected) => NodeCreateOrEditPage(
nodeCreateOrEditViewModel: getIt.get<NodeCreateOrEditViewModel>(),
editingNode: editingNode,
isSelected: isSelected));
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!,
));
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!,
));
getIt.registerFactory(() => OnRamperPage(getIt.get<OnRamperBuyProvider>()));
getIt.registerFactory<PayfuraBuyProvider>(() => PayfuraBuyProvider(
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!,
));
settingsStore: getIt.get<AppStore>().settingsStore,
wallet: getIt.get<AppStore>().wallet!,
));
getIt.registerFactory(() => PayFuraPage(getIt.get<PayfuraBuyProvider>()));
getIt.registerFactory(() => ExchangeViewModel(
getIt.get<AppStore>().wallet!,
_tradesSource,
getIt.get<ExchangeTemplateStore>(),
getIt.get<TradesStore>(),
getIt.get<AppStore>().settingsStore,
getIt.get<SharedPreferences>(),
));
getIt.get<AppStore>().wallet!,
_tradesSource,
getIt.get<ExchangeTemplateStore>(),
getIt.get<TradesStore>(),
getIt.get<AppStore>().settingsStore,
getIt.get<SharedPreferences>(),
));
getIt.registerFactory(() => ExchangeTradeViewModel(
wallet: getIt.get<AppStore>().wallet!,
@ -659,28 +702,23 @@ Future setup(
getIt.registerFactory(() => ExchangePage(getIt.get<ExchangeViewModel>()));
getIt.registerFactory(
() => ExchangeConfirmPage(tradesStore: getIt.get<TradesStore>()));
getIt.registerFactory(() => ExchangeTradePage(
exchangeTradeViewModel: getIt.get<ExchangeTradeViewModel>()));
getIt.registerFactory(() => ExchangeConfirmPage(tradesStore: getIt.get<TradesStore>()));
getIt.registerFactory(
() => ExchangeTemplatePage(getIt.get<ExchangeViewModel>()));
() => ExchangeTradePage(exchangeTradeViewModel: getIt.get<ExchangeTradeViewModel>()));
getIt.registerFactoryParam<WalletService, WalletType, void>(
(WalletType param1, __) {
getIt.registerFactory(() => ExchangeTemplatePage(getIt.get<ExchangeViewModel>()));
getIt.registerFactoryParam<WalletService, WalletType, void>((WalletType param1, __) {
switch (param1) {
case WalletType.haven:
return haven!.createHavenWalletService(_walletInfoSource);
case WalletType.monero:
return monero!.createMoneroWalletService(_walletInfoSource);
case WalletType.bitcoin:
return bitcoin!.createBitcoinWalletService(
_walletInfoSource, _unspentCoinsInfoSource!);
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
case WalletType.litecoin:
return bitcoin!.createLitecoinWalletService(
_walletInfoSource, _unspentCoinsInfoSource!);
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!);
case WalletType.ethereum:
return ethereum!.createEthereumWalletService(_walletInfoSource);
default:
@ -688,13 +726,12 @@ Future setup(
}
});
getIt.registerFactory<SetupPinCodeViewModel>(() => SetupPinCodeViewModel(
getIt.get<AuthService>(), getIt.get<SettingsStore>()));
getIt.registerFactory<SetupPinCodeViewModel>(
() => SetupPinCodeViewModel(getIt.get<AuthService>(), getIt.get<SettingsStore>()));
getIt.registerFactoryParam<SetupPinCodePage,
void Function(PinCodeState<PinCodeWidget>, String), void>(
(onSuccessfulPinSetup, _) => SetupPinCodePage(
getIt.get<SetupPinCodeViewModel>(),
getIt.registerFactoryParam<SetupPinCodePage, void Function(PinCodeState<PinCodeWidget>, String),
void>(
(onSuccessfulPinSetup, _) => SetupPinCodePage(getIt.get<SetupPinCodeViewModel>(),
onSuccessfulPinSetup: onSuccessfulPinSetup));
getIt.registerFactory(() => RescanViewModel(getIt.get<AppStore>().wallet!));
@ -703,17 +740,16 @@ Future setup(
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>(
(type, _) => WalletRestoreViewModel(getIt.get<AppStore>(),
getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) =>
WalletRestoreViewModel(
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
type: type));
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) =>
WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>(
(type, _) => WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
getIt
.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
(TransactionInfo transactionInfo, _) {
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>(
(TransactionInfo transactionInfo, _) {
final wallet = getIt.get<AppStore>().wallet!;
return TransactionDetailsViewModel(
transactionInfo: transactionInfo,
@ -727,54 +763,48 @@ Future setup(
transactionDetailsViewModel:
getIt.get<TransactionDetailsViewModel>(param1: transactionInfo)));
getIt.registerFactoryParam<NewWalletTypePage,
void Function(BuildContext, WalletType), void>(
getIt.registerFactoryParam<NewWalletTypePage, void Function(BuildContext, WalletType), void>(
(param1, _) => NewWalletTypePage(onTypeSelected: param1));
getIt.registerFactoryParam<PreSeedPage, WalletType, void>(
(WalletType type, _) => PreSeedPage(type));
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
TradeDetailsViewModel(tradeForDetails: trade, trades: _tradesSource,
TradeDetailsViewModel(
tradeForDetails: trade,
trades: _tradesSource,
settingsStore: getIt.get<SettingsStore>()));
getIt.registerFactory(() => BackupService(
getIt.get<FlutterSecureStorage>(),
_walletInfoSource,
getIt.get<KeyService>(),
getIt.get<SharedPreferences>()));
getIt.registerFactory(() => BackupService(getIt.get<FlutterSecureStorage>(), _walletInfoSource,
getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
getIt.registerFactory(() => BackupViewModel(getIt.get<FlutterSecureStorage>(),
getIt.get<SecretStore>(), getIt.get<BackupService>()));
getIt.registerFactory(() => BackupViewModel(
getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>()));
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
getIt.registerFactory(
() => EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
getIt.registerFactory(() =>
EditBackupPasswordViewModel(getIt.get<FlutterSecureStorage>(), getIt.get<SecretStore>()));
getIt.registerFactory(
() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
getIt.registerFactory(() => EditBackupPasswordPage(getIt.get<EditBackupPasswordViewModel>()));
getIt.registerFactoryParam<RestoreOptionsPage, bool, void>((bool isNewInstall, _) =>
RestoreOptionsPage(isNewInstall: isNewInstall));
getIt.registerFactoryParam<RestoreOptionsPage, bool, void>(
(bool isNewInstall, _) => RestoreOptionsPage(isNewInstall: isNewInstall));
getIt.registerFactory(() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
getIt.registerFactory(
() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
getIt.registerFactory(() => RestoreFromBackupPage(getIt.get<RestoreFromBackupViewModel>()));
getIt.registerFactory(
() => RestoreFromBackupPage(getIt.get<RestoreFromBackupViewModel>()));
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>(
(Trade trade, _) => TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
getIt.registerFactory(() => BuyAmountViewModel());
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(),
getIt.get<SettingsStore>(), getIt.get<BuyAmountViewModel>(),
return BuyViewModel(_ordersSource, getIt.get<OrdersStore>(), getIt.get<SettingsStore>(),
getIt.get<BuyAmountViewModel>(),
wallet: wallet!);
});
@ -786,7 +816,8 @@ Future setup(
final url = args.first as String;
final buyViewModel = args[1] as BuyViewModel;
return BuyWebViewPage(buyViewModel: buyViewModel, ordersStore: getIt.get<OrdersStore>(), url: url);
return BuyWebViewPage(
buyViewModel: buyViewModel, ordersStore: getIt.get<OrdersStore>(), url: url);
});
getIt.registerFactoryParam<OrderDetailsViewModel, Order, void>((order, _) {
@ -795,8 +826,8 @@ Future setup(
return OrderDetailsViewModel(wallet: wallet!, orderForDetails: order);
});
getIt.registerFactoryParam<OrderDetailsPage, Order, void>((Order order, _) =>
OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));
getIt.registerFactoryParam<OrderDetailsPage, Order, void>(
(Order order, _) => OrderDetailsPage(getIt.get<OrderDetailsViewModel>(param1: order)));
getIt.registerFactory(() => SupportViewModel());
@ -805,20 +836,18 @@ Future setup(
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
return UnspentCoinsListViewModel(
wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!);
return UnspentCoinsListViewModel(wallet: wallet!, unspentCoinsInfo: _unspentCoinsInfoSource!);
});
getIt.registerFactory(() => UnspentCoinsListPage(
unspentCoinsListViewModel: getIt.get<UnspentCoinsListViewModel>()));
getIt.registerFactory(() =>
UnspentCoinsListPage(unspentCoinsListViewModel: getIt.get<UnspentCoinsListViewModel>()));
getIt.registerFactoryParam<UnspentCoinsDetailsViewModel, UnspentCoinsItem,
UnspentCoinsListViewModel>(
(item, model) => UnspentCoinsDetailsViewModel(
unspentCoinsItem: item, unspentCoinsListViewModel: model));
(item, model) =>
UnspentCoinsDetailsViewModel(unspentCoinsItem: item, unspentCoinsListViewModel: model));
getIt.registerFactoryParam<UnspentCoinsDetailsPage, List, void>(
(List args, _) {
getIt.registerFactoryParam<UnspentCoinsDetailsPage, List, void>((List args, _) {
final item = args.first as UnspentCoinsItem;
final unspentCoinsListViewModel = args[1] as UnspentCoinsListViewModel;
@ -829,11 +858,11 @@ Future setup(
getIt.registerFactory(() => YatService());
getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>(),
walletType: getIt.get<AppStore>().wallet!.type));
getIt.registerFactory(() => AddressResolver(
yatService: getIt.get<YatService>(), walletType: getIt.get<AppStore>().wallet!.type));
getIt.registerFactoryParam<FullscreenQRPage, QrViewData, void>(
(QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData));
(QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData));
getIt.registerFactory(() => IoniaApi());
@ -842,26 +871,24 @@ Future setup(
getIt.registerFactory<IoniaService>(
() => IoniaService(getIt.get<FlutterSecureStorage>(), getIt.get<IoniaApi>()));
getIt.registerFactory<IoniaAnyPay>(
() => IoniaAnyPay(
getIt.get<IoniaService>(),
getIt.get<AnyPayApi>(),
getIt.get<AppStore>().wallet!));
getIt.registerFactory<IoniaAnyPay>(() => IoniaAnyPay(
getIt.get<IoniaService>(), getIt.get<AnyPayApi>(), getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>((double amount, merchant) {
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>(
(double amount, merchant) {
return IoniaMerchPurchaseViewModel(
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount,
ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>()
);
ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
amount: amount,
ioniaMerchant: merchant,
sendViewModel: getIt.get<SendViewModel>());
});
getIt.registerFactoryParam<IoniaBuyCardViewModel, IoniaMerchant, void>((IoniaMerchant merchant, _) {
getIt.registerFactoryParam<IoniaBuyCardViewModel, IoniaMerchant, void>(
(IoniaMerchant merchant, _) {
return IoniaBuyCardViewModel(ioniaMerchant: merchant);
});
@ -889,43 +916,45 @@ Future setup(
getIt.registerFactoryParam<IoniaBuyGiftCardDetailPage, List, void>((List args, _) {
final amount = args.first as double;
final merchant = args.last as IoniaMerchant;
return IoniaBuyGiftCardDetailPage(getIt.get<IoniaMerchPurchaseViewModel>(param1: amount, param2: merchant));
return IoniaBuyGiftCardDetailPage(
getIt.get<IoniaMerchPurchaseViewModel>(param1: amount, param2: merchant));
});
getIt.registerFactoryParam<IoniaGiftCardDetailsViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
return IoniaGiftCardDetailsViewModel(
ioniaService: getIt.get<IoniaService>(),
giftCard: giftCard);
getIt.registerFactoryParam<IoniaGiftCardDetailsViewModel, IoniaGiftCard, void>(
(IoniaGiftCard giftCard, _) {
return IoniaGiftCardDetailsViewModel(
ioniaService: getIt.get<IoniaService>(), giftCard: giftCard);
});
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
final amount = args[0] as double;
final merchant = args[1] as IoniaMerchant;
final tip = args[2] as IoniaTip;
getIt.registerFactoryParam<IoniaCustomTipViewModel, List, void>((List args, _) {
final amount = args[0] as double;
final merchant = args[1] as IoniaMerchant;
final tip = args[2] as IoniaTip;
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
});
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>((IoniaGiftCard giftCard, _) {
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>(
(IoniaGiftCard giftCard, _) {
return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
});
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _){
getIt.registerFactoryParam<IoniaMoreOptionsPage, List, void>((List args, _) {
final giftCard = args.first as IoniaGiftCard;
return IoniaMoreOptionsPage(giftCard);
});
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
=> IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>(
(IoniaGiftCard giftCard, _) =>
IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _) {
final giftCard = args.first as IoniaGiftCard;
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard) );
return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard));
});
getIt.registerFactoryParam<IoniaCustomTipPage, List, void>((List args, _) {
return IoniaCustomTipPage(getIt.get<IoniaCustomTipViewModel>(param1: args));
});
@ -940,42 +969,44 @@ Future setup(
getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
getIt.registerFactory(() => AnonPayApi(useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
wallet: getIt.get<AppStore>().wallet!)
);
getIt.registerFactory(() => AnonPayApi(
useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>(), getIt.get<AuthService>()));
getIt.registerFactory(() =>
DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>(), getIt.get<AuthService>()));
getIt.registerFactory(() => DesktopSidebarViewModel());
getIt.registerFactoryParam<AnonpayDetailsViewModel, AnonpayInvoiceInfo, void>(
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
=> AnonpayDetailsViewModel(
anonPayApi: getIt.get<AnonPayApi>(),
anonpayInvoiceInfo: anonpayInvoiceInfo,
settingsStore: getIt.get<SettingsStore>(),
));
(AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsViewModel(
anonPayApi: getIt.get<AnonPayApi>(),
anonpayInvoiceInfo: anonpayInvoiceInfo,
settingsStore: getIt.get<SettingsStore>(),
));
getIt.registerFactoryParam<AnonPayReceivePage, AnonpayInfoBase, void>(
(AnonpayInfoBase anonpayInvoiceInfo, _) => AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
(AnonpayInfoBase anonpayInvoiceInfo, _) =>
AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
getIt.registerFactoryParam<AnonpayDetailsPage, AnonpayInvoiceInfo, void>(
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
=> AnonpayDetailsPage(anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
(AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsPage(
anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
=> IoniaPaymentStatusViewModel(
getIt.get<IoniaService>(),
paymentInfo: paymentInfo,
committedInfo: committedInfo));
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo,
AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
IoniaPaymentStatusViewModel(getIt.get<IoniaService>(),
paymentInfo: paymentInfo, committedInfo: committedInfo));
getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
=> IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo,
AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
IoniaPaymentStatusPage(
getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>((type, _) =>
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>(
(type, _) => AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
_isSetupFinished = true;
}
}

View file

@ -26,7 +26,8 @@ class LanguageService {
'bg': 'Български (Bulgarian)',
'cs': 'čeština (Czech)',
'ur': 'اردو (Urdu)',
'id': 'Bahasa Indonesia (Indonesian)'
'id': 'Bahasa Indonesia (Indonesian)',
'ha': 'Hausa Najeriya (Nigeria)'
};
static const Map<String, String> localeCountryCode = {
@ -52,7 +53,8 @@ class LanguageService {
'bg': 'bgr',
'cs': 'czk',
'ur': 'pak',
'id': 'idn'
'id': 'idn',
'ha': 'hau',
};
static final list = <String, String> {};

View file

@ -47,23 +47,23 @@ class MainActions {
switch (walletType) {
case WalletType.bitcoin:
case WalletType.litecoin:
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.onramperPage);
} else {
final uri = getIt
.get<OnRamperBuyProvider>()
.requestUrl();
await launchUrl(uri);
if (viewModel.isEnabledBuyAction) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.onramperPage);
} else {
final uri = getIt.get<OnRamperBuyProvider>().requestUrl();
await launchUrl(uri);
}
}
break;
case WalletType.monero:
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.payfuraPage);
} else {
final uri = getIt
.get<PayfuraBuyProvider>()
.requestUrl();
await launchUrl(uri);
if (viewModel.isEnabledBuyAction) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.payfuraPage);
} else {
final uri = getIt.get<PayfuraBuyProvider>().requestUrl();
await launchUrl(uri);
}
}
break;
default:
@ -118,12 +118,14 @@ class MainActions {
switch (walletType) {
case WalletType.bitcoin:
final moonPaySellProvider = MoonPaySellProvider();
final uri = await moonPaySellProvider.requestUrl(
currency: viewModel.wallet.currency,
refundWalletAddress: viewModel.wallet.walletAddresses.address,
);
await launchUrl(uri);
if (viewModel.isEnabledSellAction) {
final moonPaySellProvider = MoonPaySellProvider();
final uri = await moonPaySellProvider.requestUrl(
currency: viewModel.wallet.currency,
refundWalletAddress: viewModel.wallet.walletAddresses.address,
);
await launchUrl(uri);
}
break;
default:
await showPopUp<void>(

View file

@ -11,9 +11,14 @@ class PreferencesKey {
static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
static const shouldSaveRecipientAddressKey = 'save_recipient_address';
static const isAppSecureKey = 'is_app_secure';
static const disableBuyKey = 'disable_buy';
static const disableSellKey = 'disable_sell';
static const currentFiatApiModeKey = 'current_fiat_api_mode';
static const allowBiometricalAuthenticationKey =
'allow_biometrical_authentication';
static const useTOTP2FA = 'use_totp_2fa';
static const failedTotpTokenTrials = 'failed_token_trials';
static const totpSecretKey = 'totp_qr_secret_key';
static const disableExchangeKey = 'disable_exchange';
static const exchangeStatusKey = 'exchange_status';
static const currentTheme = 'current_theme';

View file

@ -4,14 +4,15 @@ part 'exchange_template.g.dart';
@HiveType(typeId: ExchangeTemplate.typeId)
class ExchangeTemplate extends HiveObject {
ExchangeTemplate({
required this.amountRaw,
required this.depositCurrencyRaw,
required this.receiveCurrencyRaw,
required this.providerRaw,
required this.depositAddressRaw,
required this.receiveAddressRaw
});
ExchangeTemplate(
{required this.amountRaw,
required this.depositCurrencyRaw,
required this.receiveCurrencyRaw,
required this.providerRaw,
required this.depositAddressRaw,
required this.receiveAddressRaw,
required this.depositCurrencyTitleRaw,
required this.receiveCurrencyTitleRaw});
static const typeId = 7;
static const boxName = 'ExchangeTemplate';
@ -34,6 +35,12 @@ class ExchangeTemplate extends HiveObject {
@HiveField(5)
String? receiveAddressRaw;
@HiveField(6)
String? depositCurrencyTitleRaw;
@HiveField(7)
String? receiveCurrencyTitleRaw;
String get amount => amountRaw ?? '';
String get depositCurrency => depositCurrencyRaw ?? '';
@ -45,4 +52,8 @@ class ExchangeTemplate extends HiveObject {
String get depositAddress => depositAddressRaw ?? '';
String get receiveAddress => receiveAddressRaw ?? '';
}
String get depositCurrencyTitle => depositCurrencyTitleRaw ?? '';
String get receiveCurrencyTitle => receiveCurrencyTitleRaw ?? '';
}

940
lib/hausa_intl.dart Normal file
View file

@ -0,0 +1,940 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/date_symbol_data_custom.dart' as date_symbol_data_custom;
import 'package:intl/date_symbols.dart' as intl;
import 'package:intl/intl.dart' as intl;
// #docregion Date
const haLocaleDatePatterns = {
'd': 'd.',
'E': 'ccc',
'EEEE': 'cccc',
'LLL': 'LLL',
// #enddocregion Date
'LLLL': 'LLLL',
'M': 'L.',
'Md': 'd.M.',
'MEd': 'EEE d.M.',
'MMM': 'LLL',
'MMMd': 'd. MMM',
'MMMEd': 'EEE d. MMM',
'MMMM': 'LLLL',
'MMMMd': 'd. MMMM',
'MMMMEEEEd': 'EEEE d. MMMM',
'QQQ': 'QQQ',
'QQQQ': 'QQQQ',
'y': 'y',
'yM': 'M.y',
'yMd': 'd.M.y',
'yMEd': 'EEE d.MM.y',
'yMMM': 'MMM y',
'yMMMd': 'd. MMM y',
'yMMMEd': 'EEE d. MMM y',
'yMMMM': 'MMMM y',
'yMMMMd': 'd. MMMM y',
'yMMMMEEEEd': 'EEEE d. MMMM y',
'yQQQ': 'QQQ y',
'yQQQQ': 'QQQQ y',
'H': 'HH',
'Hm': 'HH:mm',
'Hms': 'HH:mm:ss',
'j': 'HH',
'jm': 'HH:mm',
'jms': 'HH:mm:ss',
'jmv': 'HH:mm v',
'jmz': 'HH:mm z',
'jz': 'HH z',
'm': 'm',
'ms': 'mm:ss',
's': 's',
'v': 'v',
'z': 'z',
'zzzz': 'zzzz',
'ZZZZ': 'ZZZZ',
};
// #docregion Date2
const haDateSymbols = {
'NAME': 'ha',
'ERAS': <dynamic>[
'f.Kr.',
'e.Kr.',
],
// #enddocregion Date2
'ERANAMES': <dynamic>[
'kafin Kristi',
'bayan Kristi',
],
'NARROWMONTHS': <dynamic>[
'J',
'F',
'M',
'A',
'M',
'J',
'J',
'A',
'S',
'O',
'N',
'D',
],
'STANDALONENARROWMONTHS': <dynamic>[
'J',
'F',
'M',
'A',
'M',
'J',
'J',
'A',
'S',
'O',
'N',
'D',
],
'MONTHS': <dynamic>[
'janairu',
'faburairu',
'maris',
'afrilu',
'mayu',
'yuni',
'yuli',
'agusta',
'satumba',
'oktoba',
'nuwamba',
'disamba',
],
'STANDALONEMONTHS': <dynamic>[
'janairu',
'faburairu',
'maris',
'afrilu',
'mayu',
'yuni',
'yuli',
'agusta',
'satumba',
'oktoba',
'nuwamba',
'disamba',
],
'SHORTMONTHS': <dynamic>[
'jan.',
'feb.',
'mar.',
'apr.',
'mai',
'jun.',
'jul.',
'aug.',
'sep.',
'okt.',
'nov.',
'des.',
],
'STANDALONESHORTMONTHS': <dynamic>[
'jan',
'feb',
'mar',
'apr',
'mai',
'jun',
'jul',
'aug',
'sep',
'okt',
'nov',
'des',
],
'WEEKDAYS': <dynamic>[
'lahadi',
'litinin',
'talata',
'laraba',
'alhamis',
'jummaʼa',
'asabar',
],
'STANDALONEWEEKDAYS': <dynamic>[
'lahadi',
'litinin',
'talata',
'laraba',
'alhamis',
'jummaʼa',
'asabar',
],
'SHORTWEEKDAYS': <dynamic>[
'lah.',
'lit.',
'tal.',
'lar.',
'alh.',
'jum.',
'asa.',
],
'STANDALONESHORTWEEKDAYS': <dynamic>[
'lah.',
'lit.',
'tal.',
'lar.',
'alh.',
'jum.',
'asa.',
],
'NARROWWEEKDAYS': <dynamic>[
'L',
'L',
'T',
'L',
'A',
'J',
'A',
],
'STANDALONENARROWWEEKDAYS': <dynamic>[
'L',
'L',
'T',
'L',
'A',
'J',
'A',
],
'SHORTQUARTERS': <dynamic>[
'K1',
'K2',
'K3',
'K4',
],
'QUARTERS': <dynamic>[
'1. quarter',
'2. quarter',
'3. quarter',
'4. quarter',
],
'AMPMS': <dynamic>[
'a.m.',
'p.m.',
],
'DATEFORMATS': <dynamic>[
'EEEE d. MMMM y',
'd. MMMM y',
'd. MMM y',
'dd.MM.y',
],
'TIMEFORMATS': <dynamic>[
'HH:mm:ss zzzz',
'HH:mm:ss z',
'HH:mm:ss',
'HH:mm',
],
'AVAILABLEFORMATS': null,
'FIRSTDAYOFWEEK': 0,
'WEEKENDRANGE': <dynamic>[
5,
6,
],
'FIRSTWEEKCUTOFFDAY': 3,
'DATETIMEFORMATS': <dynamic>[
'{1} {0}',
'{1} \'kl\'. {0}',
'{1}, {0}',
'{1}, {0}',
],
};
// #docregion Delegate
class _HaMaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
const _HaMaterialLocalizationsDelegate();
@override
bool isSupported(Locale locale) => locale.languageCode == 'ha';
@override
Future<MaterialLocalizations> load(Locale locale) async {
final String localeName = intl.Intl.canonicalizedLocale(locale.toString());
// The locale (in this case `ha`) needs to be initialized into the custom
// date symbols and patterns setup that Flutter uses.
date_symbol_data_custom.initializeDateFormattingCustom(
locale: localeName,
patterns: haLocaleDatePatterns,
symbols: intl.DateSymbols.deserializeFromMap(haDateSymbols),
);
return SynchronousFuture<MaterialLocalizations>(
HaMaterialLocalizations(
localeName: localeName,
// The `intl` library's NumberFormat class is generated from CLDR data
// (see https://github.com/dart-lang/intl/blob/master/lib/number_symbols_data.dart).
// Unfortunately, there is no way to use a locale that isn't defined in
// this map and the only way to work around this is to use a listed
// locale's NumberFormat symbols. So, here we use the number formats
// for 'en_US' instead.
decimalFormat: intl.NumberFormat('#,##0.###', 'en_US'),
twoDigitZeroPaddedFormat: intl.NumberFormat('00', 'en_US'),
// DateFormat here will use the symbols and patterns provided in the
// `date_symbol_data_custom.initializeDateFormattingCustom` call above.
// However, an alternative is to simply use a supported locale's
// DateFormat symbols, similar to NumberFormat above.
fullYearFormat: intl.DateFormat('y', localeName),
compactDateFormat: intl.DateFormat('yMd', localeName),
shortDateFormat: intl.DateFormat('yMMMd', localeName),
mediumDateFormat: intl.DateFormat('EEE, MMM d', localeName),
longDateFormat: intl.DateFormat('EEEE, MMMM d, y', localeName),
yearMonthFormat: intl.DateFormat('MMMM y', localeName),
shortMonthDayFormat: intl.DateFormat('MMM d', localeName),
),
);
}
@override
bool shouldReload(_HaMaterialLocalizationsDelegate old) => false;
}
// #enddocregion Delegate
class HaMaterialLocalizations extends GlobalMaterialLocalizations {
const HaMaterialLocalizations({
super.localeName = 'ha',
required super.fullYearFormat,
required super.compactDateFormat,
required super.shortDateFormat,
required super.mediumDateFormat,
required super.longDateFormat,
required super.yearMonthFormat,
required super.shortMonthDayFormat,
required super.decimalFormat,
required super.twoDigitZeroPaddedFormat,
});
// #docregion Getters
@override
String get moreButtonTooltip => r'Zaɓi';
@override
String get aboutListTileTitleRaw => r'Dake ɓoye $applicationname';
@override
String get alertDialogLabel => r'Alert';
// #enddocregion Getters
@override
String get anteMeridiemAbbreviation => r'AM';
@override
String get backButtonTooltip => r'Farawa';
@override
String get cancelButtonLabel => r'KANƘO';
@override
String get closeButtonLabel => r'SHIGA';
@override
String get closeButtonTooltip => r'Shiga';
@override
String get collapsedIconTapHint => r'Fara';
@override
String get continueButtonLabel => r'CI GABA';
@override
String get copyButtonLabel => r'KOPIYA';
@override
String get cutButtonLabel => r'ƘIRƘIRI';
@override
String get deleteButtonTooltip => r'Kashe';
@override
String get dialogLabel => r'Dialog';
@override
String get drawerLabel => r'Meniyar tebur';
@override
String get expandedIconTapHint => r'Faɗa';
@override
String get firstPageTooltip => r'Ta baya';
@override
String get hideAccountsLabel => r'Soke akaunti';
@override
String get lastPageTooltip => r'Ta gaba';
@override
String get licensesPageTitle => r'Lisansu';
@override
String get modalBarrierDismissLabel => r'So';
@override
String get nextMonthTooltip => r'Watan gobe';
@override
String get nextPageTooltip => r'Wani babban daidaita';
@override
String get okButtonLabel => r'OK';
@override
// A custom drawer tooltip message.
String get openAppDrawerTooltip => r'Taƙaitacciyar Menu na Nauyi';
// #docregion Raw
@override
String get pageRowsInfoTitleRaw => r'$firstRow$lastRow daga $rowCount';
@override
String get pageRowsInfoTitleApproximateRaw => r'$firstRow$lastRow daga takwas $rowCount';
// #enddocregion Raw
@override
String get pasteButtonLabel => r'BANDA';
@override
String get popupMenuLabel => r'Meniyar Kasuwa';
@override
String get menuBarMenuLabel => r'Gargajiya na menu';
@override
String get postMeridiemAbbreviation => r'PM';
@override
String get previousMonthTooltip => r'Watan gabas';
@override
String get previousPageTooltip => r'Wani babban hanya';
@override
String get refreshIndicatorSemanticLabel => r'Nada';
@override
String? get remainingTextFieldCharacterCountFew => null;
@override
String? get remainingTextFieldCharacterCountMany => null;
@override
String get remainingTextFieldCharacterCountOne => r'1 haruffa baki';
@override
String get remainingTextFieldCharacterCountOther => r'$remainingCount haruffa baki';
@override
String? get remainingTextFieldCharacterCountTwo => null;
@override
String get remainingTextFieldCharacterCountZero => r'Ba a nan rubutu sosai';
@override
String get reorderItemDown => r'A sake ƙasa';
@override
String get reorderItemLeft => r'A sake hagu';
@override
String get reorderItemRight => r'A sake dama';
@override
String get reorderItemToEnd => r'A sake zuwa tamu';
@override
String get reorderItemToStart => r'A sake zuwa farko';
@override
String get reorderItemUp => r'A sake sama';
@override
String get rowsPerPageTitle => r'Lambar Fasali:';
@override
ScriptCategory get scriptCategory => ScriptCategory.englishLike;
@override
String get searchFieldLabel => 'Binciken';
@override
String get selectAllButtonLabel => 'DUBA DUK';
@override
String? get selectedRowCountTitleFew => null;
@override
String? get selectedRowCountTitleMany => null;
@override
String get selectedRowCountTitleOne => '1 kaya';
@override
String get selectedRowCountTitleOther => r'$selectedRowCount kayayyaki';
@override
String? get selectedRowCountTitleTwo => null;
@override
String get selectedRowCountTitleZero => 'Babu kaya da aka zabi';
@override
String get showAccountsLabel => 'Nuna Hisobin';
@override
String get showMenuTooltip => 'Nuna Menu';
@override
String get signedInLabel => 'Kasance';
@override
String get tabLabelRaw => r'Tabin $tabIndex daga $tabCount';
@override
TimeOfDayFormat get timeOfDayFormatRaw => TimeOfDayFormat.h_colon_mm_space_a;
@override
String get timePickerHourModeAnnouncement => 'Zaɓi saʼoɗin lokaci';
@override
String get timePickerMinuteModeAnnouncement => 'Zaɓi minti';
@override
String get viewLicensesButtonLabel => 'DUBA LAYINSU';
@override
List<String> get narrowWeekdays => const <String>['L', 'L', 'M', 'K', 'J', 'A', 'A'];
@override
int get firstDayOfWeekIndex => 0;
static const LocalizationsDelegate<MaterialLocalizations> delegate =
_HaMaterialLocalizationsDelegate();
@override
String get calendarModeButtonLabel => 'Canza zuwa kalendar';
@override
String get dateHelpText => 'mm/dd/yyyy';
@override
String get dateInputLabel => 'Shigar Daƙin';
@override
String get dateOutOfRangeLabel => 'A cikin jerin';
@override
String get datePickerHelpText => 'ZAƘA TALATA';
@override
String get dateRangeEndDateSemanticLabelRaw => r'Aikin da ya ƙarshe $fullDate';
@override
String get dateRangeEndLabel => 'Aikin da ya ƙarshe';
@override
String get dateRangePickerHelpText => 'ZAƘA HALIN RANAR';
@override
String get dateRangeStartDateSemanticLabelRaw => 'Aikin da ya gabata \$fullDate';
@override
String get dateRangeStartLabel => 'Aikin da ya gabata';
@override
String get dateSeparator => '/';
@override
String get dialModeButtonLabel => 'Canza zuwa jerin';
@override
String get inputDateModeButtonLabel => 'Canza zuwa shigar';
@override
String get inputTimeModeButtonLabel => 'Canza zuwa jerin bayanin rubutu';
@override
String get invalidDateFormatLabel => 'Tarihin ba daidai ba';
@override
String get invalidDateRangeLabel => 'Siffar saƙo ba tare da hukunci ba';
@override
String get invalidTimeLabel => 'Kasancewa aikin lokaci mai kyau';
@override
String get licensesPackageDetailTextOther => r'$licenseCount layinsu';
@override
String get saveButtonLabel => 'Aji';
@override
String get selectYearSemanticsLabel => 'Zaɓi shekara';
@override
String get timePickerDialHelpText => 'ZAƘA LOKACI';
@override
String get timePickerHourLabel => 'Auren lokaci';
@override
String get timePickerInputHelpText => 'Shigar lokaci';
@override
String get timePickerMinuteLabel => 'Minti';
@override
String get unspecifiedDate => 'Ranar';
@override
String get unspecifiedDateRange => 'Ranar Ayyuka';
@override
String get keyboardKeyAlt => 'Alt';
@override
String get keyboardKeyAltGraph => 'AltGraph';
@override
String get keyboardKeyBackspace => 'BayaRubuta';
@override
String get keyboardKeyCapsLock => 'Caps Lock';
@override
String get keyboardKeyChannelDown => 'BayaKammalaSake';
@override
String get keyboardKeyChannelUp => 'YiKammalaSake';
@override
String get keyboardKeyControl => 'Tsara';
@override
String get keyboardKeyDelete => 'Share';
@override
String get keyboardKeyEject => 'Eject';
@override
String get keyboardKeyEnd => 'Tare';
@override
String get keyboardKeyEscape => 'Goge';
@override
String get keyboardKeyFn => 'Fn';
@override
String get keyboardKeyHome => 'Home';
@override
String get keyboardKeyInsert => 'Shirya';
@override
String get keyboardKeyMeta => 'Meta';
@override
String get keyboardKeyMetaMacOs => 'Amfani da Command';
@override
String get keyboardKeyMetaWindows => 'Windows';
@override
String get keyboardKeyNumLock => 'Num Lock';
@override
String get keyboardKeyNumpad0 => 'Numpad 0';
@override
String get keyboardKeyNumpad1 => 'Numpad 1';
@override
String get keyboardKeyNumpad2 => 'Numpad 2';
@override
String get keyboardKeyNumpad3 => 'Numpad 3';
@override
String get keyboardKeyNumpad4 => 'Numpad 4';
@override
String get keyboardKeyNumpad5 => 'Numpad 5';
@override
String get keyboardKeyNumpad6 => 'Numpad 6';
@override
String get keyboardKeyNumpad7 => 'Numpad 7';
@override
String get keyboardKeyNumpad8 => 'Numpad 8';
@override
String get keyboardKeyNumpad9 => 'Numpad 9';
@override
String get keyboardKeyNumpadAdd => 'Numpad +';
@override
String get keyboardKeyNumpadComma => 'Numpad ,';
@override
String get keyboardKeyNumpadDecimal => 'Numpad .';
@override
String get keyboardKeyNumpadDivide => 'Numpad /';
@override
String get keyboardKeyNumpadEnter => 'Numpad Enter';
@override
String get keyboardKeyNumpadEqual => 'Numpad =';
@override
String get keyboardKeyNumpadMultiply => 'Numpad *';
@override
String get keyboardKeyNumpadParenLeft => 'Numpad (';
@override
String get keyboardKeyNumpadParenRight => 'Numpad )';
@override
String get keyboardKeyNumpadSubtract => 'Numpad -';
@override
String get keyboardKeyPageDown => 'Page Down';
@override
String get keyboardKeyPageUp => 'Page Up';
@override
String get keyboardKeyPower => 'Power';
@override
String get keyboardKeyPowerOff => 'Power Off';
@override
String get keyboardKeyPrintScreen => 'Print Screen';
@override
String get keyboardKeyScrollLock => 'Scroll Lock';
@override
String get keyboardKeySelect => 'Zabi';
@override
String get keyboardKeySpace => 'Space';
}
/// Cupertino Support
/// Strings Copied from "https://github.com/flutter/flutter/blob/master/packages/flutter_localizations/lib/src/l10n/generated_cupertino_localizations.dart"
class _HaCupertinoLocalizationsDelegate extends LocalizationsDelegate<CupertinoLocalizations> {
const _HaCupertinoLocalizationsDelegate();
@override
bool isSupported(Locale locale) => locale.languageCode == 'ha';
@override
Future<CupertinoLocalizations> load(Locale locale) async {
final String localeName = intl.Intl.canonicalizedLocale(locale.toString());
// The locale (in this case `ha`) needs to be initialized into the custom =>> `ha`
// date symbols and patterns setup that Flutter uses.
date_symbol_data_custom.initializeDateFormattingCustom(
locale: localeName,
patterns: haLocaleDatePatterns,
symbols: intl.DateSymbols.deserializeFromMap(haDateSymbols),
);
return SynchronousFuture<CupertinoLocalizations>(
HaCupertinoLocalizations(
localeName: localeName,
// The `intl` library's NumberFormat class is generated from CLDR data
// (see https://github.com/dart-lang/intl/blob/master/lib/number_symbols_data.dart).
// Unfortunately, there is no way to use a locale that isn't defined in
// this map and the only way to work around this is to use a listed
// locale's NumberFormat symbols. So, here we use the number formats
// for 'en_US' instead.
decimalFormat: intl.NumberFormat('#,##0.###', 'en_US'),
// DateFormat here will use the symbols and patterns provided in the
// `date_symbol_data_custom.initializeDateFormattingCustom` call above.
// However, an alternative is to simply use a supported locale's
// DateFormat symbols, similar to NumberFormat above.
fullYearFormat: intl.DateFormat('y', localeName),
mediumDateFormat: intl.DateFormat('EEE, MMM d', localeName),
dayFormat: intl.DateFormat('d', localeName),
doubleDigitMinuteFormat: intl.DateFormat('mm', localeName),
singleDigitHourFormat: intl.DateFormat('j', localeName),
singleDigitMinuteFormat: intl.DateFormat.m(localeName),
singleDigitSecondFormat: intl.DateFormat.s(localeName),
),
);
}
@override
bool shouldReload(_HaCupertinoLocalizationsDelegate old) => false;
}
// #enddocregion Delegate
/// A custom set of localizations for the 'nn' locale. In this example, only =>> `ha`
/// the value for openAppDrawerTooltip was modified to use a custom message as
/// an example. Everything else uses the American English (en_US) messages
/// and formatting.
class HaCupertinoLocalizations extends GlobalCupertinoLocalizations {
const HaCupertinoLocalizations({
super.localeName = 'ha',
required super.fullYearFormat,
required super.mediumDateFormat,
required super.decimalFormat,
required super.dayFormat,
required super.singleDigitHourFormat,
required super.singleDigitMinuteFormat,
required super.doubleDigitMinuteFormat,
required super.singleDigitSecondFormat,
});
@override
String get alertDialogLabel => 'Fadakarwa';
@override
String get anteMeridiemAbbreviation => 'AM';
@override
String get copyButtonLabel => 'Kwafa';
@override
String get cutButtonLabel => 'yanke';
@override
String get datePickerDateOrderString => 'mdy';
@override
String get datePickerDateTimeOrderString => 'date_time_dayPeriod';
@override
String? get datePickerHourSemanticsLabelFew => null;
@override
String? get datePickerHourSemanticsLabelMany => null;
@override
String? get datePickerHourSemanticsLabelOne => r"$hour o'clock";
@override
String get datePickerHourSemanticsLabelOther => r"$hour o'clock";
@override
String? get datePickerHourSemanticsLabelTwo => null;
@override
String? get datePickerHourSemanticsLabelZero => null;
@override
String? get datePickerMinuteSemanticsLabelFew => null;
@override
String? get datePickerMinuteSemanticsLabelMany => null;
@override
String? get datePickerMinuteSemanticsLabelOne => '1 minti';
@override
String get datePickerMinuteSemanticsLabelOther => r'$minute minti';
@override
String? get datePickerMinuteSemanticsLabelTwo => null;
@override
String? get datePickerMinuteSemanticsLabelZero => null;
@override
String get modalBarrierDismissLabel => 'Korar';
@override
String get pasteButtonLabel => 'Liƙa';
@override
String get postMeridiemAbbreviation => 'PM';
@override
String get searchTextFieldPlaceholderLabel => 'Bincika';
@override
String get selectAllButtonLabel => 'Zaɓi Duk';
@override
String get tabSemanticsLabelRaw => r'Tab $tabIndex cikin $tabCount';
@override
String? get timerPickerHourLabelFew => null;
@override
String? get timerPickerHourLabelMany => null;
@override
String? get timerPickerHourLabelOne => 'awa';
@override
String get timerPickerHourLabelOther => 'awa';
@override
String? get timerPickerHourLabelTwo => null;
@override
String? get timerPickerHourLabelZero => null;
@override
String? get timerPickerMinuteLabelFew => null;
@override
String? get timerPickerMinuteLabelMany => null;
@override
String? get timerPickerMinuteLabelOne => 'minti.';
@override
String get timerPickerMinuteLabelOther => 'minti.';
@override
String? get timerPickerMinuteLabelTwo => null;
@override
String? get timerPickerMinuteLabelZero => null;
@override
String? get timerPickerSecondLabelFew => null;
@override
String? get timerPickerSecondLabelMany => null;
@override
String? get timerPickerSecondLabelOne => 'dakika.';
@override
String get timerPickerSecondLabelOther => 'dakika.';
@override
String? get timerPickerSecondLabelTwo => null;
@override
String? get timerPickerSecondLabelZero => null;
@override
String get todayLabel => 'Yau';
static const LocalizationsDelegate<CupertinoLocalizations> delegate =
_HaCupertinoLocalizationsDelegate();
}

View file

@ -3,6 +3,7 @@ import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/hausa_intl.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:flutter/foundation.dart';
@ -43,7 +44,6 @@ final rootKey = GlobalKey<RootState>();
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
Future<void> main() async {
await runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
@ -106,32 +106,27 @@ Future<void> main() async {
}
final secureStorage = FlutterSecureStorage();
final transactionDescriptionsBoxKey = await getEncryptionKey(
secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final tradesBoxKey = await getEncryptionKey(
secureStorage: secureStorage, forKey: Trade.boxKey);
final ordersBoxKey = await getEncryptionKey(
secureStorage: secureStorage, forKey: Order.boxKey);
final transactionDescriptionsBoxKey =
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
final contacts = await Hive.openBox<Contact>(Contact.boxName);
final nodes = await Hive.openBox<Node>(Node.boxName);
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
TransactionDescription.boxName,
encryptionKey: transactionDescriptionsBoxKey);
final trades =
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders =
await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
final trades = await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders = await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
final templates = await Hive.openBox<Template>(Template.boxName);
final exchangeTemplates =
await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
if (!isMoneroOnly) {
unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
}
await initialSetup(
sharedPreferences: await SharedPreferences.getInstance(),
nodes: nodes,
@ -198,8 +193,7 @@ class App extends StatefulWidget {
}
class AppState extends State<App> with SingleTickerProviderStateMixin {
AppState()
: yatStore = getIt.get<YatStore>() {
AppState() : yatStore = getIt.get<YatStore>() {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
}
@ -265,17 +259,14 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
final settingsStore = appStore.settingsStore;
final statusBarColor = Colors.transparent;
final authenticationStore = getIt.get<AuthenticationStore>();
final initialRoute =
authenticationStore.state == AuthenticationState.uninitialized
final initialRoute = authenticationStore.state == AuthenticationState.uninitialized
? Routes.disclaimer
: Routes.login;
final currentTheme = settingsStore.currentTheme;
final statusBarBrightness = currentTheme.type == ThemeType.dark
? Brightness.light
: Brightness.dark;
final statusBarIconBrightness = currentTheme.type == ThemeType.dark
? Brightness.light
: Brightness.dark;
final statusBarBrightness =
currentTheme.type == ThemeType.dark ? Brightness.light : Brightness.dark;
final statusBarIconBrightness =
currentTheme.type == ThemeType.dark ? Brightness.light : Brightness.dark;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: statusBarColor,
statusBarBrightness: statusBarBrightness,
@ -297,6 +288,8 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
HaMaterialLocalizations.delegate,
HaCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
locale: Locale(settingsStore.languageCode),

View file

@ -10,7 +10,7 @@ class CWMoneroAccountList extends MoneroAccountList {
final moneroWallet = _wallet as MoneroWallet;
final accounts = moneroWallet.walletAddresses.accountList
.accounts
.map((acc) => Account(id: acc.id, label: acc.label))
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
.toList();
return ObservableList<Account>.of(accounts);
}
@ -32,7 +32,7 @@ class CWMoneroAccountList extends MoneroAccountList {
final moneroWallet = wallet as MoneroWallet;
return moneroWallet.walletAddresses.accountList
.getAll()
.map((acc) => Account(id: acc.id, label: acc.label))
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
.toList();
}
@ -122,7 +122,7 @@ class CWMoneroWalletDetails extends MoneroWalletDetails {
Account get account {
final moneroWallet = _wallet as MoneroWallet;
final acc = moneroWallet.walletAddresses.account;
return Account(id: acc!.id, label: acc.label);
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
}
@computed
@ -316,13 +316,13 @@ class CWMonero extends Monero {
Account getCurrentAccount(Object wallet) {
final moneroWallet = wallet as MoneroWallet;
final acc = moneroWallet.walletAddresses.account;
return Account(id: acc!.id, label: acc.label);
return Account(id: acc!.id, label: acc.label, balance: acc.balance);
}
@override
void setCurrentAccount(Object wallet, int id, String label) {
void setCurrentAccount(Object wallet, int id, String label, String? balance) {
final moneroWallet = wallet as MoneroWallet;
moneroWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
moneroWallet.walletAddresses.account = monero_account.Account(id: id, label: label, balance: balance);
}
@override

View file

@ -1,5 +1,6 @@
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/entities/qr_view_data.dart';
@ -33,6 +34,10 @@ import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
import 'package:cake_wallet/src/screens/support/support_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
@ -149,6 +154,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreOptions:
final isNewInstall = settings.arguments as bool;
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<RestoreOptionsPage>(param1: isNewInstall));
case Routes.restoreWalletFromSeedKeys:
@ -169,6 +175,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
fullscreenDialog: true);
} else if (isSingleCoin) {
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<WalletRestorePage>(
param1: availableWalletTypes.first
));
@ -183,11 +190,13 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.seed:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) =>
getIt.get<WalletSeedPage>(param1: settings.arguments as bool));
case Routes.restoreWallet:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<WalletRestorePage>(
param1: settings.arguments as WalletType));
@ -260,6 +269,26 @@ Route<dynamic> createRoute(RouteSettings settings) {
param1: settings.arguments as OnAuthenticationFinished,
param2: true));
case Routes.totpAuthCodePage:
final args = settings.arguments as TotpAuthArgumentsModel;
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<TotpAuthCodePage>(
param1: args,
),
);
case Routes.login:
return CupertinoPageRoute<void>(
builder: (context) => WillPopScope(
child: getIt.get<AuthPage>(instanceName: 'login'),
onWillPop: () async =>
// FIX-ME: Additional check does it works correctly
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ??
false),
),
fullscreenDialog: true);
case Routes.unlock:
return MaterialPageRoute<void>(
fullscreenDialog: true,
@ -301,14 +330,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
param1: args?['editingNode'] as Node?,
param2: args?['isSelected'] as bool?));
case Routes.login:
return CupertinoPageRoute<void>(
builder: (context) => WillPopScope(
child: getIt.get<AuthPage>(instanceName: 'login'),
onWillPop: () async =>
// FIX-ME: Additional check does it works correctly
(await SystemChannels.platform.invokeMethod<bool>('SystemNavigator.pop') ?? false)),
fullscreenDialog: true);
case Routes.accountCreation:
return CupertinoPageRoute<String>(
@ -344,6 +366,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.tradeDetails:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) =>
getIt.get<TradeDetailsPage>(param1: settings.arguments as Trade));
@ -361,6 +384,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
final args = settings.arguments as List;
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) =>
getIt.get<BuyWebViewPage>(param1: args));
@ -370,6 +394,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
getIt.get<WalletRestorationFromSeedVM>(param1: args);
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => RestoreWalletFromSeedDetailsPage(
walletRestorationFromSeedVM: walletRestorationFromSeedVM));
@ -403,6 +428,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreFromBackup:
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<RestoreFromBackupPage>());
case Routes.support:
@ -509,7 +535,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.anonPayInvoicePage:
final args = settings.arguments as List;
return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
case Routes.anonPayReceivePage:
final anonInvoiceViewData = settings.arguments as AnonpayInfoBase;
@ -539,6 +567,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
fullscreenDialog: true,
builder: (_) => getIt.get<TransactionsPage>());
case Routes.setup_2faPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<Setup2FAPage>());
case Routes.setup_2faQRPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<Setup2FAQRPage>());
case Routes.modify2FAPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<Modify2FAPage>());
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(

View file

@ -84,4 +84,8 @@ class Routes {
static const payfuraPage = '/pay_fura_page';
static const desktop_actions = '/desktop_actions';
static const transactionsPage = '/transactions_page';
static const setup_2faPage = '/setup_2fa_page';
static const setup_2faQRPage = '/setup_2fa_qr_page';
static const totpAuthCodePage = '/totp_auth_code_page';
static const modify2FAPage = '/modify_2fa_page';
}

View file

@ -1,13 +1,11 @@
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/core/address_validator.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/currency.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/address_validator.dart';
import 'package:cake_wallet/core/contact_name_validator.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
@ -33,8 +31,8 @@ class ContactPage extends BasePage {
_addressController
.addListener(() => contactViewModel.address = _addressController.text);
autorun((_) =>
_currencyTypeController.text = contactViewModel.currency?.toString()??'');
autorun((_) => _currencyTypeController.text =
contactViewModel.currency?.toString() ?? '');
}
@override
@ -61,96 +59,105 @@ class ContactPage extends BasePage {
}
});
return ScrollableWithBottomSection(
contentPadding: EdgeInsets.all(24),
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
BaseTextFormField(
controller: _nameController,
hintText: S.of(context).contact_name,
validator: ContactNameValidator()),
Padding(
padding: EdgeInsets.only(top: 20),
child: Container(
child: InkWell(
onTap: () => _presentCurrencyPicker(context),
child: IgnorePointer(
child: BaseTextFormField(
controller: _currencyTypeController,
hintText: S.of(context).settings_currency,
suffixIcon: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[downArrow],
),
)),
return Observer(
builder: (_) => ScrollableWithBottomSection(
contentPadding: EdgeInsets.all(24),
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
BaseTextFormField(
controller: _nameController,
hintText: S.of(context).contact_name,
validator: ContactNameValidator()),
Padding(
padding: EdgeInsets.only(top: 20),
child: Container(
child: InkWell(
onTap: () => _presentCurrencyPicker(context),
child: IgnorePointer(
child: BaseTextFormField(
controller: _currencyTypeController,
hintText: S.of(context).settings_currency,
suffixIcon: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[downArrow],
),
)),
),
),
),
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Observer(
builder: (_) => AddressTextField(
if (contactViewModel.currency != null)
Padding(
padding: EdgeInsets.only(top: 20),
child: AddressTextField(
controller: _addressController,
options: [
AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode,
],
buttonColor: Theme.of(context).accentTextTheme!.headline3!.color!,
buttonColor:
Theme.of(context).accentTextTheme!.headline3!.color!,
iconColor: PaletteDark.gray,
borderColor: Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!,
validator: TextValidator()
// AddressValidator(
// type: contactViewModel.currency),
)),
)
],
),
),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Row(
children: <Widget>[
Expanded(
child: PrimaryButton(
onPressed: () {
contactViewModel.reset();
_nameController.text = '';
_addressController.text = '';
},
text: S.of(context).reset,
color: Colors.orange,
textColor: Colors.white),
borderColor: Theme.of(context)
.primaryTextTheme!
.headline6!
.backgroundColor!,
validator:
AddressValidator(type: contactViewModel.currency!),
),
)
],
),
SizedBox(width: 20),
Expanded(
child: Observer(
builder: (_) => PrimaryButton(
onPressed: () async {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
return;
}
),
bottomSectionPadding:
EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: Row(
children: <Widget>[
Expanded(
child: PrimaryButton(
onPressed: () {
contactViewModel.reset();
_nameController.text = '';
_addressController.text = '';
},
text: S.of(context).reset,
color: Colors.orange,
textColor: Colors.white),
),
SizedBox(width: 20),
Expanded(
child: Observer(
builder: (_) => PrimaryButton(
onPressed: () async {
if (_formKey.currentState != null &&
!_formKey.currentState!.validate()) {
return;
}
await contactViewModel.save();
},
text: S.of(context).save,
color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
textColor: Colors.white,
isDisabled: !contactViewModel.isReady)))
],
));
await contactViewModel.save();
},
text: S.of(context).save,
color: Theme.of(context)
.accentTextTheme!
.bodyText1!
.color!,
textColor: Colors.white,
isDisabled: !contactViewModel.isReady)))
],
)),
);
}
void _presentCurrencyPicker(BuildContext context) {
showPopUp<void>(
builder: (_) => CurrencyPicker(
selectedAtIndex:
contactViewModel.currency != null
? contactViewModel.currencies.indexOf(contactViewModel.currency!)
: 0,
selectedAtIndex: contactViewModel.currency != null
? contactViewModel.currencies
.indexOf(contactViewModel.currency!)
: -1,
items: contactViewModel.currencies,
title: S.of(context).please_select,
hintText: S.of(context).search_currency,

View file

@ -59,17 +59,16 @@ class AddressPage extends BasePage {
bool effectsInstalled = false;
@override
Color get titleColor => Colors.white;
@override
Widget? leading(BuildContext context) {
final _backButton = Icon(Icons.arrow_back_ios,
color: titleColor,
final _backButton = Icon(
Icons.arrow_back_ios,
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
size: 16,
);
final _closeButton = currentTheme.type == ThemeType.dark
? closeButtonImageDarkTheme : closeButtonImage;
? closeButtonImageDarkTheme
: closeButtonImage;
bool isMobileView = ResponsiveLayoutUtil.instance.isMobile(context);
@ -84,7 +83,7 @@ class AddressPage extends BasePage {
child: TextButton(
style: ButtonStyle(
overlayColor: MaterialStateColor.resolveWith(
(states) => Colors.transparent),
(states) => Colors.transparent),
),
onPressed: () => onClose(context),
child: !isMobileView ? _closeButton : _backButton,
@ -97,7 +96,10 @@ class AddressPage extends BasePage {
@override
Widget middle(BuildContext context) =>
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
PresentReceiveOptionPicker(
receiveOptionViewModel: receiveOptionViewModel,
hasWhiteBackground: currentTheme.type == ThemeType.light,
);
@override
Widget Function(BuildContext, Widget) get rootWrapper =>

View file

@ -1,13 +1,9 @@
import 'dart:ui';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
import 'package:cake_wallet/src/widgets/section_divider.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
//import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
@ -20,89 +16,93 @@ class FilterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
const sectionDivider = const SectionDivider();
return AlertBackground(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: EdgeInsets.all(24.0),
child: Text(
S.of(context).filter_by,
style: TextStyle(
color: Theme.of(context).primaryTextTheme.overline!.color!,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
return PickerWrapperWidget(
children: [
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(24)),
child: Container(
color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(24.0),
child: Text(
S.of(context).filter_by,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.overline!
.color!,
fontSize: 16,
fontFamily: 'Lato',
decoration: TextDecoration.none,
),
),
sectionDivider,
ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: dashboardViewModel.filterItems.length,
separatorBuilder: (context, _) => sectionDivider,
itemBuilder: (_, index1) {
final title = dashboardViewModel.filterItems.keys.elementAt(index1);
final section = dashboardViewModel.filterItems.values.elementAt(index1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20, left: 24, right: 24),
child: Text(
title,
style: TextStyle(
color: Theme.of(context).primaryTextTheme!.headline6!.color!,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
),
sectionDivider,
ListView.separated(
padding: EdgeInsets.zero,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: dashboardViewModel.filterItems.length,
separatorBuilder: (context, _) => sectionDivider,
itemBuilder: (_, index1) {
final title = dashboardViewModel.filterItems.keys
.elementAt(index1);
final section = dashboardViewModel.filterItems.values
.elementAt(index1);
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding:
EdgeInsets.only(top: 20, left: 24, right: 24),
child: Text(
title,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme!
.headline6!
.color!,
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none),
),
ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: section.length,
itemBuilder: (_, index2) {
final item = section[index2];
final content = Observer(
builder: (_) => StandardCheckbox(
value: item.value(),
caption: item.caption,
gradientBackground: true,
borderColor: Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) => item.onChanged(),
));
return FilterTile(child: content);
},
)
],
);
},
),
]),
),
),
),
],
),
ListView.builder(
padding: EdgeInsets.symmetric(vertical: 8.0),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: section.length,
itemBuilder: (_, index2) {
final item = section[index2];
final content = Observer(
builder: (_) => StandardCheckbox(
value: item.value(),
caption: item.caption,
gradientBackground: true,
borderColor:
Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) =>
item.onChanged(),
));
return FilterTile(child: content);
},
)
],
);
},
),
]),
),
),
AlertCloseButton()
],
),
)
],
);
}
}

View file

@ -177,7 +177,7 @@ class MenuWidgetState extends State<MenuWidget> {
fromTopEdge: fromTopEdge,
onTap: () => item.onTap.call(context),
image: item.image,
title: item.name,
title: item.name.call(context),
);
},
separatorBuilder: (_, index) => Container(

View file

@ -9,14 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
class PresentReceiveOptionPicker extends StatelessWidget {
PresentReceiveOptionPicker({required this.receiveOptionViewModel});
PresentReceiveOptionPicker(
{required this.receiveOptionViewModel, this.hasWhiteBackground = false});
final ReceiveOptionViewModel receiveOptionViewModel;
final bool hasWhiteBackground;
@override
Widget build(BuildContext context) {
final arrowBottom =
Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6);
final textIconTheme = hasWhiteBackground
? Theme.of(context).accentTextTheme.headline2!.backgroundColor!
: Colors.white;
final arrowBottom = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: textIconTheme,
height: 6,
);
return TextButton(
onPressed: () => _showPicker(context),
@ -40,14 +48,14 @@ class PresentReceiveOptionPicker extends StatelessWidget {
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!),
color: textIconTheme),
),
Observer(
builder: (_) => Text(receiveOptionViewModel.selectedReceiveOption.toString(),
style: TextStyle(
fontSize: 10.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).textTheme.headline5!.color!)))
color: textIconTheme)))
],
),
SizedBox(width: 5),

View file

@ -280,8 +280,8 @@ class ExchangePage extends BasePage {
return TemplateTile(
key: UniqueKey(),
amount: template.amount,
from: template.depositCurrency,
to: template.receiveCurrency,
from: template.depositCurrencyTitle,
to: template.receiveCurrencyTitle,
onTap: () {
applyTemplate(context, exchangeViewModel, template);
},

View file

@ -239,9 +239,13 @@ class ExchangeTemplatePage extends BasePage {
exchangeViewModel.addTemplate(
amount: exchangeViewModel.depositAmount,
depositCurrency:
exchangeViewModel.depositCurrency.toString(),
exchangeViewModel.depositCurrency.name,
depositCurrencyTitle: exchangeViewModel
.depositCurrency.title + ' ${exchangeViewModel.depositCurrency.tag ?? ''}',
receiveCurrency:
exchangeViewModel.receiveCurrency.toString(),
exchangeViewModel.receiveCurrency.name,
receiveCurrencyTitle: exchangeViewModel
.receiveCurrency.title + ' ${exchangeViewModel.receiveCurrency.tag ?? ''}',
provider: exchangeViewModel.provider.toString(),
depositAddress: exchangeViewModel.depositAddress,
receiveAddress: exchangeViewModel.receiveAddress);

View file

@ -88,13 +88,16 @@ class MoneroAccountListPage extends StatelessWidget {
itemBuilder: (context, index) {
final account = accounts[index];
return AccountTile(
isCurrent: account.isSelected,
accountName: account.label,
onTap: () {
if (account.isSelected) {
return;
}
return AccountTile(
isCurrent: account.isSelected,
accountName: account.label,
accountBalance: account.balance ?? '0.00',
currency: accountListViewModel
.currency.toString(),
onTap: () {
if (account.isSelected) {
return;
}
accountListViewModel
.select(account);

View file

@ -1,45 +1,68 @@
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/generated/i18n.dart';
class AccountTile extends StatelessWidget {
AccountTile({
required this.isCurrent,
required this.accountName,
this.accountBalance,
required this.currency,
required this.onTap,
required this.onEdit
});
final bool isCurrent;
final String accountName;
final String? accountBalance;
final String currency;
final Function() onTap;
final Function() onEdit;
@override
Widget build(BuildContext context) {
final color = isCurrent
? Theme.of(context).textTheme!.subtitle2!.decorationColor!
: Theme.of(context).textTheme!.headline1!.decorationColor!;
? Theme.of(context).textTheme.subtitle2!.decorationColor!
: Theme.of(context).textTheme.headline1!.decorationColor!;
final textColor = isCurrent
? Theme.of(context).textTheme!.subtitle2!.color!
: Theme.of(context).textTheme!.headline1!.color!;
? Theme.of(context).textTheme.subtitle2!.color!
: Theme.of(context).textTheme.headline1!.color!;
final Widget cell = GestureDetector(
onTap: onTap,
child: Container(
height: 77,
padding: EdgeInsets.only(left: 24, right: 24),
alignment: Alignment.centerLeft,
color: color,
child: Text(
accountName,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: textColor,
decoration: TextDecoration.none,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 2,
child: Text(
accountName,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: textColor,
decoration: TextDecoration.none,
),
),
),
if (accountBalance != null)
Expanded(
child: Text(
'${accountBalance.toString()} $currency',
textAlign: TextAlign.end,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
fontFamily: 'Lato',
color: Theme.of(context).textTheme.headline4!.color!,
decoration: TextDecoration.none,
),
),
),
],
),
),
);

View file

@ -71,7 +71,10 @@ class FullscreenQRPage extends BasePage {
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)),
child: QrImage(data: qrViewData.data, version: qrViewData.version),
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.white)),
child: QrImage(data: qrViewData.data, version: qrViewData.version)),
),
),
),

View file

@ -53,7 +53,8 @@ class ReceivePage extends BasePage {
final FocusNode _cryptoAmountFocus;
@override
Color get titleColor => Colors.white;
Color? get titleColor =>
currentTheme.type == ThemeType.bright ? Colors.white : null;
@override
Widget middle(BuildContext context) {

View file

@ -32,7 +32,7 @@ class AnonpayCurrencyInputField extends StatelessWidget {
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
color: Theme.of(context).primaryTextTheme.bodyText1!.color!,
width: 1)),
),
child: Padding(

View file

@ -69,7 +69,7 @@ class AnonInvoiceForm extends StatelessWidget {
BaseTextFormField(
controller: nameController,
focusNode: _nameFocusNode,
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
suffixIcon: SizedBox(width: 36),
hintText: S.of(context).optional_name,
textInputAction: TextInputAction.next,
@ -88,7 +88,7 @@ class AnonInvoiceForm extends StatelessWidget {
controller: descriptionController,
focusNode: _descriptionFocusNode,
textInputAction: TextInputAction.next,
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
suffixIcon: SizedBox(width: 36),
hintText: S.of(context).optional_description,
placeholderTextStyle: TextStyle(
@ -104,7 +104,7 @@ class AnonInvoiceForm extends StatelessWidget {
controller: emailController,
textInputAction: TextInputAction.next,
focusNode: _emailFocusNode,
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
borderColor: Theme.of(context).primaryTextTheme.bodyText1!.color!,
suffixIcon: SizedBox(width: 36),
keyboardType: TextInputType.emailAddress,
hintText: S.of(context).optional_email_hint,

View file

@ -1,4 +1,3 @@
import 'package:cake_wallet/core/amount_validator.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cw_core/currency.dart';
import 'package:flutter/material.dart';
@ -10,18 +9,20 @@ class CurrencyInputField extends StatelessWidget {
required this.onTapPicker,
required this.selectedCurrency,
this.focusNode,
required this.controller,
required this.controller, required this.isLight,
});
final Function() onTapPicker;
final Currency selectedCurrency;
final FocusNode? focusNode;
final TextEditingController controller;
final bool isLight;
@override
Widget build(BuildContext context) {
final arrowBottomPurple = Image.asset(
'assets/images/arrow_bottom_purple_icon.png',
color: Colors.white,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
height: 8,
);
final _width = MediaQuery.of(context).size.width;
@ -38,14 +39,14 @@ class CurrencyInputField extends StatelessWidget {
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
inputFormatters: [FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.|\,)?\d{0,8}'))],
hintText: '0.000',
placeholderTextStyle: TextStyle(
placeholderTextStyle: isLight ? null : TextStyle(
color: Theme.of(context).primaryTextTheme.headline5!.color!,
fontWeight: FontWeight.w600,
),
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
textColor: Colors.white,
textColor: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
textStyle: TextStyle(
color: Colors.white,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
prefixIcon: Padding(
padding: EdgeInsets.only(
@ -68,7 +69,7 @@ class CurrencyInputField extends StatelessWidget {
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
color: Colors.white,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
),
if (selectedCurrency.tag != null)
@ -103,7 +104,8 @@ class CurrencyInputField extends StatelessWidget {
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 20,
color: Colors.white,
color:
Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
),
),

View file

@ -16,14 +16,14 @@ class QrImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return qr.QrImage(
return qr.QrImageView(
data: data,
errorCorrectionLevel: errorCorrectionLevel,
version: version ?? 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
size: size,
foregroundColor: Colors.black,
backgroundColor: Colors.white,
padding: EdgeInsets.zero,
padding: const EdgeInsets.all(8.0),
);
}
}

View file

@ -86,7 +86,14 @@ class QRWidget extends StatelessWidget {
Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
),
child: QrImage(data: addressListViewModel.uri.toString()),
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color:Colors.white,
),
),
child: QrImage(data: addressListViewModel.uri.toString())),
),
),
),
@ -112,6 +119,7 @@ class QRWidget extends StatelessWidget {
controller: amountController,
onTapPicker: () => _presentPicker(context),
selectedCurrency: addressListViewModel.selectedCurrency,
isLight: isLight,
),
),
),

View file

@ -1,83 +0,0 @@
import 'package:flutter/services.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class RestoreFromKeysFrom extends StatefulWidget {
@override
_RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
}
class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
final _formKey = GlobalKey<FormState>();
final _blockchainHeightKey = GlobalKey<BlockchainHeightState>();
final _nameController = TextEditingController();
final _addressController = TextEditingController();
final _viewKeyController = TextEditingController();
final _spendKeyController = TextEditingController();
final _wifController = TextEditingController();
@override
void initState() {
// _nameController.addListener(() =>
// widget.walletRestorationFromKeysVM.name = _nameController.text);
// _addressController.addListener(() =>
// widget.walletRestorationFromKeysVM.address = _addressController.text);
// _viewKeyController.addListener(() =>
// widget.walletRestorationFromKeysVM.viewKey = _viewKeyController.text);
// _spendKeyController.addListener(() =>
// widget.walletRestorationFromKeysVM.spendKey = _spendKeyController.text);
// _wifController.addListener(() =>
// widget.walletRestorationFromKeysVM.wif = _wifController.text);
super.initState();
}
@override
void dispose() {
_nameController.dispose();
_addressController.dispose();
_viewKeyController.dispose();
_spendKeyController.dispose();
_wifController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 24, right: 24),
child: Form(
key: _formKey,
child: Column(children: <Widget>[
BaseTextFormField(
controller: _addressController,
keyboardType: TextInputType.multiline,
maxLines: null,
hintText: S.of(context).restore_address,
),
Container(
padding: EdgeInsets.only(top: 20.0),
child: BaseTextFormField(
controller: _viewKeyController,
hintText: S.of(context).restore_view_key_private,
)),
Container(
padding: EdgeInsets.only(top: 20.0),
child: BaseTextFormField(
controller: _spendKeyController,
hintText: S.of(context).restore_spend_key_private,
)),
BlockchainHeightWidget(
key: _blockchainHeightKey,
onHeightChange: (height) {
// widget.walletRestorationFromKeysVM.height = height;
print(height);
}),
]),
),
);
}
}

View file

@ -25,7 +25,7 @@ class RestoreOptionsPage extends BasePage {
final bool isNewInstall;
final imageSeedKeys = Image.asset('assets/images/restore_wallet_image.png');
final imageBackup = Image.asset('assets/images/backup.png');
final qrCode = Image.asset('assets/images/qr_code_icon.png');
final qrCode = Image.asset('assets/images/restore_qr.png');
@override
Widget body(BuildContext context) {

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:flutter/material.dart';
@ -10,6 +11,8 @@ import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:uni_links/uni_links.dart';
import '../setup_2fa/setup_2fa_enter_code_page.dart';
class Root extends StatefulWidget {
Root({
required Key key,
@ -114,19 +117,49 @@ class RootState extends State<Root> with WidgetsBindingObserver {
if (_isInactive && !_postFrameCallback && _requestAuth) {
_postFrameCallback = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.navigatorKey.currentState?.pushNamed(Routes.unlock,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (!isAuthenticatedSuccessfully) {
return;
}
widget.navigatorKey.currentState?.pushNamed(
Routes.unlock,
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
if (!isAuthenticatedSuccessfully) {
return;
} else {
final useTotp = widget.appStore.settingsStore.useTOTP2FA;
if (useTotp) {
_reset();
auth.close(
route: Routes.totpAuthCodePage,
arguments: TotpAuthArgumentsModel(
onTotpAuthenticationFinished:
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
if (!isAuthenticatedSuccessfully) {
return;
}
_reset();
totpAuth.close(
route: launchUri != null ? Routes.send : null,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
},
isForSetup: false,
isClosable: false,
),
);
} else {
_reset();
auth.close(
route: launchUri != null ? Routes.send : null,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
}
}
_reset();
auth.close(
route: launchUri != null ? Routes.send : null,
arguments: PaymentRequest.fromUri(launchUri),
},
);
launchUri = null;
});
});
} else if (launchUri != null) {
widget.navigatorKey.currentState?.pushNamed(

View file

@ -142,10 +142,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
required this.feeValue,
required this.feeFiatAmount,
required this.outputs})
: itemCount = 0,
recipientTitle = '' {
itemCount = outputs.length;
recipientTitle = itemCount > 1
: recipientTitle = '' {
recipientTitle = outputs.length > 1
? S.current.transaction_details_recipient_address
: S.current.recipient_address;
}
@ -165,7 +163,6 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
ScrollController controller = ScrollController();
double fromTop = 0;
String recipientTitle;
int itemCount;
bool showScrollbar = false;
@override
@ -342,12 +339,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
decoration: TextDecoration.none,
),
),
itemCount > 1
outputs.length > 1
? ListView.builder(
padding: EdgeInsets.only(top: 0),
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: itemCount,
itemCount: outputs.length,
itemBuilder: (context, index) {
final item = outputs[index];
final _address = item.isParsedAddress

View file

@ -548,6 +548,10 @@ class SendCardState extends State<SendCard>
}
void _setEffects(BuildContext context) {
if (_effectsInstalled) {
return;
}
if (output.address.isNotEmpty) {
addressController.text = output.address;
}
@ -558,10 +562,6 @@ class SendCardState extends State<SendCard>
noteController.text = output.note;
extractedAddressController.text = output.extractedAddress;
if (_effectsInstalled) {
return;
}
cryptoAmountController.addListener(() {
final amount = cryptoAmountController.text;

View file

@ -66,7 +66,7 @@ class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
}
},
image: item.image,
title: item.name,
title: item.name.call(context),
);
},
separatorBuilder: (_, index) => Container(

View file

@ -8,7 +8,6 @@ import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'dart:io' show Platform;
class PrivacyPage extends BasePage {
PrivacyPage(this._privacySettingsViewModel);
@ -49,13 +48,24 @@ class PrivacyPage extends BasePage {
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setShouldSaveRecipientAddress(value);
}),
if (Platform.isAndroid)
SettingsSwitcherCell(
title: S.current.prevent_screenshots,
value: _privacySettingsViewModel.isAppSecure,
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setIsAppSecure(value);
}),
SettingsSwitcherCell(
title: S.current.disable_buy,
value: _privacySettingsViewModel.disableBuy,
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setDisableBuy(value);
}),
SettingsSwitcherCell(
title: S.current.disable_sell,
value: _privacySettingsViewModel.disableSell,
onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setDisableSell(value);
}),
],
);
}),

View file

@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -25,63 +26,81 @@ class SecurityBackupPage extends BasePage {
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Column(mainAxisSize: MainAxisSize.min, children: [
SettingsCellWithArrow(
title: S.current.show_keys,
handler: (_) => _authService.authenticateAction(context, route: Routes.showKeys),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.create_backup,
handler: (_) => _authService.authenticateAction(context, route: Routes.backup),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.settings_change_pin,
handler: (_) => _authService.authenticateAction(
context,
route: Routes.setupPin,
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
setupPinContext.close();
},
padding: EdgeInsets.only(top: 10),
child: Column(mainAxisSize: MainAxisSize.min, children: [
SettingsCellWithArrow(
title: S.current.show_keys,
handler: (_) => _authService.authenticateAction(context, route: Routes.showKeys),
),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
Observer(builder: (_) {
return SettingsSwitcherCell(
title: S.current.settings_allow_biometrical_authentication,
value: _securitySettingsViewModel.allowBiometricalAuthentication,
onValueChange: (BuildContext context, bool value) {
if (value) {
_authService.authenticateAction(context,
onAuthSuccess: (isAuthenticatedSuccessfully) async {
if (isAuthenticatedSuccessfully) {
if (await _securitySettingsViewModel.biometricAuthenticated()) {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.create_backup,
handler: (_) => _authService.authenticateAction(context, route: Routes.backup),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
SettingsCellWithArrow(
title: S.current.settings_change_pin,
handler: (_) => _authService.authenticateAction(
context,
route: Routes.setupPin,
arguments: (PinCodeState<PinCodeWidget> setupPinContext, String _) {
setupPinContext.close();
},
),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
if (DeviceInfo.instance.isMobile)
Observer(builder: (_) {
return SettingsSwitcherCell(
title: S.current.settings_allow_biometrical_authentication,
value: _securitySettingsViewModel.allowBiometricalAuthentication,
onValueChange: (BuildContext context, bool value) {
if (value) {
_authService.authenticateAction(context,
onAuthSuccess: (isAuthenticatedSuccessfully) async {
if (isAuthenticatedSuccessfully) {
if (await _securitySettingsViewModel.biometricAuthenticated()) {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
} else {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
}
});
} else {
_securitySettingsViewModel
.setAllowBiometricalAuthentication(isAuthenticatedSuccessfully);
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
}
});
} else {
_securitySettingsViewModel.setAllowBiometricalAuthentication(value);
}
});
}),
Observer(builder: (_) {
return SettingsPickerCell<PinCodeRequiredDuration>(
title: S.current.require_pin_after,
items: PinCodeRequiredDuration.values,
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
onItemSelected: (PinCodeRequiredDuration code) {
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
}),
Observer(builder: (_) {
return SettingsPickerCell<PinCodeRequiredDuration>(
title: S.current.require_pin_after,
items: PinCodeRequiredDuration.values,
selectedItem: _securitySettingsViewModel.pinCodeRequiredDuration,
onItemSelected: (PinCodeRequiredDuration code) {
_securitySettingsViewModel.setPinCodeRequiredDuration(code);
},
);
}),
Observer(
builder: (context) {
return SettingsCellWithArrow(
title: _securitySettingsViewModel.useTotp2FA
? S.current.modify_2fa
: S.current.setup_2fa,
handler: (_) => _authService.authenticateAction(
context,
route: _securitySettingsViewModel.useTotp2FA
? Routes.modify2FAPage
: Routes.setup_2faPage,
),
);
},
);
}),
]),
),
],
),
);
}
}

View file

@ -0,0 +1,55 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import '../../../routes.dart';
class Modify2FAPage extends BasePage {
Modify2FAPage({required this.setup2FAViewModel});
final Setup2FAViewModel setup2FAViewModel;
@override
String get title => S.current.modify_2fa;
@override
Widget body(BuildContext context) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SettingsCellWithArrow(
title: S.current.disable_cake_2fa,
handler: (_) async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.current.disable_cake_2fa,
alertContent: S.current.question_to_disable_2fa,
leftButtonText: S.current.cancel,
rightButtonText: S.current.disable,
actionLeftButton: () {
Navigator.of(context).pop();
},
actionRightButton: () {
setup2FAViewModel.setUseTOTP2FA(false);
Navigator.pushNamedAndRemoveUntil(
context, Routes.dashboard, (route) => false);
},
);
},
);
}),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
],
),
);
}
}

View file

@ -0,0 +1,62 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
import '../../widgets/standard_list.dart';
class Setup2FAPage extends BasePage {
Setup2FAPage({required this.setup2FAViewModel});
final Setup2FAViewModel setup2FAViewModel;
@override
String get title => S.current.setup_2fa;
@override
Widget body(BuildContext context) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.current.important_note,
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 14,
height: 1.571,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
),
),
SizedBox(height: 16),
Text(
S.current.setup_2fa_text,
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 14,
height: 1.571,
color: Theme.of(context).primaryTextTheme.headline6!.color!,
),
),
],
),
),
SizedBox(height: 86),
SettingsCellWithArrow(
title: S.current.setup_totp_recommended,
handler: (_) => Navigator.of(context).pushNamed(Routes.setup_2faQRPage),
),
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
],
),
);
}
}

View file

@ -0,0 +1,221 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/auth_state.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/widgets/popup_cancellable_alert.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
import '../../../palette.dart';
import '../../../routes.dart';
typedef OnTotpAuthenticationFinished = void Function(bool, TotpAuthCodePageState);
class TotpAuthCodePage extends StatefulWidget {
TotpAuthCodePage(
this.setup2FAViewModel, {
required this.totpArguments,
});
final Setup2FAViewModel setup2FAViewModel;
final TotpAuthArgumentsModel totpArguments;
@override
TotpAuthCodePageState createState() => TotpAuthCodePageState();
}
class TotpAuthCodePageState extends State<TotpAuthCodePage> {
final _key = GlobalKey<ScaffoldState>();
ReactionDisposer? _reaction;
Flushbar<void>? _authBar;
Flushbar<void>? _progressBar;
@override
void initState() {
_reaction ??= reaction((_) => widget.setup2FAViewModel.state, (ExecutionState state) {
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.totpArguments.onTotpAuthenticationFinished!(true, this);
});
}
if (state is FailureState) {
print(state.error);
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
});
}
if (state is AuthenticationBanned) {
WidgetsBinding.instance.addPostFrameCallback((_) {
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
});
}
});
super.initState();
}
@override
void dispose() {
_reaction?.reaction.dispose();
super.dispose();
}
void changeProcessText(String text) {
dismissFlushBar(_authBar);
_progressBar = createBar<void>(text, duration: null)..show(_key.currentContext!);
}
Future<void> close({String? route, dynamic arguments}) async {
if (_key.currentContext == null) {
throw Exception('Key context is null. Should be not happened');
}
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
Widget build(BuildContext context) {
return Scaffold(
key: _key,
resizeToAvoidBottomInset: false,
body: TOTPEnterCode(
setup2FAViewModel: widget.setup2FAViewModel,
isForSetup: widget.totpArguments.isForSetup ?? false,
isClosable: widget.totpArguments.isClosable ?? true,
),
);
}
void dismissFlushBar(Flushbar<dynamic>? bar) {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await bar?.dismiss();
});
}
}
class TOTPEnterCode extends BasePage {
TOTPEnterCode({
required this.setup2FAViewModel,
required this.isForSetup,
required this.isClosable,
}) : totpController = TextEditingController() {
totpController.addListener(() {
setup2FAViewModel.enteredOTPCode = totpController.text;
});
}
@override
String get title => isForSetup ? S.current.setup_2fa : S.current.verify_with_2fa;
Widget? leading(BuildContext context) {
return isClosable ? super.leading(context) : null;
}
final TextEditingController totpController;
final Setup2FAViewModel setup2FAViewModel;
final bool isForSetup;
final bool isClosable;
@override
Widget body(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 24,
),
child: Column(
children: [
BaseTextFormField(
textAlign: TextAlign.left,
hintText: S.current.totp_code,
controller: totpController,
keyboardType: TextInputType.number,
placeholderTextStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 16),
Text(
S.current.please_fill_totp,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
height: 1.2,
color: Palette.darkGray,
),
textAlign: TextAlign.center,
),
Spacer(),
Observer(
builder: (context) {
return PrimaryButton(
isDisabled: setup2FAViewModel.enteredOTPCode.length != 8,
onPressed: () async {
final result =
await setup2FAViewModel.totp2FAAuth(totpController.text, isForSetup);
final bannedState = setup2FAViewModel.state is AuthenticationBanned;
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return PopUpCancellableAlertDialog(
contentText: _textDisplayedInPopupOnResult(result, bannedState, context),
actionButtonText: S.of(context).ok,
buttonAction: () {
result ? setup2FAViewModel.success() : null;
if (isForSetup && result) {
Navigator.pushNamedAndRemoveUntil(
context, Routes.dashboard, (route) => false);
} else {
Navigator.of(context).pop(result);
}
},
);
},
);
},
text: S.of(context).continue_text,
color: Theme.of(context).accentTextTheme.bodyLarge!.color!,
textColor: Colors.white,
);
},
),
SizedBox(height: 24),
],
),
);
}
String _textDisplayedInPopupOnResult(bool result, bool bannedState, BuildContext context) {
switch (result) {
case true:
return isForSetup ? S.current.totp_2fa_success : S.current.totp_verification_success;
case false:
if (bannedState) {
final state = setup2FAViewModel.state as AuthenticationBanned;
return S.of(context).failed_authentication(state.error);
} else {
return S.current.totp_2fa_failure;
}
default:
return S.current.enter_totp_code;
}
}
}

View file

@ -0,0 +1,145 @@
import 'package:cake_wallet/core/totp_request_details.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
import 'package:qr_flutter/qr_flutter.dart' as qr;
import '../../../palette.dart';
import '../../widgets/primary_button.dart';
import '../../widgets/standard_list.dart';
class Setup2FAQRPage extends BasePage {
Setup2FAQRPage({required this.setup2FAViewModel});
final Setup2FAViewModel setup2FAViewModel;
@override
String get title => S.current.setup_2fa;
@override
Widget body(BuildContext context) {
final copyImage = Image.asset(
'assets/images/copy_content.png',
height: 12,
width: 12,
color: Color(0xFF355688),
);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
children: [
SizedBox(height: 58),
Text(
S.current.add_secret_code,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w700,
height: 1.5714,
color: Palette.darkBlueCraiola,
),
),
SizedBox(height: 10),
AspectRatio(
aspectRatio: 1.0,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
),
),
child: Container(
decoration: BoxDecoration(
border: Border.all(
width: 3,
color: Colors.white,
),
),
child: QrImage(
data: setup2FAViewModel.totpVersionOneLink,
version: qr.QrVersions.auto,
)),
),
),
SizedBox(height: 13),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.current.totp_secret_code,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Palette.darkGray,
height: 1.8333,
),
),
SizedBox(height: 8),
Text(
'${setup2FAViewModel.secretKey}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
height: 1.375,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
SizedBox(width: 8),
Container(
width: 32,
height: 32,
child: InkWell(
onTap: () {
Clipboard.setData(ClipboardData(text: '${setup2FAViewModel.secretKey}'));
showBar<void>(context, S.of(context).copied_to_clipboard);
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Color(0xFFF2F0FA),
),
child: copyImage,
),
),
)
],
),
SizedBox(height: 8),
StandardListSeparator(),
Spacer(),
PrimaryButton(
onPressed: () {
Navigator.of(context).pushReplacementNamed(
Routes.totpAuthCodePage,
arguments: TotpAuthArgumentsModel(
isForSetup: true,
)
);
},
text: S.current.continue_text,
color: Theme.of(context).accentTextTheme.bodyLarge!.color!,
textColor: Colors.white,
),
SizedBox(height: 24),
],
),
);
}
}

View file

@ -0,0 +1,92 @@
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
class PopUpCancellableAlertDialog extends StatelessWidget {
final String contentText;
final String actionButtonText;
final VoidCallback? buttonAction;
final bool sameActionForButtonAndClose;
const PopUpCancellableAlertDialog({
super.key,
this.contentText = '',
this.actionButtonText = '',
this.buttonAction,
this.sameActionForButtonAndClose = true,
});
bool get barrierDismissible => false;
Color? get actionButtonTextColor => null;
Color? get actionButtonColor => null;
Widget content(BuildContext context) {
return Text(
contentText,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Theme.of(context).primaryTextTheme.titleLarge!.color!,
decoration: TextDecoration.none,
),
);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => barrierDismissible ? Navigator.of(context).pop() : null,
child: AlertBackground(
child: Stack(
alignment: AlignmentDirectional.center,
children: [
Positioned(
top: 280,
child: Column(
children: [
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
width: 340,
padding: EdgeInsets.all(10),
color: Theme.of(context).accentTextTheme.titleLarge!.decorationColor!,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Column(
children: [
Padding(
padding: EdgeInsets.fromLTRB(24, 8, 24, 32),
child: content(context),
),
PrimaryButton(
onPressed: buttonAction,
text: actionButtonText,
color: Color(0xffE9F2FC),
textColor: Palette.darkBlueCraiola,
),
],
),
],
),
),
),
),
],
),
),
AlertCloseButton(
onTap: sameActionForButtonAndClose ? buttonAction : null,
),
],
),
),
);
}
}

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
import 'package:cake_wallet/routes.dart';
import 'package:qr_flutter/qr_flutter.dart';
class WalletKeysPage extends BasePage {
WalletKeysPage(this.walletKeysViewModel);
@ -32,7 +33,7 @@ class WalletKeysPage extends BasePage {
await Navigator.pushNamed(
context,
Routes.fullscreenQR,
arguments: QrViewData(data: url.toString()),
arguments: QrViewData(data: url.toString(), version: QrVersions.auto),
);
// ignore: unawaited_futures
DeviceDisplayBrightness.setBrightness(brightness);

View file

@ -24,6 +24,9 @@ class WalletListPage extends BasePage {
final WalletListViewModel walletListViewModel;
final AuthService authService;
@override
String get title => S.current.wallets;
@override
Widget body(BuildContext context) =>
WalletListBody(walletListViewModel: walletListViewModel, authService: authService);

View file

@ -2,7 +2,8 @@ import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class AlertCloseButton extends StatelessWidget {
AlertCloseButton({this.image, this.bottom});
AlertCloseButton({this.image, this.bottom, this.onTap});
final VoidCallback? onTap;
final Image? image;
final double? bottom;
@ -17,7 +18,7 @@ class AlertCloseButton extends StatelessWidget {
return Positioned(
bottom: bottom ?? 60,
child: GestureDetector(
onTap: () => Navigator.of(context).pop(),
onTap: onTap ?? () => Navigator.of(context).pop(),
child: Container(
height: 42,
width: 42,

View file

@ -1,8 +1,7 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
class CheckBoxPicker extends StatefulWidget {
CheckBoxPicker({
@ -32,73 +31,57 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
@override
Widget build(BuildContext context) {
return AlertBackground(
child: Column(
children: [
Expanded(
child: Stack(
alignment: Alignment.center,
children: [
Column(
return PickerWrapperWidget(
children: [
if (widget.title.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.headline6!.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.65,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (widget.title.isNotEmpty)
Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Text(
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.headline6!.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.65,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Flexible(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
items.length > 3
? Scrollbar(
controller: controller,
child: itemsList(),
)
: itemsList(),
],
),
),
],
),
),
),
children: [
Flexible(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
items.length > 3
? Scrollbar(
controller: controller,
child: itemsList(),
)
: itemsList(),
],
),
),
],
),
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
AlertCloseButton(),
],
),
),
),
],
),
),
],
);
}
@ -111,7 +94,10 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
shrinkWrap: true,
separatorBuilder: (context, index) => widget.isSeparated
? Divider(
color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
color: Theme.of(context)
.accentTextTheme
.headline6!
.backgroundColor!,
height: 1,
)
: const SizedBox(),

View file

@ -2,9 +2,8 @@
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
import 'package:cw_core/currency.dart';
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
class Picker<Item> extends StatefulWidget {
Picker({
@ -114,171 +113,130 @@ class _PickerState<Item> extends State<Picker<Item>> {
final mq = MediaQuery.of(context);
final bottom = mq.viewInsets.bottom;
final height = mq.size.height - bottom;
final screenCenter = height / 2;
double closeButtonBottom = 60;
double containerHeight = height * 0.65;
if (bottom > 0) {
// increase a bit or it gets too squished in the top
containerHeight = height * 0.75;
final containerCenter = containerHeight / 2;
final containerBottom = screenCenter - containerCenter;
final hasTitle = widget.title == null || widget.title!.isEmpty;
// position the close button right below the search container
closeButtonBottom = closeButtonBottom -
containerBottom +
(hasTitle ? padding : padding / 1.5);
}
return AlertBackground(
child: Column(
children: [
Expanded(
flex: 1,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (widget.title?.isNotEmpty ?? false)
Container(
padding: EdgeInsets.symmetric(horizontal: padding),
child: Text(
widget.title!,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context)
.accentTextTheme
.headline6!
.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: containerHeight,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.hintText != null)
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
controller: searchController,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline6!
.color!),
decoration: InputDecoration(
hintText: widget.hintText,
prefixIcon: Image.asset(
"assets/images/search_icon.png"),
filled: true,
fillColor: Theme.of(context)
.accentTextTheme
.headline3!
.color!,
alignLabelWithHint: false,
contentPadding:
const EdgeInsets.symmetric(
vertical: 4, horizontal: 16),
enabledBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
),
),
),
Divider(
color: Theme.of(context)
.accentTextTheme
.headline6!
.backgroundColor!,
height: 1,
),
if (widget.selectedAtIndex != -1)
buildSelectedItem(widget.selectedAtIndex),
Flexible(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
filteredItems.length > 3
? Scrollbar(
controller: controller,
child: itemsList(),
)
: itemsList(),
(widget.description?.isNotEmpty ?? false)
? Positioned(
bottom: padding,
left: padding,
right: padding,
child: Text(
widget.description!,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
fontFamily: 'Lato',
decoration:
TextDecoration.none,
color: Theme.of(context)
.primaryTextTheme
.headline6!
.color!,
),
),
)
: Offstage(),
],
),
),
],
),
),
),
),
)
],
),
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
AlertCloseButton(bottom: closeButtonBottom),
],
return PickerWrapperWidget(
hasTitle: widget.title?.isNotEmpty ?? false,
children: [
if (widget.title?.isNotEmpty ?? false)
Container(
padding: EdgeInsets.symmetric(horizontal: padding),
child: Text(
widget.title!,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.bold,
decoration: TextDecoration.none,
color: Colors.white,
),
),
),
// gives the extra spacing using MediaQuery.viewInsets.bottom
// to simulate a keyboard area
SizedBox(
height: bottom,
)
],
),
Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(30)),
child: Container(
color: Theme.of(context).accentTextTheme.headline6!.color!,
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: containerHeight,
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.hintText != null)
Padding(
padding: const EdgeInsets.all(16),
child: TextFormField(
controller: searchController,
style: TextStyle(
color: Theme.of(context)
.primaryTextTheme
.headline6!
.color!),
decoration: InputDecoration(
hintText: widget.hintText,
prefixIcon:
Image.asset("assets/images/search_icon.png"),
filled: true,
fillColor: Theme.of(context)
.accentTextTheme
.headline3!
.color!,
alignLabelWithHint: false,
contentPadding: const EdgeInsets.symmetric(
vertical: 4, horizontal: 16),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
borderSide: const BorderSide(
color: Colors.transparent,
)),
),
),
),
Divider(
color: Theme.of(context)
.accentTextTheme
.headline6!
.backgroundColor!,
height: 1,
),
if (widget.selectedAtIndex != -1)
buildSelectedItem(widget.selectedAtIndex),
Flexible(
child: Stack(
alignment: Alignment.center,
children: <Widget>[
filteredItems.length > 3
? Scrollbar(
controller: controller,
child: itemsList(),
)
: itemsList(),
(widget.description?.isNotEmpty ?? false)
? Positioned(
bottom: padding,
left: padding,
right: padding,
child: Text(
widget.description!,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
fontFamily: 'Lato',
decoration: TextDecoration.none,
color: Theme.of(context)
.primaryTextTheme
.headline6!
.color!,
),
),
)
: Offstage(),
],
),
),
],
),
),
),
),
)
],
);
}

View file

@ -0,0 +1,61 @@
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
class PickerWrapperWidget extends StatelessWidget {
PickerWrapperWidget({required this.children, this.hasTitle = false});
final List<Widget> children;
final bool hasTitle;
@override
Widget build(BuildContext context) {
final double padding = 24;
final mq = MediaQuery.of(context);
final bottom = mq.viewInsets.bottom;
final height = mq.size.height - bottom;
final screenCenter = height / 2;
double closeButtonBottom = 60;
double containerHeight = height * 0.65;
if (bottom > 0) {
// increase a bit or it gets too squished in the top
containerHeight = height * 0.75;
final containerCenter = containerHeight / 2;
final containerBottom = screenCenter - containerCenter;
// position the close button right below the search container
closeButtonBottom = closeButtonBottom -
containerBottom + (!hasTitle ? padding : padding / 1.5);
}
return AlertBackground(
child: Column(
children: [
Expanded(
flex: 1,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
children: children,
),
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
AlertCloseButton(bottom: closeButtonBottom),
],
),
),
// gives the extra spacing using MediaQuery.viewInsets.bottom
// to simulate a keyboard area
SizedBox(
height: bottom,
)
],
),
);
}
}

View file

@ -3,7 +3,7 @@ import 'package:cake_wallet/routes.dart';
import 'package:flutter/material.dart';
class SettingActions {
final String name;
final String Function(BuildContext) name;
final String image;
final void Function(BuildContext) onTap;
@ -36,7 +36,7 @@ class SettingActions {
];
static SettingActions connectionSettingAction = SettingActions._(
name: S.current.connection_sync,
name: (context) => S.of(context).connection_sync,
image: 'assets/images/nodes_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -45,7 +45,7 @@ class SettingActions {
);
static SettingActions walletSettingAction = SettingActions._(
name: S.current.wallets,
name: (context) => S.of(context).wallets,
image: 'assets/images/wallet_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -54,7 +54,7 @@ class SettingActions {
);
static SettingActions addressBookSettingAction = SettingActions._(
name: S.current.address_book_menu,
name: (context) => S.of(context).address_book_menu,
image: 'assets/images/open_book_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -63,7 +63,7 @@ class SettingActions {
);
static SettingActions securityBackupSettingAction = SettingActions._(
name: S.current.security_and_backup,
name: (context) => S.of(context).security_and_backup,
image: 'assets/images/key_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -72,7 +72,7 @@ class SettingActions {
);
static SettingActions privacySettingAction = SettingActions._(
name: S.current.privacy,
name: (context) => S.of(context).privacy,
image: 'assets/images/privacy_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -81,7 +81,7 @@ class SettingActions {
);
static SettingActions displaySettingAction = SettingActions._(
name: S.current.display_settings,
name: (context) => S.of(context).display_settings,
image: 'assets/images/eye_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -90,7 +90,7 @@ class SettingActions {
);
static SettingActions otherSettingAction = SettingActions._(
name: S.current.other_settings,
name: (context) => S.of(context).other_settings,
image: 'assets/images/settings_menu.png',
onTap: (BuildContext context) {
Navigator.pop(context);
@ -99,7 +99,7 @@ class SettingActions {
);
static SettingActions supportSettingAction = SettingActions._(
name: S.current.settings_support,
name: (context) => S.of(context).settings_support,
image: 'assets/images/question_mark.png',
onTap: (BuildContext context) {
Navigator.pop(context);

View file

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
@ -6,6 +8,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/themes/theme_list.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
@ -21,7 +24,6 @@ import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/entities/action_list_display_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
import 'package:cw_core/set_app_secure_native.dart';
import 'dart:io' show Platform;
part 'settings_store.g.dart';
@ -35,14 +37,20 @@ abstract class SettingsStoreBase with Store {
required BalanceDisplayMode initialBalanceDisplayMode,
required bool initialSaveRecipientAddress,
required bool initialAppSecure,
required bool initialDisableBuy,
required bool initialDisableSell,
required FiatApiMode initialFiatMode,
required bool initialAllowBiometricalAuthentication,
required String initialTotpSecretKey,
required bool initialUseTOTP2FA,
required int initialFailedTokenTrial,
required ExchangeApiMode initialExchangeStatus,
required ThemeBase initialTheme,
required int initialPinLength,
required String initialLanguageCode,
// required String initialCurrentLocale,
required this.appVersion,
required this.deviceName,
required Map<WalletType, Node> nodes,
required this.shouldShowYatPopup,
required this.isBitcoinBuyEnabled,
@ -53,36 +61,41 @@ abstract class SettingsStoreBase with Store {
TransactionPriority? initialHavenTransactionPriority,
TransactionPriority? initialLitecoinTransactionPriority,
TransactionPriority? initialEthereumTransactionPriority})
: nodes = ObservableMap<WalletType, Node>.of(nodes),
_sharedPreferences = sharedPreferences,
fiatCurrency = initialFiatCurrency,
balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress,
: nodes = ObservableMap<WalletType, Node>.of(nodes),
_sharedPreferences = sharedPreferences,
fiatCurrency = initialFiatCurrency,
balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress,
fiatApiMode = initialFiatMode,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
totpSecretKey = initialTotpSecretKey,
useTOTP2FA = initialUseTOTP2FA,
numberOfFailedTokenTrials = initialFailedTokenTrial,
isAppSecure = initialAppSecure,
fiatApiMode = initialFiatMode,
allowBiometricalAuthentication = initialAllowBiometricalAuthentication,
disableBuy = initialDisableBuy,
disableSell = initialDisableSell,
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
exchangeStatus = initialExchangeStatus,
currentTheme = initialTheme,
pinCodeLength = initialPinLength,
languageCode = initialLanguageCode,
priority = ObservableMap<WalletType, TransactionPriority>() {
exchangeStatus = initialExchangeStatus,
currentTheme = initialTheme,
pinCodeLength = initialPinLength,
languageCode = initialLanguageCode,
priority = ObservableMap<WalletType, TransactionPriority>() {
//this.nodes = ObservableMap<WalletType, Node>.of(nodes);
if (initialMoneroTransactionPriority != null) {
priority[WalletType.monero] = initialMoneroTransactionPriority;
priority[WalletType.monero] = initialMoneroTransactionPriority;
}
if (initialBitcoinTransactionPriority != null) {
priority[WalletType.bitcoin] = initialBitcoinTransactionPriority;
priority[WalletType.bitcoin] = initialBitcoinTransactionPriority;
}
if (initialHavenTransactionPriority != null) {
priority[WalletType.haven] = initialHavenTransactionPriority;
priority[WalletType.haven] = initialHavenTransactionPriority;
}
if (initialLitecoinTransactionPriority != null) {
priority[WalletType.litecoin] = initialLitecoinTransactionPriority;
priority[WalletType.litecoin] = initialLitecoinTransactionPriority;
}
if (initialEthereumTransactionPriority != null) {
@ -96,8 +109,8 @@ abstract class SettingsStoreBase with Store {
reaction(
(_) => shouldShowYatPopup,
(bool shouldShowYatPopup) => sharedPreferences
.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
(bool shouldShowYatPopup) =>
sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
priority.observe((change) {
final String? key;
@ -129,55 +142,66 @@ abstract class SettingsStoreBase with Store {
reaction(
(_) => shouldSaveRecipientAddress,
(bool shouldSaveRecipientAddress) => sharedPreferences.setBool(
PreferencesKey.shouldSaveRecipientAddressKey,
shouldSaveRecipientAddress));
PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress));
setIsAppSecureNative(isAppSecure);
reaction((_) => isAppSecure, (bool isAppSecure) {
sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure);
if (Platform.isAndroid) {
setIsAppSecureNative(isAppSecure);
}
});
if (Platform.isAndroid) {
setIsAppSecureNative(isAppSecure);
}
reaction(
(_) => disableBuy,
(bool disableBuy) => sharedPreferences.setBool(
PreferencesKey.disableBuyKey, disableBuy));
reaction(
(_) => fiatApiMode,
(FiatApiMode mode) => sharedPreferences.setInt(
PreferencesKey.currentFiatApiModeKey, mode.serialize()));
(_) => disableSell,
(bool disableSell) => sharedPreferences.setBool(
PreferencesKey.disableSellKey, disableSell));
reaction(
(_) => currentTheme,
(ThemeBase theme) =>
sharedPreferences.setInt(PreferencesKey.currentTheme, theme.raw));
(_) => fiatApiMode,
(FiatApiMode mode) =>
sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, mode.serialize()));
reaction((_) => currentTheme,
(ThemeBase theme) => sharedPreferences.setInt(PreferencesKey.currentTheme, theme.raw));
reaction(
(_) => allowBiometricalAuthentication,
(bool biometricalAuthentication) => sharedPreferences.setBool(
PreferencesKey.allowBiometricalAuthenticationKey,
biometricalAuthentication));
PreferencesKey.allowBiometricalAuthenticationKey, biometricalAuthentication));
reaction(
(_) => useTOTP2FA, (bool use) => sharedPreferences.setBool(PreferencesKey.useTOTP2FA, use));
reaction(
(_) => numberOfFailedTokenTrials,
(int failedTokenTrail) =>
sharedPreferences.setInt(PreferencesKey.failedTotpTokenTrials, failedTokenTrail));
reaction((_) => totpSecretKey,
(String totpKey) => sharedPreferences.setString(PreferencesKey.totpSecretKey, totpKey));
reaction(
(_) => shouldShowMarketPlaceInDashboard,
(bool value) =>
sharedPreferences.setBool(PreferencesKey.shouldShowMarketPlaceInDashboard, value));
reaction(
(_) => pinCodeLength,
(int pinLength) => sharedPreferences.setInt(
PreferencesKey.currentPinLength, pinLength));
reaction((_) => pinCodeLength,
(int pinLength) => sharedPreferences.setInt(PreferencesKey.currentPinLength, pinLength));
reaction(
(_) => languageCode,
(String languageCode) => sharedPreferences.setString(
PreferencesKey.currentLanguageCode, languageCode));
(String languageCode) =>
sharedPreferences.setString(PreferencesKey.currentLanguageCode, languageCode));
reaction(
(_) => pinTimeOutDuration,
(PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt(
PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
(PinCodeRequiredDuration pinCodeInterval) =>
sharedPreferences.setInt(PreferencesKey.pinTimeOutDuration, pinCodeInterval.value));
reaction(
(_) => balanceDisplayMode,
@ -185,17 +209,15 @@ abstract class SettingsStoreBase with Store {
PreferencesKey.currentBalanceDisplayModeKey, mode.serialize()));
reaction(
(_) => exchangeStatus,
(ExchangeApiMode mode) => sharedPreferences.setInt(
PreferencesKey.exchangeStatusKey, mode.serialize()));
(_) => exchangeStatus,
(ExchangeApiMode mode) =>
sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, mode.serialize()));
this
.nodes
.observe((change) {
if (change.newValue != null && change.key != null) {
_saveCurrentNode(change.newValue!, change.key!);
}
});
this.nodes.observe((change) {
if (change.newValue != null && change.key != null) {
_saveCurrentNode(change.newValue!, change.key!);
}
});
}
static const defaultPinLength = 4;
@ -226,9 +248,29 @@ abstract class SettingsStoreBase with Store {
@observable
bool isAppSecure;
@observable
bool disableBuy;
@observable
bool disableSell;
@observable
bool allowBiometricalAuthentication;
@observable
String totpSecretKey;
@computed
String get totpVersionOneLink {
return 'otpauth://totp/Cake%20Wallet:$deviceName?secret=$totpSecretKey&issuer=Cake%20Wallet&algorithm=SHA512&digits=8&period=30';
}
@observable
bool useTOTP2FA;
@observable
int numberOfFailedTokenTrials;
@observable
ExchangeApiMode exchangeStatus;
@ -252,6 +294,8 @@ abstract class SettingsStoreBase with Store {
String appVersion;
String deviceName;
SharedPreferences _sharedPreferences;
ObservableMap<WalletType, Node> nodes;
@ -260,7 +304,7 @@ abstract class SettingsStoreBase with Store {
final node = nodes[walletType];
if (node == null) {
throw Exception('No node found for wallet type: ${walletType.toString()}');
throw Exception('No node found for wallet type: ${walletType.toString()}');
}
return node;
@ -269,10 +313,10 @@ abstract class SettingsStoreBase with Store {
bool isBitcoinBuyEnabled;
bool get shouldShowReceiveWarning =>
_sharedPreferences.getBool(PreferencesKey.shouldShowReceiveWarning) ?? true;
_sharedPreferences.getBool(PreferencesKey.shouldShowReceiveWarning) ?? true;
Future<void> setShouldShowReceiveWarning(bool value) async =>
_sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
_sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
static Future<SettingsStore> load(
{required Box<Node> nodeSource,
@ -280,18 +324,15 @@ abstract class SettingsStoreBase with Store {
FiatCurrency initialFiatCurrency = FiatCurrency.usd,
BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance,
ThemeBase? initialTheme}) async {
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
final currentFiatCurrency = FiatCurrency.deserialize(raw:
sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
final currentFiatCurrency = FiatCurrency.deserialize(
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
TransactionPriority? moneroTransactionPriority =
monero?.deserializeMoneroTransactionPriority(
raw: sharedPreferences
.getInt(PreferencesKey.moneroTransactionPriority)!);
TransactionPriority? moneroTransactionPriority = monero?.deserializeMoneroTransactionPriority(
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!);
TransactionPriority? bitcoinTransactionPriority =
bitcoin?.deserializeBitcoinTransactionPriority(sharedPreferences
.getInt(PreferencesKey.bitcoinTransactionPriority)!);
bitcoin?.deserializeBitcoinTransactionPriority(
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority)!);
TransactionPriority? havenTransactionPriority;
TransactionPriority? litecoinTransactionPriority;
@ -317,37 +358,40 @@ abstract class SettingsStoreBase with Store {
ethereumTransactionPriority ??= ethereum?.getDefaultTransactionPriority();
final currentBalanceDisplayMode = BalanceDisplayMode.deserialize(
raw: sharedPreferences
.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
// FIX-ME: Check for which default value we should have here
final shouldSaveRecipientAddress =
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? false;
final isAppSecure =
sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
final disableBuy =
sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
final disableSell =
sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
final currentFiatApiMode = FiatApiMode.deserialize(
raw: sharedPreferences
.getInt(PreferencesKey.currentFiatApiModeKey) ?? FiatApiMode.enabled.raw);
final allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
false;
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
FiatApiMode.enabled.raw);
final allowBiometricalAuthentication =
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? false;
final totpSecretKey = sharedPreferences.getString(PreferencesKey.totpSecretKey) ?? '';
final useTOTP2FA = sharedPreferences.getBool(PreferencesKey.useTOTP2FA) ?? false;
final tokenTrialNumber = sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? 0;
final shouldShowMarketPlaceInDashboard =
sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? true;
final exchangeStatus = ExchangeApiMode.deserialize(
raw: sharedPreferences
.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw);
final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index
: ThemeType.bright.index;
final savedTheme = initialTheme ?? ThemeList.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
legacyTheme);
raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
ExchangeApiMode.enabled.raw);
final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index
: ThemeType.bright.index;
final savedTheme = initialTheme ??
ThemeList.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? legacyTheme);
final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
actionListDisplayMode.addAll(deserializeActionlistDisplayModes(
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
defaultActionsMode));
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration);
final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration);
final pinCodeTimeOutDuration = timeOutDuration != null
? PinCodeRequiredDuration.deserialize(raw: timeOutDuration)
: defaultPinCodeTimeOutDuration;
@ -357,43 +401,40 @@ abstract class SettingsStoreBase with Store {
pinLength = defaultPinLength;
}
final savedLanguageCode =
sharedPreferences.getString(PreferencesKey.currentLanguageCode) ??
await LanguageService.localeDetection();
final savedLanguageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ??
await LanguageService.localeDetection();
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final bitcoinElectrumServerId = sharedPreferences
.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final litecoinElectrumServerId = sharedPreferences
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final havenNodeId = sharedPreferences
.getInt(PreferencesKey.currentHavenNodeIdKey);
final ethereumNodeId = sharedPreferences
.getInt(PreferencesKey.currentEthereumNodeIdKey);
final bitcoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final litecoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
final moneroNode = nodeSource.get(nodeId);
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
final havenNode = nodeSource.get(havenNodeId);
final ethereumNode = nodeSource.get(ethereumNodeId);
final packageInfo = await PackageInfo.fromPlatform();
final shouldShowYatPopup =
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
final deviceName = await _getDeviceName() ?? '';
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
final nodes = <WalletType, Node>{};
if (moneroNode != null) {
nodes[WalletType.monero] = moneroNode;
nodes[WalletType.monero] = moneroNode;
}
if (bitcoinElectrumServer != null) {
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
}
if (litecoinElectrumServer != null) {
nodes[WalletType.litecoin] = litecoinElectrumServer;
nodes[WalletType.litecoin] = litecoinElectrumServer;
}
if (havenNode != null) {
nodes[WalletType.haven] = havenNode;
nodes[WalletType.haven] = havenNode;
}
if (ethereumNode != null) {
@ -405,13 +446,19 @@ abstract class SettingsStoreBase with Store {
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
nodes: nodes,
appVersion: packageInfo.version,
deviceName: deviceName,
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
initialFiatCurrency: currentFiatCurrency,
initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAppSecure: isAppSecure,
initialDisableBuy: disableBuy,
initialDisableSell: disableSell,
initialFiatMode: currentFiatApiMode,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialTotpSecretKey: totpSecretKey,
initialUseTOTP2FA: useTOTP2FA,
initialFailedTokenTrial: tokenTrialNumber,
initialExchangeStatus: exchangeStatus,
initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode,
@ -427,27 +474,26 @@ abstract class SettingsStoreBase with Store {
}
Future<void> reload({required Box<Node> nodeSource}) async {
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
fiatCurrency = FiatCurrency.deserialize(
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
priority[WalletType.monero] = monero?.deserializeMoneroTransactionPriority(
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
priority[WalletType.monero]!;
priority[WalletType.bitcoin] = bitcoin?.deserializeBitcoinTransactionPriority(
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ??
priority[WalletType.bitcoin]!;
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
priority[WalletType.haven] = monero?.deserializeMoneroTransactionPriority(
raw: sharedPreferences.getInt(PreferencesKey.havenTransactionPriority)!) ??
raw: sharedPreferences.getInt(PreferencesKey.havenTransactionPriority)!) ??
priority[WalletType.haven]!;
}
if (sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority) != null) {
priority[WalletType.litecoin] = bitcoin?.deserializeLitecoinTransactionPriority(
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!) ??
sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!) ??
priority[WalletType.litecoin]!;
}
if (sharedPreferences.getInt(PreferencesKey.ethereumTransactionPriority) != null) {
@ -457,12 +503,21 @@ abstract class SettingsStoreBase with Store {
}
balanceDisplayMode = BalanceDisplayMode.deserialize(
raw: sharedPreferences
.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
raw: sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey)!);
shouldSaveRecipientAddress =
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ??
shouldSaveRecipientAddress;
totpSecretKey = sharedPreferences.getString(PreferencesKey.totpSecretKey) ?? totpSecretKey;
useTOTP2FA = sharedPreferences.getBool(PreferencesKey.useTOTP2FA) ?? useTOTP2FA;
numberOfFailedTokenTrials =
sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? numberOfFailedTokenTrials;
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? shouldSaveRecipientAddress;
isAppSecure =
sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
disableBuy =
sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
disableSell =
sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
allowBiometricalAuthentication;
@ -470,19 +525,16 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ??
shouldShowMarketPlaceInDashboard;
exchangeStatus = ExchangeApiMode.deserialize(
raw: sharedPreferences
.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw);
final legacyTheme =
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index
: ThemeType.bright.index;
raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ??
ExchangeApiMode.enabled.raw);
final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
? ThemeType.dark.index
: ThemeType.bright.index;
currentTheme = ThemeList.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
legacyTheme);
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? legacyTheme);
actionlistDisplayMode = ObservableList<ActionListDisplayMode>();
actionlistDisplayMode.addAll(deserializeActionlistDisplayModes(
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
defaultActionsMode));
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode));
var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength);
// If no value
if (pinLength == null || pinLength == 0) {
@ -491,17 +543,16 @@ abstract class SettingsStoreBase with Store {
pinCodeLength = pinLength;
languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode;
shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
shouldShowYatPopup =
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final bitcoinElectrumServerId = sharedPreferences
.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final litecoinElectrumServerId = sharedPreferences
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final havenNodeId = sharedPreferences
.getInt(PreferencesKey.currentHavenNodeIdKey);
final ethereumNodeId = sharedPreferences
.getInt(PreferencesKey.currentEthereumNodeIdKey);
final bitcoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final litecoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
final moneroNode = nodeSource.get(nodeId);
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
@ -540,16 +591,13 @@ abstract class SettingsStoreBase with Store {
PreferencesKey.currentLitecoinElectrumSererIdKey, node.key as int);
break;
case WalletType.monero:
await _sharedPreferences.setInt(
PreferencesKey.currentNodeIdKey, node.key as int);
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, node.key as int);
break;
case WalletType.haven:
await _sharedPreferences.setInt(
PreferencesKey.currentHavenNodeIdKey, node.key as int);
await _sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, node.key as int);
break;
case WalletType.ethereum:
await _sharedPreferences.setInt(
PreferencesKey.currentEthereumNodeIdKey, node.key as int);
await _sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, node.key as int);
break;
default:
break;
@ -557,4 +605,29 @@ abstract class SettingsStoreBase with Store {
nodes[walletType] = node;
}
static Future<String?> _getDeviceName() async {
String? deviceName = '';
final deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
final androidInfo = await deviceInfoPlugin.androidInfo;
deviceName = '${androidInfo.brand}%20${androidInfo.manufacturer}%20${androidInfo.model}';
print(deviceName);
} else if (Platform.isIOS) {
final iosInfo = await deviceInfoPlugin.iosInfo;
deviceName = iosInfo.model;
} else if (Platform.isLinux) {
final linuxInfo = await deviceInfoPlugin.linuxInfo;
deviceName = linuxInfo.prettyName;
} else if (Platform.isMacOS) {
final macInfo = await deviceInfoPlugin.macOsInfo;
deviceName = macInfo.computerName;
} else if (Platform.isWindows) {
final windowsInfo = await deviceInfoPlugin.windowsInfo;
deviceName = windowsInfo.productName;
}
return deviceName;
}
}

View file

@ -8,8 +8,8 @@ part 'exchange_template_store.g.dart';
class ExchangeTemplateStore = ExchangeTemplateBase with _$ExchangeTemplateStore;
abstract class ExchangeTemplateBase with Store {
ExchangeTemplateBase({required this.templateSource})
: templates = ObservableList<ExchangeTemplate>() {
ExchangeTemplateBase({required this.templateSource})
: templates = ObservableList<ExchangeTemplate>() {
templates = ObservableList<ExchangeTemplate>();
update();
}
@ -20,27 +20,31 @@ abstract class ExchangeTemplateBase with Store {
Box<ExchangeTemplate> templateSource;
@action
void update() =>
templates.replaceRange(0, templates.length, templateSource.values.toList());
void update() => templates.replaceRange(0, templates.length, templateSource.values.toList());
@action
Future<void> addTemplate({
required String amount,
required String depositCurrency,
required String receiveCurrency,
required String provider,
required String depositAddress,
required String receiveAddress}) async {
required String amount,
required String depositCurrency,
required String receiveCurrency,
required String provider,
required String depositAddress,
required String receiveAddress,
required String depositCurrencyTitle,
required String receiveCurrencyTitle,
}) async {
final template = ExchangeTemplate(
amountRaw: amount,
depositCurrencyRaw: depositCurrency,
receiveCurrencyRaw: receiveCurrency,
providerRaw: provider,
depositAddressRaw: depositAddress,
receiveAddressRaw: receiveAddress);
receiveAddressRaw: receiveAddress,
depositCurrencyTitleRaw: depositCurrencyTitle,
receiveCurrencyTitleRaw: receiveCurrencyTitle);
await templateSource.add(template);
}
@action
Future<void> remove({required ExchangeTemplate template}) async => await template.delete();
}
Future<void> remove({required ExchangeTemplate template}) async => await template.delete();
}

View file

@ -141,9 +141,9 @@ class ExceptionHandler {
"errno = 103", // SocketException: Software caused connection abort
"errno = 104", // SocketException: Connection reset by peer
"errno = 110", // SocketException: Connection timed out
"HttpException: Connection reset by peer",
"HttpException: Connection closed before full header was received",
"HandshakeException: Connection terminated during handshake",
"Connection reset by peer",
"Connection closed before full header was received",
"Connection terminated during handshake",
"PERMISSION_NOT_GRANTED",
];
@ -172,7 +172,7 @@ class ExceptionHandler {
}
await file.writeAsString(
"App Version: $currentVersion\n\nDevice Info $deviceInfo",
"App Version: $currentVersion\n\nDevice Info $deviceInfo\n\n",
mode: FileMode.append,
);
}
@ -193,6 +193,7 @@ class ExceptionHandler {
'systemVersion': data.systemVersion,
'model': data.model,
'localizedModel': data.localizedModel,
'isPhysicalDevice': data.isPhysicalDevice,
};
}

83
lib/utils/totp_utils.dart Normal file
View file

@ -0,0 +1,83 @@
import 'dart:math';
import 'package:base32/base32.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/foundation.dart';
//*========================== TOTP 2FA Related Utilities ==========================================
String generateRandomBase32SecretKey(int byteLength) {
final Random _secureRandom = Random.secure();
// Generate random bytes
final randomBytes = Uint8List.fromList(
List<int>.generate(byteLength, (i) => _secureRandom.nextInt(256)),
);
// Encode bytes to base32
final base32SecretKey = base32.encode(randomBytes);
return base32SecretKey;
}
String generateOTP({required String secretKey, required int input}) {
/// base32 decode the secret
var hmacKey = base32.decode(secretKey);
/// initial the HMAC-SHA1 object
var hmacSha = Hmac(sha512, hmacKey);
/// get hmac answer
var hmac = hmacSha.convert(intToBytelist(input: input)).bytes;
/// calculate the init offset
int offset = hmac[hmac.length - 1] & 0xf;
/// calculate the code
int code = ((hmac[offset] & 0x7f) << 24 |
(hmac[offset + 1] & 0xff) << 16 |
(hmac[offset + 2] & 0xff) << 8 |
(hmac[offset + 3] & 0xff));
/// get the initial string code
var strCode = (code % pow(10, 8)).toString();
strCode = strCode.padLeft(8, '0');
return strCode;
}
List<int> intToBytelist({required int input, int padding = 8}) {
List<int> _result = [];
var _input = input;
while (_input != 0) {
_result.add(_input & 0xff);
_input >>= padding;
}
_result.addAll(List<int>.generate(padding, (_) => 0));
_result = _result.sublist(0, padding);
_result = _result.reversed.toList();
return _result;
}
String totpNow(String secretKey) {
int _formatTime = timeFormat(time: DateTime.now());
return generateOTP(input: _formatTime, secretKey: secretKey);
}
int timeFormat({required DateTime time}) {
final _timeStr = time.millisecondsSinceEpoch.toString();
final _formatTime = _timeStr.substring(0, _timeStr.length - 3);
return int.parse(_formatTime) ~/ 30;
}
bool verify({String? otp, DateTime? time, required String secretKey}) {
if (otp == null) {
return false;
}
var _time = time ?? DateTime.now();
var _input = timeFormat(time: _time);
String otpTime = generateOTP(input: _input, secretKey: secretKey);
return otp == otpTime;
}

View file

@ -46,9 +46,7 @@ abstract class DashboardViewModelBase with Store {
required this.anonpayTransactionsStore})
: isOutdatedElectrumWallet = false,
hasSellAction = false,
isEnabledSellAction = false,
hasBuyAction = false,
isEnabledBuyAction = false,
hasExchangeAction = false,
isShowFirstYatIntroduction = false,
isShowSecondYatIntroduction = false,
@ -287,14 +285,19 @@ abstract class DashboardViewModelBase with Store {
@observable
bool hasExchangeAction;
@observable
bool isEnabledBuyAction;
@computed
bool get isEnabledBuyAction =>
!settingsStore.disableBuy && wallet.type != WalletType.haven;
@observable
bool hasBuyAction;
@observable
bool isEnabledSellAction;
@computed
bool get isEnabledSellAction =>
!settingsStore.disableSell &&
wallet.type != WalletType.haven &&
wallet.type != WalletType.monero &&
wallet.type != WalletType.litecoin;
@observable
bool hasSellAction;
@ -398,11 +401,7 @@ abstract class DashboardViewModelBase with Store {
void updateActions() {
hasExchangeAction = !isHaven;
isEnabledBuyAction = wallet.type != WalletType.haven;
hasBuyAction = !isHaven;
isEnabledSellAction = wallet.type != WalletType.haven
&& wallet.type != WalletType.monero
&& wallet.type != WalletType.litecoin;
hasSellAction = !isHaven;
}
}

View file

@ -123,8 +123,8 @@ abstract class ExchangeTradeViewModelBase with Store {
}
void _updateItems() {
final tagFrom = trade.from.tag != null ? '${trade.from.tag}' + ' ' : '';
final tagTo = trade.to.tag != null ? '${trade.to.tag}' + ' ' : '';
final tagFrom = tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : '';
final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : '';
items.clear();
items.add(ExchangeTradeItem(
title: "${trade.provider.title} ${S.current.id}", data: '${trade.id}', isCopied: true));
@ -142,11 +142,11 @@ abstract class ExchangeTradeViewModelBase with Store {
items.addAll([
ExchangeTradeItem(title: S.current.amount, data: '${trade.amount}', isCopied: true),
ExchangeTradeItem(
title: S.current.send_to_this_address('${trade.from}', tagFrom) + ':',
title: S.current.send_to_this_address('${tradesStore.trade!.from}', tagFrom) + ':',
data: trade.inputAddress ?? '',
isCopied: true),
ExchangeTradeItem(
title: S.current.arrive_in_this_address('${trade.to}', tagTo) + ':',
title: S.current.arrive_in_this_address('${tradesStore.trade!.to}', tagTo) + ':',
data: trade.payoutAddress ?? '',
isCopied: true),
]);

View file

@ -3,7 +3,6 @@ import 'dart:collection';
import 'dart:convert';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/fiat_api_mode.dart';
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';
@ -244,7 +243,7 @@ abstract class ExchangeViewModelBase with Store {
List<CryptoCurrency> depositCurrencies;
NumberFormat _cryptoNumberFormat;
final NumberFormat _cryptoNumberFormat;
final SettingsStore _settingsStore;
@ -388,27 +387,36 @@ abstract class ExchangeViewModelBase with Store {
double? lowestMin = double.maxFinite;
double? highestMax = 0.0;
for (var provider in selectedProviders) {
/// if this provider is not valid for the current pair, skip it
if (!providersForCurrentPair().contains(provider)) {
continue;
}
try {
final tempLimits = await provider.fetchLimits(
from: from,
to: to,
isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min;
try {
for (var provider in selectedProviders) {
/// if this provider is not valid for the current pair, skip it
if (!providersForCurrentPair().contains(provider)) {
continue;
}
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
highestMax = tempLimits.max;
try {
final tempLimits = await provider.fetchLimits(
from: from,
to: to,
isFixedRateMode: isFixedRateMode);
if (lowestMin != null && (tempLimits.min ?? -1) < lowestMin) {
lowestMin = tempLimits.min;
}
if (highestMax != null && (tempLimits.max ?? double.maxFinite) > highestMax) {
highestMax = tempLimits.max;
}
} catch (e) {
continue;
}
} catch (e) {
continue;
}
} on ConcurrentModificationError {
/// if user changed the selected providers while fetching limits
/// then delay the fetching limits a bit and try again
///
/// this is because the limitation of collections that
/// you can't modify it while iterating through it
Future.delayed(Duration(milliseconds: 200), loadLimits);
}
if (lowestMin != double.maxFinite) {
@ -534,7 +542,7 @@ abstract class ExchangeViewModelBase with Store {
///
/// this is because the limitation of the SplayTreeMap that
/// you can't modify it while iterating through it
Future.delayed(Duration(milliseconds: 500), createTrade);
Future.delayed(Duration(milliseconds: 200), createTrade);
}
}
@ -578,14 +586,18 @@ abstract class ExchangeViewModelBase with Store {
required String receiveCurrency,
required String provider,
required String depositAddress,
required String receiveAddress}) =>
required String receiveAddress,
required String depositCurrencyTitle,
required String receiveCurrencyTitle}) =>
_exchangeTemplateStore.addTemplate(
amount: amount,
depositCurrency: depositCurrency,
receiveCurrency: receiveCurrency,
provider: provider,
depositAddress: depositAddress,
receiveAddress: receiveAddress);
receiveAddress: receiveAddress,
depositCurrencyTitle: depositCurrencyTitle,
receiveCurrencyTitle: receiveCurrencyTitle);
void removeTemplate({required ExchangeTemplate template}) =>
_exchangeTemplateStore.remove(template: template);

View file

@ -1,10 +1,9 @@
import 'package:flutter/foundation.dart';
class AccountListItem {
AccountListItem(
{required this.label, required this.id, this.isSelected = false});
{required this.label, required this.id, this.balance, this.isSelected = false});
final String label;
final int id;
final bool isSelected;
final String? balance;
}

View file

@ -1,3 +1,4 @@
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/wallet_base.dart';
@ -21,6 +22,8 @@ abstract class MoneroAccountListViewModelBase with Store {
this.scrollOffsetFromTop = scrollOffsetFromTop;
}
CryptoCurrency get currency => _wallet.currency;
@computed
List<AccountListItem> get accounts {
if (_wallet.type == WalletType.haven) {
@ -39,6 +42,7 @@ abstract class MoneroAccountListViewModelBase with Store {
.accounts.map((acc) => AccountListItem(
label: acc.label,
id: acc.id,
balance: acc.balance,
isSelected: acc.id == monero!.getCurrentAccount(_wallet).id))
.toList();
}
@ -53,7 +57,9 @@ abstract class MoneroAccountListViewModelBase with Store {
monero!.setCurrentAccount(
_wallet,
item.id,
item.label);
item.label,
item.balance,
);
}
if (_wallet.type == WalletType.haven) {

View file

@ -51,6 +51,7 @@ class WalletRestoreFromQRCode {
static String getFormattedUri(String code) {
final index = code.indexOf(':');
if (index == -1) return throw Exception('Unexpected wallet type: $code, try to scan again');
final scheme = code.substring(0, index).replaceAll('_', '-');
final query = code.substring(index + 1).replaceAll('?', '&');
final formattedUri = '$scheme:?$query';

View file

@ -0,0 +1,159 @@
// ignore_for_file: prefer_final_fields
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/totp_utils.dart' as Utils;
import 'package:cake_wallet/view_model/auth_state.dart';
import 'package:flutter/widgets.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../core/auth_service.dart';
import '../core/execution_state.dart';
import '../generated/i18n.dart';
part 'set_up_2fa_viewmodel.g.dart';
class Setup2FAViewModel = Setup2FAViewModelBase with _$Setup2FAViewModel;
abstract class Setup2FAViewModelBase with Store {
final SettingsStore _settingsStore;
final AuthService _authService;
final SharedPreferences _sharedPreferences;
Setup2FAViewModelBase(this._settingsStore, this._sharedPreferences, this._authService)
: _failureCounter = 0,
enteredOTPCode = '',
state = InitialExecutionState() {
_getRandomBase32SecretKey();
reaction((_) => state, _saveLastAuthTime);
}
static const maxFailedTrials = 3;
static const banTimeout = 180; // 3 minutes
final banTimeoutKey = S.current.auth_store_ban_timeout;
String get secretKey => _settingsStore.totpSecretKey;
String get deviceName => _settingsStore.deviceName;
String get totpVersionOneLink => _settingsStore.totpVersionOneLink;
@observable
ExecutionState state;
@observable
int _failureCounter;
@observable
String enteredOTPCode;
@computed
bool get useTOTP2FA => _settingsStore.useTOTP2FA;
void _getRandomBase32SecretKey() {
final randomBase32Key = Utils.generateRandomBase32SecretKey(16);
_setBase32SecretKey(randomBase32Key);
}
@action
void setUseTOTP2FA(bool value) {
_settingsStore.useTOTP2FA = value;
}
@action
void _setBase32SecretKey(String value) {
if (_settingsStore.totpSecretKey == '') {
_settingsStore.totpSecretKey = value;
}
}
@action
void clearBase32SecretKey() {
_settingsStore.totpSecretKey = '';
}
Duration? banDuration() {
final unbanTimestamp = _sharedPreferences.getInt(banTimeoutKey);
if (unbanTimestamp == null) {
return null;
}
final unbanTime = DateTime.fromMillisecondsSinceEpoch(unbanTimestamp);
final now = DateTime.now();
if (now.isAfter(unbanTime)) {
return null;
}
return Duration(milliseconds: unbanTimestamp - now.millisecondsSinceEpoch);
}
Future<Duration> ban() async {
final multiplier = _failureCounter - maxFailedTrials;
final timeout = (multiplier * banTimeout) * 1000;
final unbanTimestamp = DateTime.now().millisecondsSinceEpoch + timeout;
await _sharedPreferences.setInt(banTimeoutKey, unbanTimestamp);
return Duration(milliseconds: timeout);
}
@action
Future<bool> totp2FAAuth(String otpText, bool isForSetup) async {
state = InitialExecutionState();
_failureCounter = _settingsStore.numberOfFailedTokenTrials;
final _banDuration = banDuration();
if (_banDuration != null) {
state = AuthenticationBanned(
error: S.current.auth_store_banned_for +
'${_banDuration.inMinutes}' +
S.current.auth_store_banned_minutes);
return false;
}
final result = Utils.verify(
secretKey: secretKey,
otp: otpText,
);
isForSetup ? setUseTOTP2FA(result) : null;
if (result) {
return true;
} else {
final value = _settingsStore.numberOfFailedTokenTrials + 1;
adjustTokenTrialNumber(value);
print(value);
if (_failureCounter >= maxFailedTrials) {
final banDuration = await ban();
state = AuthenticationBanned(
error: S.current.auth_store_banned_for +
'${banDuration.inMinutes}' +
S.current.auth_store_banned_minutes);
return false;
}
state = FailureState('Incorrect code');
return false;
}
}
@action
void success() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
state = ExecutedSuccessfullyState();
adjustTokenTrialNumber(0);
});
}
@action
void adjustTokenTrialNumber(int value) {
_failureCounter = value;
_settingsStore.numberOfFailedTokenTrials = value;
}
void _saveLastAuthTime(ExecutionState state) {
if (state is ExecutedSuccessfullyState) {
_authService.saveLastAuthTime();
}
}
}

View file

@ -24,6 +24,12 @@ abstract class PrivacySettingsViewModelBase with Store {
@computed
bool get isAppSecure => _settingsStore.isAppSecure;
@computed
bool get disableBuy => _settingsStore.disableBuy;
@computed
bool get disableSell => _settingsStore.disableSell;
@action
void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value;
@ -36,4 +42,10 @@ abstract class PrivacySettingsViewModelBase with Store {
@action
void setIsAppSecure(bool value) => _settingsStore.isAppSecure = value;
@action
void setDisableBuy(bool value) => _settingsStore.disableBuy = value;
@action
void setDisableSell(bool value) => _settingsStore.disableSell = value;
}

View file

@ -21,6 +21,9 @@ abstract class SecuritySettingsViewModelBase with Store {
@computed
bool get allowBiometricalAuthentication => _settingsStore.allowBiometricalAuthentication;
@computed
bool get useTotp2FA => _settingsStore.useTOTP2FA;
@computed
PinCodeRequiredDuration get pinCodeRequiredDuration => _settingsStore.pinTimeOutDuration;

View file

@ -23,7 +23,7 @@ PODS:
- FlutterMacOS
- devicelocale (0.0.1):
- FlutterMacOS
- flutter_secure_storage_macos (3.3.1):
- flutter_secure_storage_macos (6.1.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- in_app_review (0.2.0):
@ -103,19 +103,19 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
connectivity_macos: 5dae6ee11d320fac7c05f0d08bd08fc32b5514d9
cw_monero: f8b7f104508efba2591548e76b5c058d05cba3f0
cw_monero: ec03de55a19c4a2b174ea687e0f4202edc716fa4
device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
flutter_secure_storage_macos: 6ceee8fbc7f484553ad17f79361b556259df89aa
flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0
package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
platform_device_id: 3e414428f45df149bbbfb623e2c0ca27c545b763
platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451
wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9

View file

@ -423,7 +423,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ARCHS = arm64;
ARCHS = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
@ -557,7 +557,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ARCHS = arm64;
ARCHS = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
@ -585,7 +585,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
buildSettings = {
ARCHS = arm64;
ARCHS = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;

View file

@ -6,15 +6,19 @@ dependencies:
flutter_cupertino_localizations: ^1.0.1
intl: ^0.17.0
url_launcher: ^6.1.4
qr_flutter: ^4.0.0
qr_flutter:
git:
url: https://github.com/cake-tech/qr.flutter.git
ref: cake-4.0.2
version: 4.0.2
uuid: 3.0.6
shared_preferences: ^2.0.15
flutter_secure_storage:
git:
url: https://github.com/cake-tech/flutter_secure_storage.git
path: flutter_secure_storage
ref: cake-6.0.0
version: 6.0.0
ref: cake-8.0.0
version: 8.0.0
# provider: ^6.0.3
rxdart: ^0.27.4
yaml: ^3.1.1
@ -67,6 +71,7 @@ dependencies:
wakelock: ^0.6.2
flutter_mailer: ^2.0.2
device_info_plus: 8.1.0
base32: 2.1.3
in_app_review: ^2.0.6
cake_backup:
git:
@ -77,6 +82,10 @@ dependencies:
path_provider_android: 2.0.24
shared_preferences_android: 2.0.17
url_launcher_android: 6.0.24
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v2
dev_dependencies:
flutter_test:

View file

@ -706,5 +706,24 @@
"error_text_input_below_minimum_limit":" المبلغ أقل من الحد الأدنى",
"error_text_input_above_maximum_limit":"المبلغ أكبر من الحد الأقصى",
"show_market_place": "إظهار السوق",
"prevent_screenshots": "منع لقطات الشاشة وتسجيل الشاشة"
"prevent_screenshots": "منع لقطات الشاشة وتسجيل الشاشة",
"modify_2fa": "تعديل 2 عامل المصادقة",
"disable_cake_2fa": "تعطيل 2 عامل المصادقة",
"question_to_disable_2fa":"هل أنت متأكد أنك تريد تعطيل Cake 2FA؟ لن تكون هناك حاجة إلى رمز 2FA للوصول إلى المحفظة ووظائف معينة.",
"disable": "إبطال",
"setup_2fa": "تعيين 2 عامل المصادقة",
"verify_with_2fa": "تحقق مع Cake 2FA",
"totp_code": "كود TOTP",
"please_fill_totp": "يرجى ملء الرمز المكون من 8 أرقام الموجود على جهازك الآخر",
"totp_2fa_success": "نجاح! تم تمكين Cake 2FA لهذه المحفظة. تذكر حفظ بذرة ذاكري في حالة فقد الوصول إلى المحفظة.",
"totp_verification_success" :"تم التحقق بنجاح!",
"totp_2fa_failure": "شفرة خاطئة. يرجى تجربة رمز مختلف أو إنشاء مفتاح سري جديد. استخدم تطبيق 2FA متوافقًا يدعم الرموز المكونة من 8 أرقام و SHA512.",
"enter_totp_code": "الرجاء إدخال رمز TOTP.",
"add_secret_code":"أضف هذا الرمز السري إلى جهاز آخر",
"totp_secret_code":"كود TOTP السري",
"important_note": "ملاحظة مهمة",
"setup_2fa_text": "كعكة 2FA ليست آمنة مثل التخزين البارد. تحمي 2FA من الأنواع الأساسية للهجمات ، مثل قيام صديقك بتقديم بصمة إصبعك أثناء نومك. لا تحمي Cake 2FA من جهاز مخترق من قِبل مهاجم متطور. إذا فقدت الوصول إلى رموز 2FA الخاصة بك ، ستفقد إمكانية الوصول إلى هذه المحفظة. سوف تحتاج إلى استعادة محفظتك من بذرة ذاكري. يجب عليك بالتالي الاحتفاظ بنسخة احتياطية من بذور الذاكرة الخاصة بك! علاوة على ذلك ، سيتمكن أي شخص لديه حق الوصول إلى بذرة (بذور) ذاكري من سرقة أموالك ، متجاوزًا Cake 2FA. لن يتمكن فريق دعم الكيك من مساعدتك إذا فقدت الوصول إلى بذرتك ، نظرًا لأن Cake هي المحفظة غير الحافظة.",
"setup_totp_recommended": "إعداد TOTP (موصى به)",
"disable_buy": "تعطيل إجراء الشراء",
"disable_sell": "قم بتعطيل إجراء البيع"
}

View file

@ -702,5 +702,24 @@
"error_text_input_below_minimum_limit" : "Сумата е по-малко от минималната",
"error_text_input_above_maximum_limit" : "Сумата надвишава максималната",
"show_market_place":"Покажи пазар",
"prevent_screenshots": "Предотвратете екранни снимки и запис на екрана"
"prevent_screenshots": "Предотвратете екранни снимки и запис на екрана",
"modify_2fa": "Модифициране на тортата 2FA",
"disable_cake_2fa": "Деактивирайте Cake 2FA",
"question_to_disable_2fa":"Сигурни ли сте, че искате да деактивирате Cake 2FA? Вече няма да е необходим 2FA код за достъп до портфейла и определени функции.",
"disable": "Деактивиране",
"setup_2fa": "Настройка на Cake 2FA",
"verify_with_2fa": "Проверете с Cake 2FA",
"totp_code": "TOTP код",
"please_fill_totp": "Моля, попълнете 8-цифрения код на другото ви устройство",
"totp_2fa_success": "Успех! Cake 2FA е активиран за този портфейл. Не забравяйте да запазите мнемоничното начало, в случай че загубите достъп до портфейла.",
"totp_verification_success" :"Проверката е успешна!",
"totp_2fa_failure": "Грешен код. Моля, опитайте с различен код или генерирайте нов таен ключ. Използвайте съвместимо 2FA приложение, което поддържа 8-цифрени кодове и SHA512.",
"enter_totp_code": "Моля, въведете TOTP кода.",
"add_secret_code":"Добавете този таен код към друго устройство",
"totp_secret_code":"TOTP таен код",
"important_note": "Важна забележка",
"setup_2fa_text": "Тортата 2FA НЕ е толкова сигурна, колкото хладилното съхранение. 2FA защитава срещу основни видове атаки, като например вашият приятел да предостави вашия пръстов отпечатък, докато спите.\n\n Cake 2FA НЕ защитава срещу компрометирано устройство от сложен хакер.\n\n Ако загубите достъп до своите 2FA кодове , ЩЕ ЗАГУБИТЕ ДОСТЪП ДО ТОЗИ ПОРТФЕЙЛ. Ще трябва да възстановите портфейла си от мнемонично семе. ЗАТОВА ТРЯБВА ДА НАПРАВИТЕ РЕЗЕРВНО КОПИЕ НА ВАШИТЕ МНЕМОНИЧНИ СЕМЕНА! Освен това, някой с достъп до вашите мнемонични начални точки ще може да открадне вашите средства, заобикаляйки Cake 2FA.\n\n Персоналът по поддръжката на Cake няма да може да ви помогне, ако загубите достъп до вашите мнемонични начални стойности, тъй като Cake е портфейл без попечителство.",
"setup_totp_recommended": "Настройка на TOTP (препоръчително)",
"disable_buy": "Деактивирайте действието за покупка",
"disable_sell": "Деактивирайте действието за продажба"
}

View file

@ -702,5 +702,24 @@
"error_text_input_below_minimum_limit" : "Částka je menší než minimální hodnota",
"error_text_input_above_maximum_limit" : "Částka je větší než maximální hodnota",
"show_market_place": "Zobrazit trh",
"prevent_screenshots": "Zabránit vytváření snímků obrazovky a nahrávání obrazovky"
"prevent_screenshots": "Zabránit vytváření snímků obrazovky a nahrávání obrazovky",
"modify_2fa": "Upravte Cake 2FA",
"disable_cake_2fa": "Zakázat Cake 2FA",
"question_to_disable_2fa":"Opravdu chcete deaktivovat Cake 2FA? Pro přístup k peněžence a některým funkcím již nebude potřeba kód 2FA.",
"disable": "Zakázat",
"setup_2fa": "Nastavení Cake 2FA",
"verify_with_2fa": "Ověřte pomocí Cake 2FA",
"totp_code": "Kód TOTP",
"please_fill_totp": "Vyplňte prosím 8místný kód na vašem druhém zařízení",
"totp_2fa_success": "Úspěch! Pro tuto peněženku povolen Cake 2FA. Nezapomeňte si uložit mnemotechnický klíč pro případ, že ztratíte přístup k peněžence.",
"totp_verification_success" :"Ověření proběhlo úspěšně!",
"totp_2fa_failure": "Nesprávný kód. Zkuste prosím jiný kód nebo vygenerujte nový tajný klíč. Použijte kompatibilní aplikaci 2FA, která podporuje 8místné kódy a SHA512.",
"enter_totp_code": "Zadejte kód TOTP.",
"add_secret_code":"Přidejte tento tajný kód do jiného zařízení",
"totp_secret_code":"Tajný kód TOTP",
"important_note": "Důležitá poznámka",
"setup_2fa_text": "Cake 2FA NENÍ tak bezpečný jako skladování v chladu. 2FA chrání před základními typy útoků, jako je váš přítel, který vám poskytne otisk prstu, když spíte.\n\n Cake 2FA nechrání před napadením zařízení sofistikovaným útočníkem.\n\n Pokud ztratíte přístup ke svým kódům 2FA , ZTRÁTÍTE PŘÍSTUP K TÉTO PENĚŽENCE. Budete muset obnovit svou peněženku z mnemotechnického semínka. MUSÍTE TEDY ZÁLOHOVAT SVÉ MNEMONICKÉ SEMÉNKY! Kromě toho někdo s přístupem k vašemu mnemotechnickému semenu bude moci ukrást vaše finanční prostředky a obejít Cake 2FA.\n\n Pracovníci podpory Cake vám nebudou schopni pomoci, pokud ztratíte přístup k vašemu mnemotechnickému semenu, protože Cake je nevazební peněženka.",
"setup_totp_recommended": "Nastavit TOTP (doporučeno)",
"disable_buy": "Zakázat akci nákupu",
"disable_sell": "Zakázat akci prodeje"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Menge ist unter dem Minimum",
"error_text_input_above_maximum_limit" : "Menge ist über dem Maximum",
"show_market_place": "Marktplatz anzeigen",
"prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen"
"prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen",
"modify_2fa": "Kuchen 2FA ändern",
"disable_cake_2fa": "Kuchen 2FA deaktivieren",
"question_to_disable_2fa":"Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Brieftasche und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
"disable": "Deaktivieren",
"setup_2fa": "Setup-Kuchen 2FA",
"verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
"totp_code": "TOTP-Code",
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
"totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Brieftasche verlieren.",
"totp_verification_success" :"Verifizierung erfolgreich!",
"totp_2fa_failure": "Falscher Code. Bitte versuchen Sie es mit einem anderen Code oder generieren Sie einen neuen geheimen Schlüssel. Verwenden Sie eine kompatible 2FA-App, die 8-stellige Codes und SHA512 unterstützt.",
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
"add_secret_code":"Fügen Sie diesen Geheimcode einem anderen Gerät hinzu",
"totp_secret_code":"TOTP-Geheimcode",
"important_note": "Wichtiger Hinweis",
"setup_2fa_text": "Cake 2FA ist NICHT so sicher wie eine Kühllagerung. 2FA schützt vor grundlegenden Arten von Angriffen, z. B. wenn Ihr Freund Ihren Fingerabdruck bereitstellt, während Sie schlafen.\n\n Cake 2FA schützt NICHT vor einem kompromittierten Gerät durch einen raffinierten Angreifer.\n\n Wenn Sie den Zugriff auf Ihre 2FA-Codes verlieren , VERLIEREN SIE DEN ZUGANG ZU DIESEM WALLET. Sie müssen Ihre Brieftasche aus mnemonic Seed wiederherstellen. SIE MÜSSEN DESHALB IHRE MNEMONISCHEN SEEDS SICHERN! Außerdem kann jemand mit Zugriff auf Ihre mnemonischen Seed(s) Ihr Geld stehlen und Cake 2FA umgehen.\n\n Cake-Supportmitarbeiter können Ihnen nicht helfen, wenn Sie den Zugriff auf Ihre mnemonischen Seed(s) verlieren, da Cake ein Brieftasche ohne Verwahrung.",
"setup_totp_recommended": "TOTP einrichten (empfohlen)",
"disable_buy": "Kaufaktion deaktivieren",
"disable_sell": "Verkaufsaktion deaktivieren"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Amount is less than the minimum",
"error_text_input_above_maximum_limit" : "Amount is more than the maximum",
"show_market_place" :"Show Marketplace",
"prevent_screenshots": "Prevent screenshots and screen recording"
"prevent_screenshots": "Prevent screenshots and screen recording",
"modify_2fa": "Modify Cake 2FA",
"disable_cake_2fa": "Disable Cake 2FA",
"question_to_disable_2fa":"Are you sure that you want to disable Cake 2FA? A 2FA code will no longer be needed to access the wallet and certain functions.",
"disable": "Disable",
"setup_2fa": "Setup Cake 2FA",
"verify_with_2fa": "Verify with Cake 2FA",
"totp_code": "TOTP Code",
"please_fill_totp": "Please fill in the 8-digit code present on your other device",
"totp_2fa_success": "Success! Cake 2FA enabled for this wallet. Remember to save your mnemonic seed in case you lose wallet access.",
"totp_verification_success" :"Verification Successful!",
"totp_2fa_failure": "Incorrect code. Please try a different code or generate a new secret key. Use a compatible 2FA app that supports 8-digit codes and SHA512.",
"enter_totp_code": "Please enter the TOTP Code.",
"add_secret_code":"Add this secret code to another device",
"totp_secret_code":"TOTP Secret Code",
"important_note": "Important note",
"setup_2fa_text": "Cake 2FA is NOT as secure as cold storage. 2FA protects against basic types of attacks, such as your friend providing your fingerprint while you are sleeping.\n\n Cake 2FA does NOT protect against a compromised device by a sophisticated attacker.\n\n If you lose access to your 2FA codes, YOU WILL LOSE ACCESS TO THIS WALLET. You will need to restore your wallet from mnemonic seed. YOU MUST THEREFORE BACK UP YOUR MNEMONIC SEEDS! Further, someone with access to your mnemonic seed(s) will be able to steal your funds, bypassing Cake 2FA.\n\n Cake support staff will be unable to assist you if you lose access to your mnemonic seed, since Cake is a noncustodial wallet.",
"setup_totp_recommended": "Set up TOTP (Recommended)",
"disable_buy": "Disable buy action",
"disable_sell": "Disable sell action"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "La cantidad es menos que mínima",
"error_text_input_above_maximum_limit" : "La cantidad es más que el máximo",
"show_market_place": "Mostrar mercado",
"prevent_screenshots": "Evitar capturas de pantalla y grabación de pantalla"
"prevent_screenshots": "Evitar capturas de pantalla y grabación de pantalla",
"modify_2fa": "Modificar torta 2FA",
"disable_cake_2fa": "Desactivar pastel 2FA",
"question_to_disable_2fa":"¿Está seguro de que desea deshabilitar Cake 2FA? Ya no se necesitará un código 2FA para acceder a la billetera y a ciertas funciones.",
"disable": "Desactivar",
"setup_2fa": "Configurar pastel 2FA",
"verify_with_2fa": "Verificar con Cake 2FA",
"totp_code": "Código TOTP",
"please_fill_totp": "Complete el código de 8 dígitos presente en su otro dispositivo",
"totp_2fa_success": "¡Éxito! Cake 2FA habilitado para esta billetera. Recuerde guardar su semilla mnemotécnica en caso de que pierda el acceso a la billetera.",
"totp_verification_success" :"¡Verificación exitosa!",
"totp_2fa_failure": "Código incorrecto. Intente con un código diferente o genere una nueva clave secreta. Use una aplicación 2FA compatible que admita códigos de 8 dígitos y SHA512.",
"enter_totp_code": "Ingrese el código TOTP.",
"add_secret_code":"Agregue este código secreto a otro dispositivo",
"totp_secret_code":"Código secreto TOTP",
"important_note": "Nota IMPORTANTE",
"setup_2fa_text": "Cake 2FA NO es tan seguro como el almacenamiento en frío. 2FA protege contra tipos básicos de ataques, como cuando un amigo proporciona su huella digital mientras usted duerme.\n\n Cake 2FA NO protege contra un dispositivo comprometido por un atacante sofisticado.\n\n Si pierde el acceso a sus códigos 2FA , PERDERÁS EL ACCESO A ESTA BILLETERA. Deberá restaurar su billetera desde la semilla mnemotécnica. ¡POR LO TANTO, DEBE HACER UNA COPIA DE SEGURIDAD DE SUS SEMILLAS MNEMÓNICAS! Además, alguien con acceso a sus semillas mnemotécnicas podrá robar sus fondos, sin pasar por Cake 2FA.\n\n El personal de soporte de Cake no podrá ayudarlo si pierde el acceso a su semilla mnemotécnica, ya que Cake es un billetera sin custodia.",
"setup_totp_recommended": "Configurar TOTP (Recomendado)",
"disable_buy": "Desactivar acción de compra",
"disable_sell": "Desactivar acción de venta"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Le montant est inférieur au minimum",
"error_text_input_above_maximum_limit" : "Le montant est supérieur au maximum",
"show_market_place" :"Afficher la place de marché",
"prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran"
"prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran",
"modify_2fa": "Modifier le gâteau 2FA",
"disable_cake_2fa": "Désactiver le gâteau 2FA",
"question_to_disable_2fa":"Êtes-vous sûr de vouloir désactiver Cake 2FA ? Un code 2FA ne sera plus nécessaire pour accéder au portefeuille et à certaines fonctions.",
"disable": "Désactiver",
"setup_2fa": "Gâteau d'installation 2FA",
"verify_with_2fa": "Vérifier avec Cake 2FA",
"totp_code": "Code TOTP",
"please_fill_totp": "Veuillez renseigner le code à 8 chiffres présent sur votre autre appareil",
"totp_2fa_success": "Succès! Cake 2FA activé pour ce portefeuille. N'oubliez pas de sauvegarder votre graine mnémonique au cas où vous perdriez l'accès au portefeuille.",
"totp_verification_success" :"Vérification réussie !",
"totp_2fa_failure": "Code incorrect. Veuillez essayer un code différent ou générer une nouvelle clé secrète. Utilisez une application 2FA compatible qui prend en charge les codes à 8 chiffres et SHA512.",
"enter_totp_code": "Veuillez entrer le code TOTP.",
"add_secret_code":"Ajouter ce code secret à un autre appareil",
"totp_secret_code":"Code secret TOTP",
"important_note": "Note importante",
"setup_2fa_text": "Cake 2FA n'est PAS aussi sûr que le stockage à froid. 2FA protège contre les types d'attaques de base, comme votre ami fournissant votre empreinte digitale pendant que vous dormez.\n\n Cake 2FA ne protège PAS contre un appareil compromis par un attaquant sophistiqué.\n\n Si vous perdez l'accès à vos codes 2FA , VOUS PERDREZ L'ACCÈS À CE PORTEFEUILLE. Vous devrez restaurer votre portefeuille à partir de graines mnémotechniques. VOUS DEVEZ DONC SAUVEGARDER VOS SEMENCES MNEMONIQUES ! De plus, quelqu'un ayant accès à vos graines mnémoniques pourra voler vos fonds, en contournant Cake 2FA.\n\n Le personnel d'assistance de Cake ne pourra pas vous aider si vous perdez l'accès à vos graines mnémoniques, puisque Cake est un portefeuille non dépositaire.",
"setup_totp_recommended": "Configurer TOTP (recommandé)",
"disable_buy": "Désactiver l'action d'achat",
"disable_sell": "Désactiver l'action de vente"
}

714
res/values/strings_ha.arb Normal file
View file

@ -0,0 +1,714 @@
{
"welcome": "Barka da zuwa",
"cake_wallet": "Cake Wallet",
"first_wallet_text": "Aikace-aikacen e-wallet ga Monero, Bitcoin, Litecoin, da kuma Haven",
"please_make_selection": "Don Allah zaɓi ƙasa don ƙirƙira ko dawo da kwalinku.",
"create_new": "Ƙirƙira Sabon Kwalinku",
"restore_wallet": "Dawo da Kwalinku",
"monero_com": "Monero.com ta Cake Wallet",
"monero_com_wallet_text": "Aikace-aikacen e-wallet ga Monero",
"haven_app": "Haven da Cake Wallet",
"haven_app_wallet_text": "Aikace-aikacen e-wallet ga Haven",
"accounts": "Lissafi",
"edit": "Gyara",
"account": "Asusu",
"add": "Ƙara",
"address_book": "Littafin adireshi",
"contact": "Tuntuɓar",
"please_select": "Don Allah zaɓi:",
"cancel": "Soke",
"ok": "OK",
"contact_name": "Sunan Tuntuɓi",
"reset": "Sake saiti",
"save": "Ajiye",
"address_remove_contact": "Cire lamba",
"address_remove_content": "Kuna tabbatar kuna so ku cire wannan Contact?",
"authenticated": "Ingantacce",
"authentication": "Tabbatarwa",
"failed_authentication": "Binne wajen shiga. ${state_error}",
"wallet_menu": "Menu",
"Blocks_remaining": "${status} Katanga ya rage",
"please_try_to_connect_to_another_node": "Don Allah yi ƙoƙarin haɗa da wani node",
"xmr_hidden": "Boye",
"xmr_available_balance": "Akwai Ma'auni",
"xmr_full_balance": "Cikakken Ma'auni",
"send": "Aika",
"receive": "Samu",
"transactions": "Ma'amaloli",
"incoming": "Mai shigowa",
"outgoing": "Mai fita",
"transactions_by_date": "Ma'amaloli ta kwanan wata",
"trades": "Cinikai",
"filter_by": "Tace ta",
"today": "Yau",
"yesterday": "Jiya",
"received": "Samu",
"sent": "Aika",
"pending": "(pending)",
"rescan": "Rescan",
"reconnect": "Sake haɗawa",
"wallets": "Wallets",
"show_seed": "Nuna iri",
"show_keys": "Nuna iri/maɓallai",
"address_book_menu": "Littafin adireshi",
"reconnection": "Sake haɗawa",
"reconnect_alert_text": "Shin kun tabbata kuna son sake haɗawa?",
"exchange": "Exchange",
"clear": "Share",
"refund_address": "Adireshin maidowa",
"change_exchange_provider": "Canza Mai Bayar da Musanya",
"you_will_send": "Maida daga",
"you_will_get": "Maida zuwa",
"amount_is_guaranteed": "Adadin da aka karɓa yana da garanti",
"amount_is_estimate": "Adadin da aka karɓa shine kimantawa",
"powered_by": "An ƙarfafa shi ta ${title}",
"error": "Kuskure",
"estimated": "Kiyasta",
"min_value": "Min: ${value} ${currency}",
"max_value": "Max: ${value} ${currency}",
"change_currency": "Canja Kuɗi",
"overwrite_amount": "Rubuta adadin",
"qr_payment_amount": "Wannan QR code yana da adadin kuɗi. Kuna so ku overwrite wannan adadi?",
"copy_id": "Kwafi ID",
"exchange_result_write_down_trade_id": "Da fatan za a kwafa ko rubuta ID ɗin ciniki don ci gaba.",
"trade_id": "ID na kasuwanci:",
"copied_to_clipboard": "An kwafi zuwa Clipboard",
"saved_the_trade_id": "Na ajiye ID na ciniki",
"fetching": "Daukewa",
"id": "ID:",
"amount": "Adadi:",
"payment_id": "ID na biyan kuɗi:",
"status": "Matsayi:",
"offer_expires_in": "tayin zai ƙare a:",
"trade_is_powered_by": "Ana yin wannan ciniki ta hanyar ${provider}",
"copy_address": "Kwafi Adireshin",
"exchange_result_confirm": "Ta danna tabbatarwa, zaku aika ${fetchingLabel} ${from} daga walat ɗin ku mai suna ${walletName} zuwa address dake kasa. Ko zaka iya aika daga kwalinku na external zuwa address/QR code dake kasa.\n\nDon Allah shigar da confirm don ci gaba ko dawo ka canja adadinku.",
"exchange_result_description": "Dole ne ku aika mafi ƙarancin ${fetchingLabel} ${from} zuwa adireshin da aka nuna akan shafi na gaba. Idan ka aika adadi kasa da ${fetchingLabel} ${from} bazai yi converting ba kuma ba zai koma ba.",
"exchange_result_write_down_ID": "*Don Allah kwafi ko rubuta ID dake nuna sama.",
"confirm": "Tabbatar",
"confirm_sending": "Tabbatar da aikawa",
"commit_transaction_amount_fee": "Aikata ciniki\nAdadi: ${amount}\nKuda: ${fee}",
"sending": "Aika",
"transaction_sent": "An aika ciniki!",
"expired": "Karewa",
"time": "${minutes}m ${seconds}s",
"send_xmr": "Aika XMR",
"exchange_new_template": "Sabon template",
"faq": "FAQ",
"enter_your_pin": "Shigar da PIN",
"loading_your_wallet": "Ana loda walat ɗin ku",
"new_wallet": "Sabuwar Wallet",
"wallet_name": "Sunan walat",
"continue_text": "Ci gaba",
"choose_wallet_currency": "Da fatan za a zaɓi kuɗin walat:",
"node_new": "Sabon Node",
"node_address": "Address Node",
"node_port": "Node tashar jiragen ruwa",
"login": "Shiga",
"password": "Kalmar wucewa",
"nodes": "Nodes",
"node_reset_settings_title": "Sake saitunan",
"nodes_list_reset_to_default_message": "Kuna tabbatar kuna so ku sake saitunan zuwa default?",
"change_current_node": "Kuna tabbatar kuna so ku canja node yanzu zuwa ${node}?",
"change": "Canja",
"remove_node": "Cire node",
"remove_node_message": "Kuna tabbatar kuna so ku cire wannan node?",
"remove": "Cire",
"delete": "Share",
"add_new_node": "Ƙara sabon node",
"change_current_node_title": "Canja node yanzu",
"node_test": "Gwaji",
"node_connection_successful": "Haɗin ya yi nasara",
"node_connection_failed": "Haɗin ya gaza",
"new_node_testing": "Sabbin gwajin kumburi",
"use": "Canja zuwa",
"digit_pin": "-lambar PIN",
"share_address": "Raba adireshin",
"receive_amount": "Adadi",
"subaddresses": "Subaddresses",
"addresses": "Addresses",
"scan_qr_code": "Duba lambar QR don samun adireshin",
"qr_fullscreen": "Matsa don buɗe lambar QR na cikakken allo",
"rename": "Sake suna",
"choose_account": "Zaɓi asusu",
"create_new_account": "Ƙirƙiri sabon asusu",
"accounts_subaddresses": "Accounts da subaddresses",
"restore_restore_wallet": "Maida Wallet",
"restore_title_from_seed_keys": "Dawo da iri/maɓallai",
"restore_description_from_seed_keys": "Maido da walat ɗin ku daga iri/maɓallan da kuka adana don amintaccen wuri",
"restore_next": "Na gaba",
"restore_title_from_backup": "Dawo daga madadin",
"restore_description_from_backup": "Kuna iya dawo da duk aikace-aikacen Wallet ɗin Cake daga fayil ɗin ajiyar ku",
"restore_seed_keys_restore": "Mayar da iri/Maɓallai",
"restore_title_from_seed": "Maidowa daga iri",
"restore_description_from_seed": "Dawo da kwalinku daga 25 ko 13 lambar haɗin kalma",
"restore_title_from_keys": "Dawo daga maɓallai",
"restore_description_from_keys": "Maido da walat ɗin ku daga maɓallan maɓalli da aka ƙera da aka ajiye daga maɓallan ku na sirri",
"restore_wallet_name": "Sunan kwalinku",
"restore_address": "Address",
"restore_view_key_private": "Maɓallin Duba (key kalmar sirri)",
"restore_spend_key_private": "Maɓallin kashewa (key kalmar sirri)",
"restore_recover": "Maida",
"restore_wallet_restore_description": "Bayanin dawo da walat",
"restore_new_seed": "Sabon iri",
"restore_active_seed": "iri mai aiki",
"restore_bitcoin_description_from_seed": "Dawo da kwalinku daga 24 lambar haɗin kalma",
"restore_bitcoin_description_from_keys": "Dawo da kwalinku daga WIF string dake generate daga maɓallan sirri",
"restore_bitcoin_title_from_keys": "Dawo daga WIF",
"restore_from_date_or_blockheight": "Don Allah shigar da wata kwanan a kafin ku ƙirƙirar wannan kwalinku. Ko idan kun san blockheight, don Allah shigar da shi",
"seed_reminder": "Don Allah rubuta wadannan in case ka manta ko ka sake kwallon wayarka",
"seed_title": "iri",
"seed_share": "Raba iri",
"copy": "Kwafi",
"seed_language_choose": "Don Allah zaɓi harshen seed:",
"seed_choose": "Zaɓi harshen seed",
"seed_language_next": "Na gaba",
"seed_language_english": "Ingilishi",
"seed_language_chinese": "Sinanci",
"seed_language_dutch": "Dutch",
"seed_language_german": "Jamus",
"seed_language_japanese": "Jafananci",
"seed_language_portuguese": "Fotigal",
"seed_language_russian": "Rashanci",
"seed_language_spanish": "Spanish",
"seed_language_french": "Faransanci",
"seed_language_italian": "Italiyanci",
"send_title": "Aika",
"send_your_wallet": "Walat ɗin ku",
"send_address": "${cryptoCurrency} address",
"send_payment_id": "ID na biyan kuɗi (optional)",
"all": "DUK",
"send_error_minimum_value": "Mafi ƙarancin ƙimar adadin shine 0.01",
"send_error_currency": "Kudi zai iya ƙunsar lambobi kawai",
"send_estimated_fee": "Ƙimar kuɗi:",
"send_priority": "Yanzu haka fee yana set a ${transactionPriority} fifiko.\nAna iya daidaita fifikon ciniki a cikin saitunan",
"send_creating_transaction": "Ƙirƙirar ciniki",
"send_templates": "Samfura",
"send_new": "Sabon",
"send_amount": "Adadi:",
"send_fee": "Kudin:",
"send_name": "Sunan",
"send_got_it": "Gama",
"send_sending": "Aika...",
"send_success": "${crypto} kwalinku ya aika da nasara",
"settings_title": "Saitunan",
"settings_nodes": "Nodes",
"settings_current_node": "Node yanzu",
"settings_wallets": "Wallets",
"settings_display_balance": "Nuna ma'auni",
"settings_currency": "Kudi",
"settings_fee_priority": "fifikon kuɗi",
"settings_save_recipient_address": "Ajiye adireshin mai karɓa",
"settings_personal": "Na sirri",
"settings_change_pin": "Canja PIN",
"settings_change_language": "Canja yaren",
"settings_allow_biometrical_authentication": "Bada izinin tantance sawun yatsa",
"settings_dark_mode": "Launi mai duhu",
"settings_transactions": "Ma'amaloli",
"settings_trades": "Cinikai",
"settings_display_on_dashboard_list": "Nuna a kan tebur na bayanan",
"settings_all": "DUK",
"settings_only_trades": "Kawai kasuwancin",
"settings_only_transactions": "Kawai ayyuka",
"settings_none": "Babu",
"settings_support": "Taimako",
"settings_terms_and_conditions": "Sharuɗɗa da Ka'idoji",
"pin_is_incorrect": "PIN ba daidai ba ne",
"setup_pin": "Saita PIN",
"enter_your_pin_again": "Shigar da PIN ɗinku na sake",
"setup_successful": "An saita PIN ɗinku da nasara!",
"wallet_keys": "Iri/maɓalli na walat",
"wallet_seed": "kalmar sirri na walat",
"private_key": "Keɓaɓɓen maɓalli",
"public_key": "Maɓallin jama'a",
"view_key_private": "Duba maɓallin (maɓallin kalmar sirri)",
"view_key_public": "Maɓallin Duba (maɓallin jama'a)",
"spend_key_private": "makullin biya (maɓallin kalmar sirri)",
"spend_key_public": "makullin biya (maɓallin jama'a)",
"copied_key_to_clipboard": "An kwafa ${key} a cikin kwafin",
"new_subaddress_title": "Adireshin sabuwa",
"new_subaddress_label_name": "Lakabin suna",
"new_subaddress_create": "Ƙirƙiri",
"address_label": "Labari adireshi",
"subaddress_title": "Jagorar subaddress",
"trade_details_title": "Bayanai game da kasuwancin",
"trade_details_id": "ID",
"trade_details_state": "Matsayi",
"trade_details_fetching": "Daukewa",
"trade_details_provider": "Mai bayarwa",
"trade_details_created_at": "An ƙirƙira a",
"trade_details_pair": "miji da matarsa",
"trade_details_copied": "${title} an kwafa zuwa cikin kwafin",
"trade_history_title": "Tarihin kasuwancin",
"transaction_details_title": "Bayanai game da aikace-aikacen",
"transaction_details_transaction_id": "ID na kasuwanci",
"transaction_details_date": "Kwanan wata",
"transaction_details_height": "tsawo",
"transaction_details_amount": "Adadin",
"transaction_details_fee": "Kudin",
"transaction_details_copied": "${title} an kwafa zuwa cikin kwafin",
"transaction_details_recipient_address": "Adireshin masu amfani",
"wallet_list_title": "Monero walat",
"wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet",
"wallet_list_restore_wallet": "Maida Wallet",
"wallet_list_load_wallet": "Ana loda wallet na Monero",
"wallet_list_loading_wallet": "Ana loda ${wallet_name} walat",
"wallet_list_failed_to_load": "An kasa loda ${wallet_name} walat. ${error}",
"wallet_list_removing_wallet": "Cirewa ${wallet_name} walat",
"wallet_list_failed_to_remove": "Ba a iya cirewa ${wallet_name} walat. ${error}",
"widgets_address": "Adireshin",
"widgets_restore_from_blockheight": "Sake dawo da daga blockheight",
"widgets_restore_from_date": "Sake dawo da daga kwanan wata",
"widgets_or": "ko",
"widgets_seed": "iri",
"router_no_route": "Babu wata hanya da aka bayyana don ${name}",
"error_text_account_name": "Sunan ajiya zai iya ɗauka ne kawai da haruffa, lambobi\nkuma ya zama tsakanin 1 zuwa 15 haruffa",
"error_text_contact_name": "Sunan kira ba zai iya ɗaukar ` , ' \" haruffa\nkuma ya zama tsakanin 1 zuwa 32 haruffa",
"error_text_address": "Adireshin hujja ya kamata ya dace da irin\nna cryptocurrency",
"error_text_node_address": "Da fatan a shigar da iPv4 adireshin",
"error_text_node_port": "Node tashar jiragen ruwa zai iya ƙunsar lambobi tsakanin 0 zuwa 65535 kawai",
"error_text_payment_id": "ID na biyan kudi kawai zai iya ɗaukar daga 16 zuwa 64 haruffa a cikin hex",
"error_text_xmr": "XMR adadin ba zai iya wuce available balance.\nAdadin haruffan gaba zai kamata ya zama ko ƙasa daga na 12",
"error_text_fiat": "Adadin kudin ba zai iya wuce available balance.\nAdadin haruffan gaba zai kamata ya zama ko ƙasa daga na 2",
"error_text_subaddress_name": "Sunan subaddress ba zai iya ɗaukar `, ', \" haruffa\nkuma ya zama tsakanin 1 zuwa 20 haruffa",
"error_text_amount": "Adadin biya zai iya ƙunsar lambobi kawai",
"error_text_wallet_name": "Sunan hujja kawai zai iya ɗauka ne haruffa, lambobi, _ - haruffa\nkuma ya zama tsakanin 1 zuwa 33 haruffa",
"error_text_keys": "Ƙunci na hujja kawai zai iya ɗaukar 64 haruffa a cikin hex",
"error_text_crypto_currency": "Adadin haruffan gaba\n zai kamata ya zama ko ƙasa daga na 12",
"error_text_minimal_limit": "Kasuwanci ga ${provider} ba a yi ba. Adadin shine ƙasa fiye da ƙananan: ${min} ${currency}",
"error_text_maximum_limit": "Kasuwanci ga ${provider} ba a yi ba. Adadin shine fiye da ƙimanin: ${max} ${currency}",
"error_text_limits_loading_failed": "Kasuwanci ga ${provider} ba a yi ba. An kasa saukewa masanan",
"error_text_template": "Sunan na tushe da adireshin ba zai iya ɗaukar ` , ' \" haruffa\nkuma ya zama tsakanin 1 zuwa 106 haruffa",
"auth_store_ban_timeout": "ban_timeout",
"auth_store_banned_for": "An haramta don",
"auth_store_banned_minutes": "da minti",
"auth_store_incorrect_password": "PIN na gaskiya",
"wallet_store_monero_wallet": "Monero walat",
"wallet_restoration_store_incorrect_seed_length": "kalmar sirrin iri ba daidai ba",
"full_balance": "DUKAN KUDI",
"available_balance": "KUDI",
"hidden_balance": "BOYE KUDI",
"sync_status_syncronizing": "KWAFI",
"sync_status_syncronized": "KYAU",
"sync_status_not_connected": "BABU INTERNET",
"sync_status_starting_sync": "KWAFI",
"sync_status_failed_connect": "BABU INTERNET",
"sync_status_connecting": "HADA",
"sync_status_connected": "HANNU",
"sync_status_attempting_sync": "KWAFI",
"transaction_priority_slow": "SAURI DA SAURI",
"transaction_priority_regular": "SAURI NORMAL",
"transaction_priority_medium": "SAURI DA DADI",
"transaction_priority_fast": "sauri",
"transaction_priority_fastest": "mafi sauri",
"trade_for_not_created": "Ba a ƙirƙira ciniki don ${title} ba.",
"trade_not_created": "Ba a ƙirƙira ciniki ba",
"trade_id_not_found": "Ba a samo cinikin ${tradeId} na ${title} ba.",
"trade_not_found": "Ba a sami ciniki ba.",
"trade_state_pending": "Jira",
"trade_state_confirming": "Tabbatar",
"trade_state_trading": "Ciniki",
"trade_state_traded": "Ciniki",
"trade_state_complete": "Cikakkun",
"trade_state_to_be_created": "za a halicci",
"trade_state_unpaid": "ba a biya ba",
"trade_state_underpaid": "ba a biya gaba ɗaya ba",
"trade_state_paid_unconfirmed": "an biya amma ba a tabbatar ba",
"trade_state_paid": "an biya",
"trade_state_btc_sent": "Btc an aika",
"trade_state_timeout": "lokacin da ya ƙare",
"trade_state_created": "an halicci",
"trade_state_finished": "an kammala",
"change_language": "canja harshen",
"change_language_to": "canja harshen zuwa ${language}?",
"paste": "Manna",
"restore_from_seed_placeholder": "Da fatan za a shigar da ko manna maɓallin ku a nan",
"add_new_word": "Ƙara kalma sabuwa",
"incorrect_seed": "rubutun da aka shigar ba shi da inganci.",
"biometric_auth_reason": "Duba hoton yatsa don tantancewa",
"version": "Sigar ${currentVersion}",
"openalias_alert_title": "An gano adireshin",
"openalias_alert_content": "Zaka aika kuɗi zuwa \n${recipient_name}",
"card_address": "Adireshin:",
"buy": "Sayi",
"sell": "sayar",
"placeholder_transactions": "Za a nuna ma'amalolin ku anan",
"placeholder_contacts": "Za a nuna lambobin sadarwar ku anan",
"template": "Samfura",
"confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?",
"confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?",
"picker_description": "Don zaɓar ChangeNOW ko MorphToken, da farko canja kasuwancin pair din ku",
"change_wallet_alert_title": "Canja walat yanzu",
"change_wallet_alert_content": "Kana so ka canja walat yanzu zuwa ${wallet_name}?",
"creating_new_wallet": "Haliccin walat sabuwa",
"creating_new_wallet_error": "Kuskure: ${description}",
"seed_alert_title": "Hankali",
"seed_alert_content": "Irin ita ce kawai hanya don dawo da walat ɗin ku. Kun rubuta shi?",
"seed_alert_back": "juya baya",
"seed_alert_yes": "E, Na yi",
"exchange_sync_alert_content": "Da fatan za a jira har sai an daidaita walat ɗin ku",
"pre_seed_title": "MUHIMMANCI",
"pre_seed_description": "A kan shafin nan za ku ga wata ƙungiya na ${words} kalmomi. Wannan shine tsarin daban-daban ku kuma na sirri kuma shine hanya ɗaya kadai don mai da purse dinku a cikin yanayin rasa ko rashin aiki. Yana da damar da kuke a cikin tabbatar da kuyi rubuta shi kuma kuyi ajiye shi a wuri na aminci wanda ya wuce wurin app na Cake Wallet.",
"pre_seed_button_text": "Ina fahimta. Nuna mini seed din nawa",
"xmr_to_error": "XMR.TO kuskure",
"xmr_to_error_description": "Adadin ba shi da inganci. Maksimum ɗaura 8 digiri bayan decimal point",
"provider_error": "${provider} kuskure",
"use_ssl": "Yi amfani da SSL",
"trusted": "Amintacce",
"color_theme": "Jigon launi",
"light_theme": "Haske",
"bright_theme": "Mai haske",
"dark_theme": "Duhu",
"enter_your_note": "Shigar da bayanin kula…",
"note_optional": "Bayani (optional)",
"note_tap_to_change": "Bayani (tap don canja)",
"view_in_block_explorer": "Dubo a cikin Block Explorer",
"view_transaction_on": "Dubo aikace-aikacen akan",
"transaction_key": "Aikace-aikacen key",
"confirmations": "Tabbatar",
"recipient_address": "Adireshin mai karɓa",
"extra_id": "Karin ID:",
"destination_tag": "Tambarin makoma:",
"memo": "Memo:",
"backup": "Ajiyayyen",
"change_password": "Canza kalmar shiga",
"backup_password": "Ajiyayyen kalmar sirri",
"write_down_backup_password": "Da fatan za a rubuta kalmar sirrin ajiyar ku, wacce ake amfani da ita don shigo da fayilolin ajiyar ku.",
"export_backup": "Ajiyayyen fitarwa",
"save_backup_password": "Da fatan za a tabbatar cewa kun adana kalmar sirrin ajiyar ku. Ba za ku iya shigo da fayilolin ajiyar ku ba tare da shi ba.",
"backup_file": "Ajiyayyen fayil",
"edit_backup_password": "Shirya Kalmar wucewa ta Ajiyayyen",
"save_backup_password_alert": "Ajiye kalmar sirri ta ajiya",
"change_backup_password_alert": "Fayilolin madadin ku na baya ba za su kasance don shigo da sabon kalmar sirri ta madadin ba. Sabuwar kalmar sirri ta ajiya za a yi amfani da ita kawai don sabbin fayilolin madadin. Shin kun tabbata cewa kuna son canza kalmar wucewa?",
"enter_backup_password": "Shigar da kalmar wucewa ta madadin nan",
"select_backup_file": "Zaɓi fayil ɗin madadin",
"import": "Shigo da",
"please_select_backup_file": "Da fatan za a zaɓi fayil ɗin madadin kuma shigar da kalmar wucewa ta madadin.",
"fixed_rate": "Kafaffen ƙima",
"fixed_rate_alert": "Za ku iya shigar da adadin karɓa lokacin da aka duba ƙayyadadden zaɓin ƙimar kuɗi. Kuna so ku canza zuwa ƙayyadadden yanayin ƙimar kuɗi?",
"xlm_extra_info": "Don Allah kar a manta da saka Memo ID yayin aika ma'amalar XLM don musayar",
"xrp_extra_info": "Don Allah kar a manta da saka alamar Ƙaddamarwa yayin aika ma'amalar XRP don musayar",
"exchange_incorrect_current_wallet_for_xmr": "Idan kana son musanya XMR daga ma'aunin Cake Wallet Monero, da fatan za a fara canza wallet ɗin Monero ɗin ku.",
"confirmed": "An tabbatar",
"unconfirmed": "Ba a tabbatar ba",
"displayable": "Ana iya nunawa",
"submit_request": "gabatar da bukata",
"buy_alert_content": "A halin yanzu muna tallafawa kawai siyan Bitcoin da Litecoin. Don siyan Bitcoin ko Litecoin, da fatan za a ƙirƙira ko canza zuwa walat ɗin ku na Bitcoin ko Litecoin.",
"sell_alert_content": "A halin yanzu muna tallafawa siyar da Bitcoin kawai. Don sayar da Bitcoin, da fatan za a ƙirƙira ko canza zuwa walat ɗin ku na Bitcoin.",
"outdated_electrum_wallet_description": "Sabbin walat ɗin Bitcoin da aka kirkira a cikin Cake yanzu suna da nau'in kalma 24. Ya zama dole ka ƙirƙiri sabon walat ɗin Bitcoin kuma canza duk kuɗin ku zuwa sabon walat ɗin kalmomi 24, kuma ku daina amfani da walat tare da iri mai kalma 12. Da fatan za a yi haka nan take don samun kuɗin ku.",
"understand": "na gane",
"apk_update": "apk sabunta",
"buy_bitcoin": "Sayi Bitcoin",
"buy_with": "Saya da",
"moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}",
"outdated_electrum_wallet_receive_warning": "Idan wannan walat ɗin yana da nau'in kalma 12 kuma an ƙirƙira shi a cikin Cake, KAR KA saka Bitcoin cikin wannan jakar. Duk wani BTC da aka canjawa wuri zuwa wannan walat na iya ɓacewa. Ƙirƙiri sabon walat mai kalmomi 24 (matsa menu a saman dama, zaɓi Wallets, zaɓi Ƙirƙiri Sabon Wallet, sannan zaɓi Bitcoin) kuma NAN nan take matsar da BTC ɗin ku a can. Sabbin (kalmomi 24) BTC wallets daga Cake suna da tsaro",
"do_not_show_me": "Kar ka sake nuna min wannan",
"unspent_coins_title": "Tsabar da ba a kashe ba",
"unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba",
"freeze": "Daskare",
"frozen": "Daskararre",
"coin_control": "Sarrafa tsabar kuɗi (na zaɓi)",
"address_detected": "An gano adireshin",
"address_from_domain": "Wannan adireshin ya fito daga ${domain} akan Unstoppable Domain",
"add_receiver": "Ƙara wani mai karɓa (na zaɓi)",
"manage_yats": "Sarrafa Yats",
"yat_alert_title": "Aika da karɓar crypto cikin sauƙi tare da Yat",
"yat_alert_content": "Masu amfani da Wallet ɗin Cake yanzu za su iya aikawa da karɓar duk kuɗin da suka fi so tare da sunan mai amfani na tushen emoji iri ɗaya.",
"get_your_yat": "Samun Yat ka",
"connect_an_existing_yat": "Haɗa Yat da ke akwai",
"connect_yats": "Haɗa Yats",
"yat_address": "Yat Address",
"yat": "Yat",
"address_from_yat": "Wannan adireshin daga ${emoji} ne akan Yat",
"yat_error": "Kuskure",
"yat_error_content": "Babu adireshi da ke da alaƙa da wannan Yat. Gwada wani Yat",
"choose_address": "\n\n Da fatan za a zaɓi adireshin:",
"yat_popup_title": "Adireshin jakar ku na iya zama emojifid.",
"yat_popup_content": "Yanzu zaku iya aikawa da karɓar crypto a cikin Cake Wallet tare da Yat - gajere, sunan mai amfani na tushen emoji. Sarrafa Yats a kowane lokaci akan allon saiti",
"second_intro_title": "Adireshin emoji ɗaya don sarrafa su duka",
"second_intro_content": "Your Yat adireshi ne na musamman na Emoji guda ɗaya wanda ke maye gurbin duk dogayen adiresoshin ku na hexadecimal na duk kudaden ku.",
"third_intro_title": "Yat yana wasa da kyau tare da wasu",
"third_intro_content": "Yats suna zaune a wajen Kek Wallet, kuma. Ana iya maye gurbin kowane adireshin walat a duniya da Yat!",
"learn_more": "Ƙara Koyi",
"search": "Bincika",
"search_language": "Bincika harshe",
"search_currency": "Neman kudin waje",
"new_template": "Sabon Samfura",
"electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki",
"wallet_name_exists": "Wallet mai wannan sunan ya riga ya wanzu. Da fatan za a zaɓi wani suna daban ko sake suna ɗayan walat tukuna.",
"market_place": "Kasuwa",
"cake_pay_title": "Cake Pay Gift Cards",
"cake_pay_subtitle": "Sayi katunan kyauta masu rahusa (Amurka kawai)",
"cake_pay_web_cards_title": "Cake Pay Web Cards",
"cake_pay_web_cards_subtitle": "Sayi katunan da aka riga aka biya na duniya da katunan kyauta",
"about_cake_pay": "Biyan Cake yana ba ku damar sauƙin siyan katunan kyauta tare da kadarorin kama-da-wane, wanda za'a iya kashewa nan take a sama da yan kasuwa 150,000 a Amurka.",
"cake_pay_account_note": "Yi rajista tare da adireshin imel kawai don gani da siyan katunan. Wasu ma suna samuwa a rangwame!",
"already_have_account": "Kuna da asusu?",
"create_account": "Kirkira ajiya",
"privacy_policy": "takardar kebantawa",
"welcome_to_cakepay": "Barka da zuwa Cake Pay!",
"sign_up": "Shiga",
"forgot_password": "Manta Kalmar wucewa",
"reset_password": "Sake saita kalmar wucewa",
"gift_cards": "Katunan Kyauta",
"setup_your_debit_card": "Saita katin zare kudi",
"no_id_required": "Babu ID da ake buƙata. Yi da kuma ciyar a ko'ina",
"how_to_use_card": "Yadda ake amfani da wannan kati",
"purchase_gift_card": "Katin Kyautar Sayi",
"verification": "tabbatar",
"fill_code": "Da fatan za a cika lambar tabbatarwa da aka bayar zuwa imel ɗin ku",
"dont_get_code": "Ba a samun code?",
"resend_code": "Da fatan za a sake aika shi",
"debit_card": "Katin Zare kudi",
"cakepay_prepaid_card": "Katin zare kudi na CakePay",
"no_id_needed": "Babu ID da ake buƙata!",
"frequently_asked_questions": "Tambayoyin da ake yawan yi",
"debit_card_terms": "Adana da amfani da lambar katin kuɗin ku (da takaddun shaida masu dacewa da lambar katin kuɗin ku) a cikin wannan walat ɗin dijital suna ƙarƙashin Sharuɗɗa da Sharuɗɗa na yarjejeniya mai amfani da katin tare da mai fitar da katin biyan kuɗi, kamar yadda yake aiki daga lokaci zuwa lokaci.",
"please_reference_document": "Da fatan za a nemi takaddun da ke ƙasa don ƙarin bayani.",
"cardholder_agreement": "Yarjejeniyar mai katin",
"e_sign_consent": "Izinin Alamar E-Sign",
"agree_and_continue": "Amincewa & Ci gaba",
"email_address": "Adireshin i-mel",
"agree_to": "Ta hanyar ƙirƙirar asusu kun yarda da",
"and": "kuma",
"enter_code": "Shigar da lamba",
"congratulations": "Taya murna!",
"you_now_have_debit_card": "Yanzu kana da katin zare kudi",
"min_amount": "Min: ${value}",
"max_amount": "Max: ${value}",
"enter_amount": "Shigar da Adadi",
"billing_address_info": "Idan an nemi adireshin biyan kuɗi, samar da adireshin jigilar kaya",
"order_physical_card": "Yi Oda Katin Jiki",
"add_value": "Ƙara ƙima",
"activate": "Kunna",
"get_a": "Samu a",
"digital_and_physical_card": "katin zare kudi na dijital da na zahiri",
"get_card_note": "cewa zaku iya sake lodawa tare da kudaden dijital. Babu ƙarin bayani da ake buƙata!",
"signup_for_card_accept_terms": "Yi rajista don katin kuma karɓi sharuɗɗan.",
"add_fund_to_card": "Ƙara kuɗin da aka riga aka biya a katunan (har zuwa ${value})",
"use_card_info_two": "Ana canza kuɗi zuwa dalar Amurka lokacin da ake riƙe su a cikin asusun da aka riga aka biya, ba cikin agogon dijital ba.",
"use_card_info_three": "Yi amfani da katin dijital akan layi ko tare da hanyoyin biyan kuɗi mara lamba.",
"optionally_order_card": "Zaɓin yin odar katin zahiri.",
"hide_details": "Ɓoye cikakkun bayanai",
"show_details": "Nuna Cikakkun bayanai",
"upto": "har zuwa ${value}",
"discount": "Ajiye ${value}%",
"gift_card_amount": "Adadin Katin Kyauta",
"bill_amount": "Adadin Bill",
"you_pay": "Ka Bayar",
"tip": "Tukwici:",
"custom": "al'ada",
"by_cake_pay": "da Cake Pay",
"expires": "Ya ƙare",
"mm": "MM",
"yy": "YY",
"online": "Kan layi",
"offline": "Offline",
"gift_card_number": "Lambar katin kyauta",
"pin_number": "Lambar PIN",
"total_saving": "Jimlar Adana",
"last_30_days": "Kwanaki 30 na ƙarshe",
"avg_savings": "Matsakaici Adana",
"view_all": "Duba duka",
"active_cards": "Katunan aiki",
"delete_account": "Share Account",
"cards": "Katuna",
"active": "Mai aiki",
"redeemed": "An fanshi",
"gift_card_balance_note": "Katunan kyauta tare da ragowar ma'auni zasu bayyana anan",
"gift_card_redeemed_note": "Katunan kyauta da kuka fanshi zasu bayyana anan",
"logout": "Fita",
"add_tip": "Ƙara Tukwici",
"percentageOf": "na ${amount}",
"is_percentage": "shine",
"search_category": "Nemo nau'in",
"mark_as_redeemed": "Yi Alama Kamar An Fansa",
"more_options": "Ƙarin Zaɓuɓɓuka",
"awaiting_payment_confirmation": "Ana jiran Tabbacin Biyan Kuɗi",
"transaction_sent_notice": "Idan allon bai ci gaba ba bayan minti 1, duba mai binciken toshewa da imel ɗin ku.",
"agree": "Yarda",
"in_store": "A cikin Store",
"generating_gift_card": "Samar da Katin Kyauta",
"payment_was_received": "An karɓi kuɗin ku.",
"proceed_after_one_minute": "Idan allon bai ci gaba ba bayan minti 1, duba imel ɗin ku.",
"order_id": "Oda ID",
"gift_card_is_generated": "An samar da Katin Kyauta",
"open_gift_card": "Bude Katin Kyauta",
"contact_support": "Tuntuɓi Support",
"gift_cards_unavailable": "Ana samun katunan kyauta don siye kawai tare da Monero, Bitcoin, da Litecoin a wannan lokacin",
"introducing_cake_pay": "Gabatar da Cake Pay!",
"cake_pay_learn_more": "Nan take siya ku kwaso katunan kyaututtuka a cikin app!\nTake hagu zuwa dama don ƙarin koyo.",
"automatic": "Na atomatik",
"fixed_pair_not_supported": "Wannan kafaffen guda biyu ba shi da tallafi tare da zaɓaɓɓun musayar",
"variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar",
"none_of_selected_providers_can_exchange": "Babu ɗaya daga cikin zaɓaɓɓun masu samarwa da zai iya yin wannan musayar",
"choose_one": "Zaɓi ɗaya",
"choose_from_available_options": "Zaɓi daga zaɓuɓɓukan da ake da su:",
"custom_redeem_amount": "Adadin Fansa na Musamman",
"add_custom_redemption": "Ƙara Ceto na Musamman",
"remaining": "saura",
"delete_wallet": "Share walat",
"delete_wallet_confirm_message": "Shin kun tabbata cewa kuna son share jakar ${wallet_name}?",
"low_fee": "maras tsada",
"low_fee_alert": "A halin yanzu kuna amfani da ƙarancin fifikon kuɗin hanyar sadarwa. Wannan na iya haifar da dogon jira, farashi daban-daban, ko soke kasuwancin. Muna ba da shawarar saita farashi mafi girma don ƙwarewa mafi kyau.",
"ignor": "Yi watsi da shi",
"use_suggested": "Amfani da Shawarwari",
"do_not_share_warning_text": "Kada ku raba waɗannan ga kowa, gami da tallafi.\n\nZa a iya sace kuɗin ku kuma za a sace!",
"help": "taimako",
"all_transactions": "Dukan Ma'amaloli",
"all_trades": "Duk ciniki",
"connection_sync": "Haɗi da daidaitawa",
"security_and_backup": "Tsaro da madadin",
"create_backup": "Ƙirƙiri madadin",
"privacy_settings": "Saitunan sirri",
"privacy": "Keɓantawa",
"display_settings": "Nuni saituna",
"other_settings": "Sauran saituna",
"require_pin_after": "Bukatar PIN bayan",
"always": "Koyaushe",
"minutes_to_pin_code": "${minute} minti",
"disable_exchange": "Kashe musanya",
"advanced_privacy_settings": "Babban Saitunan Sirri",
"settings_can_be_changed_later": "Ana iya canza waɗannan saitunan daga baya a cikin saitunan app",
"add_custom_node": "Ƙara Sabon Kulli na Custom",
"disable_fiat": "Dakatar da fiat",
"fiat_api": "API ɗin Fiat",
"disabled": "tsaya",
"enabled": "An kunna",
"tor_only": "Tor kawai",
"unmatched_currencies": "Nau'in walat ɗin ku na yanzu bai dace da na lambar QR da aka bincika ba",
"contact_list_contacts": "Lambobin sadarwa",
"contact_list_wallets": "Wallets dina",
"bitcoin_payments_require_1_confirmation": "Akwatin Bitcoin na buɗe 1 sambumbu, da yake za ta samu mintuna 20 ko yawa. Ina kira ga sabuwar lafiya! Zaka sanarwa ta email lokacin da aka samu akwatin samun lambar waya.",
"send_to_this_address" : "Aiko ${currency} ${tag} zuwa adireshin wannan",
"arrive_in_this_address" : "${currency} ${tag} zai je wurin wannan adireshi",
"do_not_send": "Kada ka aika",
"error_dialog_content": "Ai, yanzu muka ga alamar kuskure. \n\nDa fatan, aika rahoton kuskuren da muka kira zuwa gasar tsarinmu don gaskiyar shirya.",
"scan_qr_code": "Gani QR kodin",
"cold_or_recover_wallet": "Samun kashi na baya ko samun kashi na kasa",
"please_wait": "Don Allah a rufe",
"sweeping_wallet": "Kashi na kasa",
"sweeping_wallet_alert": "Wannan ba zai samu lokacin mai tsaski. KADA KA SAMU KUNGIYARAN KUHON, ZAMAN DADIN BANKUNCI ZAI HAŘA",
"invoice_details": "Bayanin wadannan",
"donation_link_details": "Bayanin hanyar sadaka",
"anonpay_description": "Ƙirƙirar ${type}. Maƙiyantun mai nasara zai iya ${method} da duk abubuwan da ke samun lambar waya, kuma zaku samu kuɗin dama a wannan kashi.",
"create_invoice": "Sanya bayanin wadannan",
"create_donation_link": "Sanya hanyar sadaka",
"optional_email_hint": "Email na kayan taimako ga wadanda basu ba da maki",
"optional_description": "Bayanin zai iya ba da maki",
"optional_name": "Sunan mawallin zai iya ba da maki",
"clearnet_link": "Lambar makomar kwayoyi",
"onion_link": "Lambar onion",
"decimal_places_error": "Wadannan suna da tsawon harsuna",
"edit_node": "Shirya Node",
"frozen_balance": "Falin kuma maɓallin",
"settings": "Saiti",
"sell_monero_com_alert_content": "Selling Monero bai sami ƙarshen mai bukatar samun ba",
"error_text_input_below_minimum_limit" : "Kudin ba a kamai",
"error_text_input_above_maximum_limit" : "Kudin da ya kamata",
"show_market_place" :"Nuna dan kasuwa",
"prevent_screenshots": "Fada lambobi da jarrabobi na kayan lambobi",
"disable_buy": "Kashe alama",
"disable_sell": "Kashe karbuwa"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "राशि न्यूनतम से कम है",
"error_text_input_above_maximum_limit" : "राशि अधिकतम से अधिक है",
"show_market_place":"बाज़ार दिखाएँ",
"prevent_screenshots": "स्क्रीनशॉट और स्क्रीन रिकॉर्डिंग रोकें"
"prevent_screenshots": "स्क्रीनशॉट और स्क्रीन रिकॉर्डिंग रोकें",
"modify_2fa": "केक 2FA संशोधित करें",
"disable_cake_2fa": "केक 2FA अक्षम करें",
"question_to_disable_2fa":"क्या आप सुनिश्चित हैं कि आप Cake 2FA को अक्षम करना चाहते हैं? वॉलेट और कुछ कार्यों तक पहुँचने के लिए अब 2FA कोड की आवश्यकता नहीं होगी।",
"disable": "अक्षम करना",
"setup_2fa": "सेटअप केक 2FA",
"verify_with_2fa": "केक 2FA के साथ सत्यापित करें",
"totp_code": "टीओटीपी कोड",
"please_fill_totp": "कृपया अपने दूसरे डिवाइस पर मौजूद 8 अंकों का कोड भरें",
"totp_2fa_success": "सफलता! इस वॉलेट के लिए Cake 2FA सक्षम है। यदि आप वॉलेट एक्सेस खो देते हैं तो अपने स्मरक बीज को सहेजना याद रखें।",
"totp_verification_success" :"सत्यापन सफल!",
"totp_2fa_failure": "गलत कोड़। कृपया एक अलग कोड का प्रयास करें या एक नई गुप्त कुंजी उत्पन्न करें। 8-अंकीय कोड और SHA512 का समर्थन करने वाले संगत 2FA ऐप का उपयोग करें।",
"enter_totp_code": "कृपया TOTP कोड दर्ज करें।",
"add_secret_code":"इस गुप्त कोड को किसी अन्य डिवाइस में जोड़ें",
"totp_secret_code":"टीओटीपी गुप्त कोड",
"important_note": "महत्वपूर्ण लेख",
"setup_2fa_text": "केक 2FA कोल्ड स्टोरेज जितना सुरक्षित नहीं है। 2FA बुनियादी प्रकार के हमलों से बचाता है, जैसे कि आपका मित्र सोते समय आपको अपना फ़िंगरप्रिंट प्रदान करता है।\n\n Cake 2FA परिष्कृत हमलावर द्वारा किसी डिवाइस से छेड़छाड़ से रक्षा नहीं करता है।\n\n यदि आप अपने 2FA कोड तक पहुंच खो देते हैं , आप इस वॉलेट तक पहुंच खो देंगे। आपको अपने बटुए को स्मरणीय बीज से पुनर्स्थापित करने की आवश्यकता होगी। इसलिए आपको अपने स्मरणीय बीजों का बैकअप लेना चाहिए! इसके अलावा, आपके स्मरक बीज (बीजों) तक पहुंच रखने वाला कोई व्यक्ति केक 2FA को दरकिनार कर आपके धन की चोरी करने में सक्षम होगा। अप्रबंधित बटुआ।",
"setup_totp_recommended": "टीओटीपी सेट अप करें (अनुशंसित)",
"disable_buy": "खरीद कार्रवाई अक्षम करें",
"disable_sell": "बेचने की कार्रवाई अक्षम करें"
}

View file

@ -708,5 +708,29 @@
"error_text_input_below_minimum_limit" : "Iznos je manji od minimalnog",
"error_text_input_above_maximum_limit" : "Iznos je veći od maskimalnog",
"show_market_place" : "Prikaži tržište",
"prevent_screenshots": "Spriječite snimke zaslona i snimanje zaslona"
"prevent_screenshots": "Spriječite snimke zaslona i snimanje zaslona",
"modify_2fa": "Izmijenite tortu 2FA",
"disable_cake_2fa": "Onemogući Cake 2FA",
"question_to_disable_2fa":"Jeste li sigurni da želite onemogućiti Cake 2FA? 2FA kod više neće biti potreban za pristup novčaniku i određenim funkcijama.",
"disable": "Onemogući",
"setup_2fa": "Postavljanje torte 2FA",
"verify_with_2fa": "Provjerite s Cake 2FA",
"totp_code": "TOTP kod",
"please_fill_totp": "Unesite 8-znamenkasti kod koji se nalazi na vašem drugom uređaju",
"totp_2fa_success": "Uspjeh! Cake 2FA omogućen za ovaj novčanik. Ne zaboravite spremiti svoje mnemoničko sjeme u slučaju da izgubite pristup novčaniku.",
"totp_verification_success" :"Provjera uspješna!",
"totp_2fa_failure": "Neispravan kod. Pokušajte s drugim kodom ili generirajte novi tajni ključ. Koristite kompatibilnu 2FA aplikaciju koja podržava 8-znamenkasti kod i SHA512.",
"enter_totp_code": "Unesite TOTP kod.",
"add_secret_code":"Dodajte ovaj tajni kod na drugi uređaj",
"totp_secret_code":"TOTP tajni kod",
"important_note": "Važna nota",
"setup_2fa_text": "Torta 2FA NIJE sigurna kao hladno skladište. 2FA štiti od osnovnih vrsta napada, kao što je vaš prijatelj koji vam daje otisak prsta dok spavate.\n\n Cake 2FA NE štiti od kompromitiranog uređaja od strane sofisticiranog napadača.\n\n Ako izgubite pristup svojim 2FA kodovima , IZGUBIT ĆETE PRISTUP OVOM NOVČANIKU. Morat ćete obnoviti svoj novčanik iz mnemoničkog sjemena. STOGA MORATE NAPRAVITI SIGURNOSNE KOPIJE SVOJIH MNEMONIČKIH SJEMENA! Nadalje, netko tko ima pristup vašem mnemoničkom seedu(ima) moći će ukrasti vaša sredstva, zaobilazeći Cake 2FA.\n\n Cake osoblje za podršku neće vam moći pomoći ako izgubite pristup svom mnemoničkom seedu, budući da je Cake neskrbnički novčanik.",
"setup_totp_recommended": "Postavite TOTP (preporučeno)",
"disable_buy": "Onemogući kupnju",
"disable_sell": "Onemogući akciju prodaje"
}

View file

@ -684,5 +684,35 @@
"error_text_input_below_minimum_limit" : "Jumlah kurang dari minimal",
"error_text_input_above_maximum_limit" : "Jumlah lebih dari maksimal",
"show_market_place": "Tampilkan Pasar",
"prevent_screenshots": "Cegah tangkapan layar dan perekaman layar"
"prevent_screenshots": "Cegah tangkapan layar dan perekaman layar",
"modify_2fa": "Ubah Kue 2FA",
"disable_cake_2fa": "Nonaktifkan Kue 2FA",
"question_to_disable_2fa":"Apakah Anda yakin ingin menonaktifkan Cake 2FA? Kode 2FA tidak lagi diperlukan untuk mengakses dompet dan fungsi tertentu.",
"disable": "Cacat",
"setup_2fa": "Siapkan Kue 2FA",
"verify_with_2fa": "Verifikasi dengan Cake 2FA",
"totp_code": "Kode TOTP",
"please_fill_totp": "Harap isi kode 8 digit yang ada di perangkat Anda yang lain",
"totp_2fa_success": "Kesuksesan! Cake 2FA diaktifkan untuk dompet ini. Ingatlah untuk menyimpan benih mnemonik Anda jika Anda kehilangan akses dompet.",
"totp_verification_success" :"Verifikasi Berhasil!",
"totp_2fa_failure": "Kode salah. Silakan coba kode lain atau buat kunci rahasia baru. Gunakan aplikasi 2FA yang kompatibel yang mendukung kode 8 digit dan SHA512.",
"enter_totp_code": "Masukkan Kode TOTP.",
"add_secret_code":"Tambahkan kode rahasia ini ke perangkat lain",
"totp_secret_code":"Kode Rahasia TOTP",
"important_note": "Catatan penting",
"setup_2fa_text": "Cake 2FA TIDAK seaman cold storage. 2FA melindungi dari jenis serangan dasar, seperti teman Anda memberikan sidik jari saat Anda sedang tidur.\n\n Cake 2FA TIDAK melindungi dari perangkat yang disusupi oleh penyerang canggih.\n\n Jika Anda kehilangan akses ke kode 2FA , ANDA AKAN KEHILANGAN AKSES KE DOMPET INI. Anda perlu memulihkan dompet Anda dari benih mnemonik. OLEH KARENA ITU, ANDA HARUS MENYIMPAN BIJI MNEMONIK ANDA! Selanjutnya, seseorang yang memiliki akses ke benih mnemonik Anda akan dapat mencuri dana Anda, melewati Cake 2FA.\n\n Staf pendukung Cake tidak akan dapat membantu Anda jika Anda kehilangan akses ke benih mnemonik Anda, karena Cake adalah dompet tanpa hak asuh.",
"setup_totp_recommended": "Siapkan TOTP (Disarankan)",
"disable_buy": "Nonaktifkan tindakan beli",
"disable_sell": "Nonaktifkan aksi jual"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "L'ammontare è inferiore al minimo",
"error_text_input_above_maximum_limit" : "L'ammontare è superiore al massimo",
"show_market_place":"Mostra mercato",
"prevent_screenshots": "Impedisci screenshot e registrazione dello schermo"
"prevent_screenshots": "Impedisci screenshot e registrazione dello schermo",
"modify_2fa": "Modifica Torta 2FA",
"disable_cake_2fa": "Disabilita Cake 2FA",
"question_to_disable_2fa":"Sei sicuro di voler disabilitare Cake 2FA? Non sarà più necessario un codice 2FA per accedere al portafoglio e ad alcune funzioni.",
"disable": "disattivare",
"setup_2fa": "Imposta la torta 2FA",
"verify_with_2fa": "Verifica con Cake 2FA",
"totp_code": "Codice TOTP",
"please_fill_totp": "Inserisci il codice di 8 cifre presente sull'altro tuo dispositivo",
"totp_2fa_success": "Successo! Cake 2FA abilitato per questo portafoglio. Ricordati di salvare il tuo seme mnemonico nel caso in cui perdi l'accesso al portafoglio.",
"totp_verification_success" :"Verifica riuscita!",
"totp_2fa_failure": "Codice non corretto. Prova un codice diverso o genera una nuova chiave segreta. Utilizza un'app 2FA compatibile che supporti codici a 8 cifre e SHA512.",
"enter_totp_code": "Inserisci il codice TOTP.",
"add_secret_code":"Aggiungi questo codice segreto a un altro dispositivo",
"totp_secret_code":"TOTP codice segreto",
"important_note": "Nota importante",
"setup_2fa_text": "Cake 2FA NON è sicuro come la cella frigorifera. 2FA protegge da tipi di attacchi di base, come il tuo amico che fornisce la tua impronta digitale mentre dormi.\n\n Cake 2FA NON protegge da un dispositivo compromesso da un aggressore sofisticato.\n\n Se perdi l'accesso ai tuoi codici 2FA , PERDERAI L'ACCESSO A QUESTO PORTAFOGLIO. Dovrai ripristinare il tuo portafoglio dal seme mnemonico. DOVETE QUINDI SOSTITUIRE I VOSTRI SEMI MNEMONICI! Inoltre, qualcuno con accesso ai tuoi seed mnemonici sarà in grado di rubare i tuoi fondi, aggirando Cake 2FA.\n\n Il personale di supporto di Cake non sarà in grado di aiutarti se perdi l'accesso al tuo seed mnemonico, poiché Cake è un portafoglio non detentivo.",
"setup_totp_recommended": "Imposta TOTP (consigliato)",
"disable_buy": "Disabilita l'azione di acquisto",
"disable_sell": "Disabilita l'azione di vendita"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "金額は最小額より少ない",
"error_text_input_above_maximum_limit" : "金額は最大値を超えています",
"show_market_place":"マーケットプレイスを表示",
"prevent_screenshots": "スクリーンショットと画面録画を防止する"
}
"prevent_screenshots": "スクリーンショットと画面録画を防止する",
"modify_2fa": "ケーキの 2FA を変更する",
"disable_cake_2fa": "Cake 2FA を無効にする",
"question_to_disable_2fa":"Cake 2FA を無効にしてもよろしいですか?ウォレットと特定の機能にアクセスするために 2FA コードは必要なくなります。",
"disable": "無効にする",
"setup_2fa": "セットアップ ケーキ 2FA",
"verify_with_2fa": "Cake 2FA で検証する",
"totp_code": "TOTP コード",
"please_fill_totp": "他のデバイスにある 8 桁のコードを入力してください",
"totp_2fa_success": "成功!このウォレットでは Cake 2FA が有効になっています。ウォレットへのアクセスを失った場合に備えて、ニーモニック シードを忘れずに保存してください。",
"totp_verification_success" :"検証成功!",
"totp_2fa_failure": "コードが正しくありません。 別のコードを試すか、新しい秘密鍵を生成してください。 8 桁のコードと SHA512 をサポートする互換性のある 2FA アプリを使用してください。",
"enter_totp_code": "TOTPコードを入力してください。",
"add_secret_code":"このシークレット コードを別のデバイスに追加する",
"totp_secret_code":"TOTPシークレットコード",
"important_note": "重要な注意点",
"setup_2fa_text": "Cake 2FA は、コールド ストレージほど安全ではありません。 2FA は、あなたが寝ているときに友人が指紋を提供するなどの基本的なタイプの攻撃から保護します。\n\n Cake 2FA は、巧妙な攻撃者による侵害されたデバイスから保護しません。\n\n 2FA コードにアクセスできなくなった場合、このウォレットにアクセスできなくなります。ニーモニック シードからウォレットを復元する必要があります。したがって、ニーモニック シードをバックアップする必要があります。さらに、あなたのニーモニック シードにアクセスできる誰かが、Cake 2FA をバイパスして、あなたの資金を盗むことができます。\n\n Cake は無印の財布。",
"setup_totp_recommended": "TOTP を設定する (推奨)",
"disable_buy": "購入アクションを無効にする",
"disable_sell": "販売アクションを無効にする"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "금액이 최소보다 적습니다.",
"error_text_input_above_maximum_limit" : "금액이 최대 값보다 많습니다.",
"show_market_place":"마켓플레이스 표시",
"prevent_screenshots": "스크린샷 및 화면 녹화 방지"
"prevent_screenshots": "스크린샷 및 화면 녹화 방지",
"modify_2fa": "수정 케이크 2FA",
"disable_cake_2fa": "케이크 2FA 비활성화",
"question_to_disable_2fa":"Cake 2FA를 비활성화하시겠습니까? 지갑 및 특정 기능에 액세스하는 데 더 이상 2FA 코드가 필요하지 않습니다.",
"disable": "장애를 입히다",
"setup_2fa": "케이크 2FA 설정",
"verify_with_2fa": "케이크 2FA로 확인",
"totp_code": "TOTP 코드",
"please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.",
"totp_2fa_success": "성공! 이 지갑에 케이크 2FA가 활성화되었습니다. 지갑 액세스 권한을 잃을 경우를 대비하여 니모닉 시드를 저장하는 것을 잊지 마십시오.",
"totp_verification_success" :"확인 성공!",
"totp_2fa_failure": "잘못된 코드입니다. 다른 코드를 시도하거나 새 비밀 키를 생성하십시오. 8자리 코드와 SHA512를 지원하는 호환되는 2FA 앱을 사용하세요.",
"enter_totp_code": "TOTP 코드를 입력하세요.",
"add_secret_code":"이 비밀 코드를 다른 장치에 추가",
"totp_secret_code":"TOTP 비밀 코드",
"important_note": "중요 사항",
"setup_2fa_text": "케이크 2FA는 냉장 보관만큼 안전하지 않습니다. 2FA는 당신이 잠자는 동안 친구가 지문을 제공하는 것과 같은 기본적인 유형의 공격으로부터 보호합니다.\n\n Cake 2FA는 정교한 공격자에 의해 손상된 장치로부터 보호하지 않습니다.\n\n 2FA 코드에 대한 액세스 권한을 잃으면 , 이 지갑에 대한 액세스 권한을 잃게 됩니다. 니모닉 시드에서 지갑을 복원해야 합니다. 따라서 니모닉 시드를 백업해야 합니다! 또한 니모닉 시드에 액세스할 수 있는 사람이 Cake 2FA를 우회하여 자금을 훔칠 수 있습니다.\n\n 니모닉 시드에 대한 액세스 권한을 잃으면 Cake 지원 직원이 도와줄 수 없습니다. 비수탁 지갑.",
"setup_totp_recommended": "TOTP 설정(권장)",
"disable_buy": "구매 행동 비활성화",
"disable_sell": "판매 조치 비활성화"
}

View file

@ -708,5 +708,36 @@
"error_text_input_below_minimum_limit" : "ပမာဏသည် အနိမ့်ဆုံးထက်နည်းသည်။",
"error_text_input_above_maximum_limit" : "ပမာဏသည် အများဆုံးထက် ပိုများသည်။",
"show_market_place":"စျေးကွက်ကိုပြသပါ။",
"prevent_screenshots": "ဖန်သားပြင်ဓာတ်ပုံများနှင့် မျက်နှာပြင်ရိုက်ကူးခြင်းကို တားဆီးပါ။"
"prevent_screenshots": "ဖန်သားပြင်ဓာတ်ပုံများနှင့် မျက်နှာပြင်ရိုက်ကူးခြင်းကို တားဆီးပါ။",
"modify_2fa": "ကိတ်မုန့် 2FA ကို ပြင်ဆင်ပါ။",
"disable_cake_2fa": "ကိတ်မုန့် 2FA ကို ပိတ်ပါ။",
"question_to_disable_2fa":"Cake 2FA ကို ပိတ်လိုသည်မှာ သေချာပါသလား။ ပိုက်ဆံအိတ်နှင့် အချို့သောလုပ်ဆောင်ချက်များကို အသုံးပြုရန်အတွက် 2FA ကုဒ်တစ်ခု မလိုအပ်တော့ပါ။",
"disable": "ပိတ်ပါ။",
"setup_2fa": "ကိတ်မုန့် 2FA စနစ်ထည့်သွင်းပါ။",
"verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။",
"totp_code": "TOTP ကုဒ်",
"please_fill_totp": "သင့်အခြားစက်တွင်ရှိသော ဂဏန်း ၈ လုံးကုဒ်ကို ကျေးဇူးပြု၍ ဖြည့်ပါ။",
"totp_2fa_success": "အောင်မြင် ဤပိုက်ဆံအိတ်အတွက် ကိတ်မုန့် 2FA ကို ဖွင့်ထားသည်။ ပိုက်ဆံအိတ်ဝင်ရောက်ခွင့်ဆုံးရှုံးသွားသောအခါတွင် သင်၏ mnemonic မျိုးစေ့များကို သိမ်းဆည်းရန် မမေ့ပါနှင့်။",
"totp_verification_success" :"အတည်ပြုခြင်း အောင်မြင်ပါသည်။",
"totp_2fa_failure": "ကုဒ်မမှန်ပါ။ ကျေးဇူးပြု၍ အခြားကုဒ်တစ်ခုကို စမ်းကြည့်ပါ သို့မဟုတ် လျှို့ဝှက်သော့အသစ်တစ်ခု ဖန်တီးပါ။ ဂဏန်း ၈ လုံးကုဒ်များနှင့် SHA512 ကို ပံ့ပိုးပေးသည့် တွဲဖက်အသုံးပြုနိုင်သော 2FA အက်ပ်ကို အသုံးပြုပါ။",
"enter_totp_code": "ကျေးဇူးပြု၍ TOTP ကုဒ်ကို ထည့်ပါ။",
"add_secret_code":"ဤလျှို့ဝှက်ကုဒ်ကို အခြားစက်ပစ္စည်းသို့ ထည့်ပါ။",
"totp_secret_code":"TOTP လျှို့ဝှက်ကုဒ်",
"important_note": "အရေးကြီးသောမှတ်ချက်",
"setup_2fa_text": "ကိတ်မုန့် 2FA သည် အအေးခန်းကဲ့သို့ မလုံခြုံပါ။ 2FA သည် သင်အိပ်နေစဉ်တွင် သင့်သူငယ်ချင်းသည် သင့်လက်ဗွေရာကို ပေးဆောင်ခြင်းကဲ့သို့သော အခြေခံတိုက်ခိုက်မှုအမျိုးအစားများကို ကာကွယ်ပေးပါသည်။\n\n Cake 2FA သည် ခေတ်မီဆန်းပြားသော တိုက်ခိုက်သူ၏ အန္တရာယ်ပြုသည့်စက်ပစ္စည်းကို မကာကွယ်ပါ။\n\n သင်၏ 2FA ကုဒ်များကို အသုံးပြုခွင့်ဆုံးရှုံးသွားပါက၊ ဤပိုက်ဆံအိတ်ကို သင်ဝင်ရောက်ခွင့်ဆုံးရှုံးလိမ့်မည်။ သင့်ပိုက်ဆံအိတ်ကို mnemonic မျိုးစေ့မှ ပြန်လည်ရယူရန် လိုအပ်မည်ဖြစ်သည်။ ထို့ကြောင့် သင်၏ MNEMONIC မျိုးစေ့များကို အရန်သိမ်းထားရပါမည်။ ထို့အပြင်၊ သင်၏ mnemonic မျိုးစေ့(များ) ကို အသုံးပြုခွင့်ရှိသူတစ်ဦးက Cake 2FA ကိုကျော်ဖြတ်ကာ သင့်ရန်ပုံငွေများကို ခိုးယူနိုင်ပါမည်။\n\n ကိတ်မုန့်သည် သင့် mnemonic မျိုးစေ့သို့ ဝင်ရောက်ခွင့်ဆုံးရှုံးသွားပါက သင့်အား ကူညီပေးနိုင်မည်မဟုတ်ပါ၊ အထိန်းအချုပ်မရှိသော ပိုက်ဆံအိတ်။",
"setup_totp_recommended": "TOTP ကို ​​စနစ်ထည့်သွင်းပါ (အကြံပြုထားသည်)",
"disable_buy": "ဝယ်ယူမှု လုပ်ဆောင်ချက်ကို ပိတ်ပါ။",
"disable_sell": "ရောင်းချခြင်းလုပ်ဆောင်ချက်ကို ပိတ်ပါ။"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Bedrag is minder dan minimaal",
"error_text_input_above_maximum_limit" : "Bedrag is meer dan maximaal",
"show_market_place":"Toon Marktplaats",
"prevent_screenshots": "Voorkom screenshots en schermopname"
"prevent_screenshots": "Voorkom screenshots en schermopname",
"modify_2fa": "Wijzig Cake 2FA",
"disable_cake_2fa": "Taart 2FA uitschakelen",
"question_to_disable_2fa":"Weet je zeker dat je Cake 2FA wilt uitschakelen? Er is geen 2FA-code meer nodig om toegang te krijgen tot de portemonnee en bepaalde functies.",
"disable": "Uitzetten",
"setup_2fa": "Opstelling Taart 2FA",
"verify_with_2fa": "Controleer met Cake 2FA",
"totp_code": "TOTP-code",
"please_fill_totp": "Vul de 8-cijferige code in die op uw andere apparaat aanwezig is",
"totp_2fa_success": "Succes! Cake 2FA ingeschakeld voor deze portemonnee. Vergeet niet om uw geheugensteuntje op te slaan voor het geval u de toegang tot de portemonnee kwijtraakt.",
"totp_verification_success" :"Verificatie geslaagd!",
"totp_2fa_failure": "Foute code. Probeer een andere code of genereer een nieuwe geheime sleutel. Gebruik een compatibele 2FA-app die 8-cijferige codes en SHA512 ondersteunt.",
"enter_totp_code": "Voer de TOTP-code in.",
"add_secret_code":"Voeg deze geheime code toe aan een ander apparaat",
"totp_secret_code":"TOTP-geheime code",
"important_note": "Belangrijke notitie",
"setup_2fa_text": "Cake 2FA is NIET zo veilig als koude opslag. 2FA beschermt tegen basistypen aanvallen, zoals uw vriend die uw vingerafdruk geeft terwijl u slaapt.\n\n Cake 2FA biedt GEEN bescherming tegen een gecompromitteerd apparaat door een geavanceerde aanvaller.\n\n Als u de toegang tot uw 2FA-codes kwijtraakt , VERLIEST U DE TOEGANG TOT DEZE PORTEFEUILLE. U moet uw portemonnee herstellen van mnemonic seed. JE MOET DAAROM EEN BACK-UP MAKEN VAN JE MNEMONISCHE ZADEN! Verder kan iemand met toegang tot je geheugensteuntje(s) je geld stelen, waarbij Cake 2FA wordt omzeild.\n\n Het ondersteunend personeel van Cake kan je niet helpen als je de toegang tot je geheugensteuntje kwijtraakt, aangezien Cake een niet-bewaarbare portemonnee.",
"setup_totp_recommended": "TOTP instellen (aanbevolen)",
"disable_buy": "Koopactie uitschakelen",
"disable_sell": "Verkoopactie uitschakelen"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Kwota jest mniejsza niż minimalna",
"error_text_input_above_maximum_limit" : "Kwota jest większa niż maksymalna",
"show_market_place" : "Pokaż rynek",
"prevent_screenshots": "Zapobiegaj zrzutom ekranu i nagrywaniu ekranu"
"prevent_screenshots": "Zapobiegaj zrzutom ekranu i nagrywaniu ekranu",
"modify_2fa": "Zmodyfikuj ciasto 2FA",
"disable_cake_2fa": "Wyłącz Cake 2FA",
"question_to_disable_2fa":"Czy na pewno chcesz wyłączyć Cake 2FA? Kod 2FA nie będzie już potrzebny do uzyskania dostępu do portfela i niektórych funkcji.",
"disable": "Wyłączyć",
"setup_2fa": "Skonfiguruj ciasto 2FA",
"verify_with_2fa": "Sprawdź za pomocą Cake 2FA",
"totp_code": "Kod TOTP",
"please_fill_totp": "Wpisz 8-cyfrowy kod znajdujący się na drugim urządzeniu",
"totp_2fa_success": "Powodzenie! Cake 2FA włączony dla tego portfela. Pamiętaj, aby zapisać swoje mnemoniczne ziarno na wypadek utraty dostępu do portfela.",
"totp_verification_success" :"Weryfikacja powiodła się!",
"totp_2fa_failure": "Błędny kod. Spróbuj użyć innego kodu lub wygeneruj nowy tajny klucz. Użyj kompatybilnej aplikacji 2FA, która obsługuje 8-cyfrowe kody i SHA512.",
"enter_totp_code": "Wprowadź kod TOTP.",
"add_secret_code":"Dodaj ten tajny kod do innego urządzenia",
"totp_secret_code":"Tajny kod TOTP",
"important_note": "Ważna uwaga",
"setup_2fa_text": "Cake 2FA NIE jest tak bezpieczny jak przechowywanie w chłodni. 2FA chroni przed podstawowymi typami ataków, takimi jak udostępnienie odcisku palca przez znajomego podczas snu.\n\n Cake 2FA NIE chroni przed zhakowanym urządzeniem przez wyrafinowanego atakującego.\n\n Jeśli utracisz dostęp do swoich kodów 2FA , UTRACISZ DOSTĘP DO TEGO PORTFELA. Będziesz musiał przywrócić swój portfel z mnemonicznego materiału siewnego. DLATEGO MUSISZ ZROBIĆ KOPIĘ SWOICH NASION MNEMONICZNYCH! Co więcej, ktoś z dostępem do twoich mnemonicznych nasion będzie mógł ukraść twoje fundusze, omijając Cake 2FA.\n\n Personel pomocniczy Cake nie będzie mógł ci pomóc, jeśli stracisz dostęp do swojego mnemonicznego seeda, ponieważ Cake jest portfel niezabezpieczony.",
"setup_totp_recommended": "Skonfiguruj TOTP (zalecane)",
"disable_buy": "Wyłącz akcję kupna",
"disable_sell": "Wyłącz akcję sprzedaży"
}

View file

@ -707,5 +707,24 @@
"error_text_input_below_minimum_limit" : "O valor é menor que o mínimo",
"error_text_input_above_maximum_limit" : "O valor é superior ao máximo",
"show_market_place":"Mostrar mercado",
"prevent_screenshots": "Evite capturas de tela e gravação de tela"
"prevent_screenshots": "Evite capturas de tela e gravação de tela",
"modify_2fa": "Modificar Bolo 2FA",
"disable_cake_2fa": "Desabilitar Bolo 2FA",
"question_to_disable_2fa":"Tem certeza de que deseja desativar o Cake 2FA? Um código 2FA não será mais necessário para acessar a carteira e certas funções.",
"disable": "Desativar",
"setup_2fa": "Bolo de Configuração 2FA",
"verify_with_2fa": "Verificar com Cake 2FA",
"totp_code": "Código TOTP",
"please_fill_totp": "Por favor, preencha o código de 8 dígitos presente em seu outro dispositivo",
"totp_2fa_success": "Sucesso! Cake 2FA ativado para esta carteira. Lembre-se de salvar sua semente mnemônica caso perca o acesso à carteira.",
"totp_verification_success" :"Verificação bem-sucedida!",
"totp_2fa_failure": "Código incorreto. Tente um código diferente ou gere uma nova chave secreta. Use um aplicativo 2FA compatível com códigos de 8 dígitos e SHA512.",
"enter_totp_code": "Digite o código TOTP.",
"add_secret_code":"Adicione este código secreto a outro dispositivo",
"totp_secret_code":"Código Secreto TOTP",
"important_note": "Nota importante",
"setup_2fa_text": "O Cake 2FA NÃO é tão seguro quanto o armazenamento a frio. O 2FA protege contra tipos básicos de ataques, como seu amigo fornecer sua impressão digital enquanto você está dormindo.\n\n O Cake 2FA NÃO protege contra um dispositivo comprometido por um invasor sofisticado.\n\n Se você perder o acesso aos seus códigos 2FA , VOCÊ PERDERÁ O ACESSO A ESTA CARTEIRA. Você precisará restaurar sua carteira da semente mnemônica. VOCÊ DEVE, PORTANTO, FAZER BACKUP DE SUAS SEMENTES MNEMÔNICAS! Além disso, alguém com acesso às suas sementes mnemônicas poderá roubar seus fundos, ignorando o Cake 2FA.\n\n A equipe de suporte do Cake não poderá ajudá-lo se você perder o acesso à sua semente mnemônica, pois o Cake é um carteira não custodial.",
"setup_totp_recommended": "Configurar TOTP (recomendado)",
"disable_buy": "Desativar ação de compra",
"disable_sell": "Desativar ação de venda"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Сумма меньше минимальной",
"error_text_input_above_maximum_limit" : "Сумма больше максимальной",
"show_market_place":"Показать торговую площадку",
"prevent_screenshots": "Предотвратить скриншоты и запись экрана"
"prevent_screenshots": "Предотвратить скриншоты и запись экрана",
"modify_2fa": "Изменить торт 2FA",
"disable_cake_2fa": "Отключить торт 2FA",
"question_to_disable_2fa":"Вы уверены, что хотите отключить Cake 2FA? Код 2FA больше не потребуется для доступа к кошельку и некоторым функциям.",
"disable": "Запрещать",
"setup_2fa": "Настройка торта 2FA",
"verify_with_2fa": "Подтвердить с помощью Cake 2FA",
"totp_code": "TOTP-код",
"please_fill_totp": "Пожалуйста, введите 8-значный код на другом устройстве",
"totp_2fa_success": "Успех! Для этого кошелька включена двухфакторная аутентификация Cake. Не забудьте сохранить мнемоническое семя на случай, если вы потеряете доступ к кошельку.",
"totp_verification_success" :"Проверка прошла успешно!",
"totp_2fa_failure": "Неверный код. Пожалуйста, попробуйте другой код или создайте новый секретный ключ. Используйте совместимое приложение 2FA, которое поддерживает 8-значные коды и SHA512.",
"enter_totp_code": "Пожалуйста, введите TOTP-код.",
"add_secret_code":"Добавьте этот секретный код на другое устройство",
"totp_secret_code":"Секретный код ТОТП",
"important_note": "Важная заметка",
"setup_2fa_text": "Cake 2FA НЕ так безопасен, как холодное хранилище. Двухфакторная аутентификация защищает от основных типов атак, таких как отпечаток вашего друга, когда вы спите.\n\n Двухфакторная аутентификация Cake НЕ защищает от взлома устройства опытным злоумышленником.\n\n Если вы потеряете доступ к своим кодам двухфакторной аутентификации. , ВЫ ПОТЕРЯЕТЕ ДОСТУП К ЭТОМУ КОШЕЛЬКУ. Вам нужно будет восстановить свой кошелек из мнемонической семени. ПОЭТОМУ ВЫ ДОЛЖНЫ СОЗДАТЬ РЕЗЕРВНУЮ ВЕРСИЮ СВОИХ МНЕМОНИКОВ! Кроме того, кто-то, имеющий доступ к вашему мнемоническому семени, сможет украсть ваши средства, минуя Cake 2FA.\n\n Персонал службы поддержки Cake не сможет помочь вам, если вы потеряете доступ к своему мнемоническому семени, поскольку Cake — это некастодиальный кошелек.",
"setup_totp_recommended": "Настроить TOTP (рекомендуется)",
"disable_buy": "Отключить действие покупки",
"disable_sell": "Отключить действие продажи"
}

Some files were not shown because too many files have changed in this diff Show more