Merge branch 'main' into CW-292-Save-historical-fiat-API-rate

This commit is contained in:
Serhii 2023-05-19 09:45:15 +03:00
commit 7473590abb
85 changed files with 2785 additions and 1142 deletions

View file

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

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,6 +15,8 @@ import UnstoppableDomainsResolution
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
makeSecure()
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let legacyMigrationChannel = FlutterMethodChannel(
@ -96,22 +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?.rootViewController?.view.endEditing(true)
self.window?.isHidden = true;
}
override func applicationDidBecomeActive(_: UIApplication) {
self.window?.isHidden = false;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,6 +10,7 @@ import 'package:cake_wallet/entities/receive_page_option.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';
@ -27,6 +28,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';
@ -53,8 +58,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';
@ -187,6 +192,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;
@ -201,18 +208,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;
@ -225,8 +232,7 @@ Future setup(
_anonpayInvoiceInfoSource = anonpayInvoiceInfoSource;
if (!_isSetupFinished) {
getIt.registerSingletonAsync<SharedPreferences>(
() => SharedPreferences.getInstance());
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
}
final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty ?? false) &&
@ -256,84 +262,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>(),
@ -354,62 +349,106 @@ Future setup(
)
);
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>();
@ -422,16 +461,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;
@ -445,28 +494,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)));
@ -486,15 +534,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>(),
@ -504,7 +553,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>(),
@ -513,8 +563,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!;
@ -523,11 +575,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;
@ -544,16 +597,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)));
@ -574,41 +625,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>()));
@ -616,41 +663,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!,
@ -660,40 +704,34 @@ 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!);
default:
throw Exception('Unexpected token: ${param1.toString()} for generating of WalletService');
}
});
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!));
@ -702,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,
@ -726,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!);
});
@ -785,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, _) {
@ -794,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());
@ -804,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;
@ -828,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());
@ -841,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);
});
@ -888,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));
});
@ -939,42 +969,44 @@ Future setup(
getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
getIt.registerFactory(() => AnonPayApi(useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
wallet: getIt.get<AppStore>().wallet!)
);
getIt.registerFactory(() => AnonPayApi(
useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
wallet: getIt.get<AppStore>().wallet!));
getIt.registerFactory(() => DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>(), getIt.get<AuthService>()));
getIt.registerFactory(() =>
DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>(), getIt.get<AuthService>()));
getIt.registerFactory(() => DesktopSidebarViewModel());
getIt.registerFactoryParam<AnonpayDetailsViewModel, AnonpayInvoiceInfo, void>(
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
=> AnonpayDetailsViewModel(
anonPayApi: getIt.get<AnonPayApi>(),
anonpayInvoiceInfo: anonpayInvoiceInfo,
settingsStore: getIt.get<SettingsStore>(),
));
(AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsViewModel(
anonPayApi: getIt.get<AnonPayApi>(),
anonpayInvoiceInfo: anonpayInvoiceInfo,
settingsStore: getIt.get<SettingsStore>(),
));
getIt.registerFactoryParam<AnonPayReceivePage, AnonpayInfoBase, void>(
(AnonpayInfoBase anonpayInvoiceInfo, _) => AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
(AnonpayInfoBase anonpayInvoiceInfo, _) =>
AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
getIt.registerFactoryParam<AnonpayDetailsPage, AnonpayInvoiceInfo, void>(
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
=> AnonpayDetailsPage(anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
(AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsPage(
anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
=> IoniaPaymentStatusViewModel(
getIt.get<IoniaService>(),
paymentInfo: paymentInfo,
committedInfo: committedInfo));
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo,
AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
IoniaPaymentStatusViewModel(getIt.get<IoniaService>(),
paymentInfo: paymentInfo, committedInfo: committedInfo));
getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
=> IoniaPaymentStatusPage(getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo,
AnyPayPaymentCommittedInfo>(
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
IoniaPaymentStatusPage(
getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>((type, _) =>
AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
getIt.registerFactoryParam<AdvancedPrivacySettingsViewModel, WalletType, void>(
(type, _) => AdvancedPrivacySettingsViewModel(type, getIt.get<SettingsStore>()));
_isSetupFinished = true;
}
}

View file

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

View file

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

View file

@ -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
));
@ -188,6 +195,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreWallet:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<WalletRestorePage>(
param1: settings.arguments as WalletType));
@ -260,6 +268,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 +329,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 +365,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 +383,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 +393,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
getIt.get<WalletRestorationFromSeedVM>(param1: args);
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => RestoreWalletFromSeedDetailsPage(
walletRestorationFromSeedVM: walletRestorationFromSeedVM));
@ -403,6 +427,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreFromBackup:
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<RestoreFromBackupPage>());
case Routes.support:
@ -509,7 +534,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 +566,15 @@ Route<dynamic> createRoute(RouteSettings settings) {
fullscreenDialog: true,
builder: (_) => getIt.get<TransactionsPage>());
case Routes.setup_2faPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<Setup2FAPage>());
case Routes.setup_2faQRPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<Setup2FAQRPage>());
case Routes.modify2FAPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<Modify2FAPage>());
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(

View file

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

View file

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

View file

@ -96,7 +96,10 @@ class AddressPage extends BasePage {
@override
Widget middle(BuildContext context) =>
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
PresentReceiveOptionPicker(
receiveOptionViewModel: receiveOptionViewModel,
hasWhiteBackground: currentTheme.type == ThemeType.light,
);
@override
Widget Function(BuildContext, Widget) get rootWrapper =>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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';
@ -5,6 +7,7 @@ import 'package:cake_wallet/entities/preferences_key.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';
@ -20,7 +23,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';
@ -34,15 +36,21 @@ 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 bool initialShowHistoricalFiatRate,
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,
@ -52,37 +60,42 @@ abstract class SettingsStoreBase with Store {
TransactionPriority? initialMoneroTransactionPriority,
TransactionPriority? initialHavenTransactionPriority,
TransactionPriority? initialLitecoinTransactionPriority})
: 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,
showHistoricalFiatRate = initialShowHistoricalFiatRate,
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;
}
reaction(
@ -92,8 +105,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;
@ -122,35 +135,48 @@ 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(
(_) => showHistoricalFiatRate,
@ -163,20 +189,18 @@ abstract class SettingsStoreBase with Store {
(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,
@ -184,17 +208,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;
@ -225,12 +247,31 @@ abstract class SettingsStoreBase with Store {
@observable
bool isAppSecure;
@observable
bool disableBuy;
@observable
bool disableSell;
@observable
bool allowBiometricalAuthentication;
@observable
bool showHistoricalFiatRate;
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;
@ -254,6 +295,8 @@ abstract class SettingsStoreBase with Store {
String appVersion;
String deviceName;
SharedPreferences _sharedPreferences;
ObservableMap<WalletType, Node> nodes;
@ -262,7 +305,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;
@ -271,10 +314,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,
@ -282,18 +325,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;
@ -313,15 +353,17 @@ abstract class SettingsStoreBase with Store {
litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium();
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 currentFiatApiMode = FiatApiMode.deserialize(
raw: sharedPreferences
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) ??
@ -329,24 +371,25 @@ abstract class SettingsStoreBase with Store {
final showHistoricalFiatRate = sharedPreferences
.getBool(PreferencesKey.showHistoricalFiatRateKey) ??
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;
@ -356,40 +399,38 @@ 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 bitcoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final litecoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final moneroNode = nodeSource.get(nodeId);
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
final havenNode = nodeSource.get(havenNodeId);
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;
}
return SettingsStore(
@ -397,14 +438,20 @@ 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,
initialShowHistoricalFiatRate: showHistoricalFiatRate,
initialTotpSecretKey: totpSecretKey,
initialUseTOTP2FA: useTOTP2FA,
initialFailedTokenTrial: tokenTrialNumber,
initialExchangeStatus: exchangeStatus,
initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode,
@ -419,37 +466,45 @@ 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]!;
}
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;
@ -460,19 +515,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) {
@ -481,15 +533,15 @@ 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 bitcoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
final litecoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
final moneroNode = nodeSource.get(nodeId);
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
@ -523,12 +575,10 @@ 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;
default:
break;
@ -536,4 +586,29 @@ abstract class SettingsStoreBase with Store {
nodes[walletType] = node;
}
static Future<String?> _getDeviceName() async {
String? deviceName = '';
final deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
final androidInfo = await deviceInfoPlugin.androidInfo;
deviceName = '${androidInfo.brand}%20${androidInfo.manufacturer}%20${androidInfo.model}';
print(deviceName);
} else if (Platform.isIOS) {
final iosInfo = await deviceInfoPlugin.iosInfo;
deviceName = iosInfo.model;
} else if (Platform.isLinux) {
final linuxInfo = await deviceInfoPlugin.linuxInfo;
deviceName = linuxInfo.prettyName;
} else if (Platform.isMacOS) {
final macInfo = await deviceInfoPlugin.macOsInfo;
deviceName = macInfo.computerName;
} else if (Platform.isWindows) {
final windowsInfo = await deviceInfoPlugin.windowsInfo;
deviceName = windowsInfo.productName;
}
return deviceName;
}
}

View file

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

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

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

View file

@ -54,9 +54,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,
@ -316,14 +314,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;
@ -433,11 +436,7 @@ abstract class DashboardViewModelBase with Store {
void updateActions() {
hasExchangeAction = !isHaven;
isEnabledBuyAction = wallet.type != WalletType.haven;
hasBuyAction = !isHaven;
isEnabledSellAction = wallet.type != WalletType.haven
&& wallet.type != WalletType.monero
&& wallet.type != WalletType.litecoin;
hasSellAction = !isHaven;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -706,5 +706,24 @@
"error_text_input_below_minimum_limit" : "จำนวนเงินน้อยกว่าขั้นต่ำ",
"error_text_input_above_maximum_limit" : "จำนวนเงินสูงกว่าค่าสูงสุด",
"show_market_place":"แสดงตลาดกลาง",
"prevent_screenshots": "ป้องกันภาพหน้าจอและการบันทึกหน้าจอ"
"prevent_screenshots": "ป้องกันภาพหน้าจอและการบันทึกหน้าจอ",
"modify_2fa": "แก้ไขเค้ก 2FA",
"disable_cake_2fa": "ปิดการใช้งานเค้ก 2FA",
"question_to_disable_2fa":"คุณแน่ใจหรือไม่ว่าต้องการปิดการใช้งาน Cake 2FA ไม่จำเป็นต้องใช้รหัส 2FA ในการเข้าถึงกระเป๋าเงินและฟังก์ชั่นบางอย่างอีกต่อไป",
"disable": "ปิดการใช้งาน",
"setup_2fa": "ตั้งค่าเค้ก 2FA",
"verify_with_2fa": "ตรวจสอบกับ Cake 2FA",
"totp_code": "รหัสทีโอพี",
"please_fill_totp": "กรุณากรอกรหัส 8 หลักที่อยู่ในอุปกรณ์อื่นของคุณ",
"totp_2fa_success": "ความสำเร็จ! Cake 2FA เปิดใช้งานสำหรับกระเป๋าเงินนี้ อย่าลืมบันทึกเมล็ดช่วยจำของคุณในกรณีที่คุณสูญเสียการเข้าถึงกระเป๋าเงิน",
"totp_verification_success" :"การยืนยันสำเร็จ!",
"totp_2fa_failure": "รหัสไม่ถูกต้อง. โปรดลองใช้รหัสอื่นหรือสร้างรหัสลับใหม่ ใช้แอพ 2FA ที่เข้ากันได้ซึ่งรองรับรหัส 8 หลักและ SHA512",
"enter_totp_code": "กรุณาใส่รหัสทีโอที",
"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 จะไม่สามารถช่วยเหลือคุณได้ หากคุณสูญเสียการเข้าถึงเมล็ดช่วยจำ เนื่องจาก Cake เป็น กระเป๋าสตางค์ที่ไม่เป็นผู้ดูแล",
"setup_totp_recommended": "ตั้งค่า TOTP (แนะนำ)",
"disable_buy": "ปิดการใช้งานการซื้อ",
"disable_sell": "ปิดการใช้งานการขาย"
}

View file

@ -708,5 +708,24 @@
"error_text_input_below_minimum_limit" : "Miktar minimumdan daha azdır",
"error_text_input_above_maximum_limit" : "Miktar maksimumdan daha fazla",
"show_market_place":"Pazar Yerini Göster",
"prevent_screenshots": "Ekran görüntülerini ve ekran kaydını önleyin"
"prevent_screenshots": "Ekran görüntülerini ve ekran kaydını önleyin",
"modify_2fa": "Cake 2FA'yı Değiştirin",
"disable_cake_2fa": "Cake 2FA'yı Devre Dışı Bırak",
"question_to_disable_2fa":"Cake 2FA'yı devre dışı bırakmak istediğinizden emin misiniz? M-cüzdana ve belirli işlevlere erişmek için artık 2FA koduna gerek kalmayacak.",
"disable": "Devre dışı bırakmak",
"setup_2fa": "Kurulum Pastası 2FA",
"verify_with_2fa": "Cake 2FA ile Doğrulayın",
"totp_code": "TOTP Kodu",
"please_fill_totp": "Lütfen diğer cihazınızda bulunan 8 haneli kodu girin",
"totp_2fa_success": "Başarı! Bu cüzdan için Cake 2FA etkinleştirildi. Mnemonic seed'inizi cüzdan erişiminizi kaybetme ihtimaline karşı kaydetmeyi unutmayın.",
"totp_verification_success" :"Doğrulama Başarılı!",
"totp_2fa_failure": "Yanlış kod. Lütfen farklı bir kod deneyin veya yeni bir gizli anahtar oluşturun. 8 basamaklı kodları ve SHA512'yi destekleyen uyumlu bir 2FA uygulaması kullanın.",
"enter_totp_code": "Lütfen TOTP Kodunu giriniz.",
"add_secret_code":"Bu gizli kodu başka bir cihaza ekleyin",
"totp_secret_code":"TOTP Gizli Kodu",
"important_note": "Önemli Not",
"setup_2fa_text": "Cake 2FA, soğuk hava deposu kadar güvenli DEĞİLDİR. 2FA, siz uyurken arkadaşınızın parmak izinizi sağlaması gibi temel saldırı türlerine karşı koruma sağlar.\n\n Cake 2FA, gelişmiş bir saldırgan tarafından güvenliği ihlal edilmiş bir cihaza karşı koruma SAĞLAMAZ.\n\n 2FA kodlarınıza erişimi kaybederseniz , BU CÜZDANA ERİŞİMİNİZİ KAYBEDECEKSİNİZ. Mnemonic seed'den cüzdanınızı geri yüklemeniz gerekecek. BU NEDENLE HATIRLAYICI TOHUMLARINIZI YEDEKLEMELİSİNİZ! Ayrıca anımsatıcı tohumlarınıza erişimi olan biri, Cake 2FA'yı atlayarak paranızı çalabilir.\n\n Cake, anımsatıcı tohumlarınıza erişimi kaybederseniz size yardımcı olamaz, çünkü Cake bir saklama dışı cüzdan.",
"setup_totp_recommended": "TOTP'yi kurun (Önerilir)",
"disable_buy": "Satın alma işlemini devre dışı bırak",
"disable_sell": "Satış işlemini devre dışı bırak"
}

View file

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

View file

@ -703,5 +703,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":"کیا آپ واقعی کیک 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": "غلط کوڈ. براہ کرم ایک مختلف کوڈ آزمائیں یا ایک نئی خفیہ کلید بنائیں۔ ایک ہم آہنگ 2FA ایپ استعمال کریں جو 8 ہندسوں کے کوڈز اور SHA512 کو سپورٹ کرتی ہو۔",
"enter_totp_code": "براہ کرم TOTP کوڈ درج کریں۔",
"add_secret_code":"اس خفیہ کوڈ کو کسی اور ڈیوائس میں شامل کریں۔",
"totp_secret_code":"TOTP خفیہ کوڈ",
"important_note": "اہم نوٹ",
"setup_2fa_text": "کیک 2FA کولڈ اسٹوریج کی طرح محفوظ نہیں ہے۔ 2FA بنیادی قسم کے حملوں سے حفاظت کرتا ہے، جیسے کہ آپ کا دوست آپ کے سوتے وقت آپ کے فنگر پرنٹ فراہم کرتا ہے۔\n\n کیک 2FA کسی جدید حملہ آور کے ذریعے سمجھوتہ کرنے والے آلہ سے حفاظت نہیں کرتا ہے۔\n\n اگر آپ اپنے 2FA کوڈز تک رسائی کھو دیتے ہیں ، آپ اس بٹوے تک رسائی سے محروم ہو جائیں گے۔ آپ کو یادداشت کے بیج سے اپنے بٹوے کو بحال کرنے کی ضرورت ہوگی۔ اس لیے آپ کو اپنے یادداشت کے بیجوں کا بیک اپ لینا چاہیے! اس کے علاوہ، آپ کے یادداشت کے بیج تک رسائی رکھنے والا کوئی شخص کیک 2FA کو نظرانداز کرتے ہوئے آپ کے فنڈز چرا سکے گا۔\n\n اگر آپ اپنے یادداشت کے بیج تک رسائی کھو دیتے ہیں تو کیک کا معاون عملہ آپ کی مدد نہیں کر سکے گا، کیونکہ کیک ایک ہے غیر نگہداشت پرس.",
"setup_totp_recommended": "TOTP ترتیب دیں (تجویز کردہ)",
"disable_buy": "خرید ایکشن کو غیر فعال کریں۔",
"disable_sell": "فروخت کی کارروائی کو غیر فعال کریں۔"
}

View file

@ -707,5 +707,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 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 支持人员将无法帮助您,因为 Cake 是一个非托管钱包。",
"setup_totp_recommended": "设置 TOTP推荐",
"disable_buy": "禁用购买操作",
"disable_sell": "禁用卖出操作"
}

View file

@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_ANDROID_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.3.5"
MONERO_COM_BUILD_NUMBER=48
MONERO_COM_VERSION="1.3.6"
MONERO_COM_BUILD_NUMBER=49
MONERO_COM_BUNDLE_ID="com.monero.app"
MONERO_COM_PACKAGE="com.monero.app"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.6.4"
CAKEWALLET_BUILD_NUMBER=158
CAKEWALLET_VERSION="4.6.5"
CAKEWALLET_BUILD_NUMBER=159
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"

View file

@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
APP_IOS_TYPE=$1
MONERO_COM_NAME="Monero.com"
MONERO_COM_VERSION="1.3.5"
MONERO_COM_BUILD_NUMBER=46
MONERO_COM_VERSION="1.3.6"
MONERO_COM_BUILD_NUMBER=47
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="4.6.4"
CAKEWALLET_BUILD_NUMBER=153
CAKEWALLET_VERSION="4.6.5"
CAKEWALLET_BUILD_NUMBER=154
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
HAVEN_NAME="Haven"

View file

@ -15,8 +15,8 @@ if [ -n "$1" ]; then
fi
CAKEWALLET_NAME="Cake Wallet"
CAKEWALLET_VERSION="1.0.3"
CAKEWALLET_BUILD_NUMBER=20
CAKEWALLET_VERSION="1.0.4"
CAKEWALLET_BUILD_NUMBER=22
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then