mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-12 09:32:33 +00:00
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:
commit
0a76686c96
112 changed files with 4654 additions and 1288 deletions
22
README.md
22
README.md
|
@ -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
|
||||
|
|
|
@ -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
BIN
assets/images/flags/hau.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
BIN
assets/images/restore_qr.png
Normal file
BIN
assets/images/restore_qr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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});
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
13
lib/core/totp_request_details.dart
Normal file
13
lib/core/totp_request_details.dart
Normal 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,
|
||||
});
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
613
lib/di.dart
613
lib/di.dart
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {};
|
||||
|
|
|
@ -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>(
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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
940
lib/hausa_intl.dart
Normal 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();
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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';
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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()
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -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)),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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!,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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);
|
||||
}),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
|
|||
}
|
||||
},
|
||||
image: item.image,
|
||||
title: item.name,
|
||||
title: item.name.call(context),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, index) => Container(
|
||||
|
|
|
@ -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);
|
||||
}),
|
||||
],
|
||||
);
|
||||
}),
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
55
lib/src/screens/setup_2fa/modify_2fa_page.dart
Normal file
55
lib/src/screens/setup_2fa/modify_2fa_page.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
62
lib/src/screens/setup_2fa/setup_2fa.dart
Normal file
62
lib/src/screens/setup_2fa/setup_2fa.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
221
lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
Normal file
221
lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
145
lib/src/screens/setup_2fa/setup_2fa_qr_page.dart
Normal file
145
lib/src/screens/setup_2fa/setup_2fa_qr_page.dart
Normal 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),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
61
lib/src/widgets/picker_wrapper_widget.dart
Normal file
61
lib/src/widgets/picker_wrapper_widget.dart
Normal 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,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
83
lib/utils/totp_utils.dart
Normal 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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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';
|
||||
|
|
159
lib/view_model/set_up_2fa_viewmodel.dart
Normal file
159
lib/view_model/set_up_2fa_viewmodel.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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": "قم بتعطيل إجراء البيع"
|
||||
}
|
||||
|
|
|
@ -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": "Деактивирайте действието за продажба"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
714
res/values/strings_ha.arb
Normal 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"
|
||||
}
|
|
@ -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": "बेचने की कार्रवाई अक्षम करें"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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": "販売アクションを無効にする"
|
||||
}
|
|
@ -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": "판매 조치 비활성화"
|
||||
}
|
||||
|
|
|
@ -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": "ရောင်းချခြင်းလုပ်ဆောင်ချက်ကို ပိတ်ပါ။"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue