mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into linux/password-direct-input
Conflicts: cw_bitcoin/lib/electrum_transaction_history.dart lib/core/wallet_loading_service.dart lib/di.dart lib/main.dart lib/router.dart lib/src/screens/dashboard/widgets/market_place_page.dart lib/src/screens/wallet_list/wallet_list_page.dart lib/view_model/wallet_list/wallet_list_view_model.dart macos/Podfile.lock res/values/strings_ar.arb res/values/strings_bg.arb res/values/strings_cs.arb res/values/strings_de.arb res/values/strings_en.arb res/values/strings_es.arb res/values/strings_fr.arb res/values/strings_hi.arb res/values/strings_hr.arb res/values/strings_id.arb res/values/strings_it.arb res/values/strings_ja.arb res/values/strings_ko.arb res/values/strings_my.arb res/values/strings_nl.arb res/values/strings_pl.arb res/values/strings_pt.arb res/values/strings_ru.arb res/values/strings_th.arb res/values/strings_tr.arb res/values/strings_uk.arb res/values/strings_ur.arb res/values/strings_zh.arb
This commit is contained in:
commit
e9582f31e5
104 changed files with 13177 additions and 14946 deletions
|
@ -22,7 +22,6 @@
|
|||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:screenOrientation="portrait"
|
||||
android:exported="true">
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.SplashScreenDrawable"
|
||||
|
|
|
@ -56,9 +56,32 @@ class BitcoinWalletService extends WalletService<
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> remove(String wallet) async =>
|
||||
File(await pathForWalletDir(name: wallet, type: WalletType.bitcoin))
|
||||
.delete(recursive: true);
|
||||
Future<void> remove(String wallet) async {
|
||||
File(await pathForWalletDir(name: wallet, type: getType()))
|
||||
.delete(recursive: true);
|
||||
final walletInfo = walletInfoSource.values.firstWhereOrNull(
|
||||
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||
await walletInfoSource.delete(walletInfo.key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rename(String currentName, String password, String newName) async {
|
||||
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
|
||||
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
||||
final currentWallet = await BitcoinWalletBase.open(
|
||||
password: password,
|
||||
name: currentName,
|
||||
walletInfo: currentWalletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
|
||||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BitcoinWallet> restoreFromKeys(
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
|||
|
||||
part 'electrum_transaction_history.g.dart';
|
||||
|
||||
const _transactionsHistoryFileName = 'transactions.json';
|
||||
const transactionsHistoryFileName = 'transactions.json';
|
||||
|
||||
class ElectrumTransactionHistory = ElectrumTransactionHistoryBase
|
||||
with _$ElectrumTransactionHistory;
|
||||
|
@ -42,7 +42,7 @@ abstract class ElectrumTransactionHistoryBase
|
|||
try {
|
||||
final dirPath =
|
||||
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||
final path = '$dirPath/$_transactionsHistoryFileName';
|
||||
final path = '$dirPath/$transactionsHistoryFileName';
|
||||
final data =
|
||||
json.encode({'height': _height, 'transactions': transactions});
|
||||
await encryptionFileUtils.write(path: path, password: _password, data: data);
|
||||
|
@ -59,7 +59,7 @@ abstract class ElectrumTransactionHistoryBase
|
|||
Future<Map<String, dynamic>> _read() async {
|
||||
final dirPath =
|
||||
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||
final path = '$dirPath/$_transactionsHistoryFileName';
|
||||
final path = '$dirPath/$transactionsHistoryFileName';
|
||||
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||
return json.decode(content) as Map<String, dynamic>;
|
||||
}
|
||||
|
@ -86,4 +86,5 @@ abstract class ElectrumTransactionHistoryBase
|
|||
|
||||
void _update(ElectrumTransactionInfo transaction) =>
|
||||
transactions[transaction.id] = transaction;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:cw_bitcoin/encryption_file_utils.dart';
|
||||
|
@ -439,6 +440,28 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
|||
await transactionHistory.save();
|
||||
}
|
||||
|
||||
Future<void> renameWalletFiles(String newWalletName) async {
|
||||
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
|
||||
final currentWalletFile = File(currentWalletPath);
|
||||
|
||||
final currentDirPath =
|
||||
await pathForWalletDir(name: walletInfo.name, type: type);
|
||||
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
|
||||
|
||||
// Copies current wallet files into new wallet name's dir and files
|
||||
if (currentWalletFile.existsSync()) {
|
||||
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
|
||||
await currentWalletFile.copy(newWalletPath);
|
||||
}
|
||||
if (currentTransactionsFile.existsSync()) {
|
||||
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
|
||||
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
|
||||
}
|
||||
|
||||
// Delete old name's dir and files
|
||||
await Directory(currentDirPath).delete(recursive: true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
_password = password;
|
||||
|
|
|
@ -57,9 +57,32 @@ class LitecoinWalletService extends WalletService<
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> remove(String wallet) async =>
|
||||
File(await pathForWalletDir(name: wallet, type: getType()))
|
||||
.delete(recursive: true);
|
||||
Future<void> remove(String wallet) async {
|
||||
File(await pathForWalletDir(name: wallet, type: getType()))
|
||||
.delete(recursive: true);
|
||||
final walletInfo = walletInfoSource.values.firstWhereOrNull(
|
||||
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||
await walletInfoSource.delete(walletInfo.key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rename(String currentName, String password, String newName) async {
|
||||
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
|
||||
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
||||
final currentWallet = await LitecoinWalletBase.open(
|
||||
password: password,
|
||||
name: currentName,
|
||||
walletInfo: currentWalletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
|
||||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LitecoinWallet> restoreFromKeys(
|
||||
|
|
|
@ -14,6 +14,8 @@ abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> {
|
|||
|
||||
void addMany(Map<String, TransactionType> transactions);
|
||||
|
||||
void clear() => transactions.clear();
|
||||
|
||||
// bool _isUpdating;
|
||||
|
||||
// @action
|
||||
|
|
|
@ -17,4 +17,6 @@ abstract class WalletService<N extends WalletCredentials,
|
|||
Future<bool> isWalletExit(String name);
|
||||
|
||||
Future<void> remove(String wallet);
|
||||
|
||||
Future<void> rename(String name, String password, String newName);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ enum WalletType {
|
|||
litecoin,
|
||||
|
||||
@HiveField(4)
|
||||
haven
|
||||
haven,
|
||||
}
|
||||
|
||||
int serializeToInt(WalletType type) {
|
||||
|
@ -77,13 +77,13 @@ String walletTypeToString(WalletType type) {
|
|||
String walletTypeToDisplayName(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return 'Monero';
|
||||
return 'Monero (XMR)';
|
||||
case WalletType.bitcoin:
|
||||
return 'Bitcoin (Electrum)';
|
||||
return 'Bitcoin (BTC)';
|
||||
case WalletType.litecoin:
|
||||
return 'Litecoin (Electrum)';
|
||||
return 'Litecoin (LTC)';
|
||||
case WalletType.haven:
|
||||
return 'Haven';
|
||||
return 'Haven (XHV)';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_haven/haven_transaction_creation_credentials.dart';
|
||||
import 'package:cw_core/monero_amount_format.dart';
|
||||
|
@ -251,6 +253,29 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
|
|||
await haven_wallet.store();
|
||||
}
|
||||
|
||||
Future<void> renameWalletFiles(String newWalletName) async {
|
||||
final currentWalletPath = await pathForWallet(name: name, type: type);
|
||||
final currentCacheFile = File(currentWalletPath);
|
||||
final currentKeysFile = File('$currentWalletPath.keys');
|
||||
final currentAddressListFile = File('$currentWalletPath.address.txt');
|
||||
|
||||
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
|
||||
|
||||
// Copies current wallet files into new wallet name's dir and files
|
||||
if (currentCacheFile.existsSync()) {
|
||||
await currentCacheFile.copy(newWalletPath);
|
||||
}
|
||||
if (currentKeysFile.existsSync()) {
|
||||
await currentKeysFile.copy('$newWalletPath.keys');
|
||||
}
|
||||
if (currentAddressListFile.existsSync()) {
|
||||
await currentAddressListFile.copy('$newWalletPath.address.txt');
|
||||
}
|
||||
|
||||
// Delete old name's dir and files
|
||||
await Directory(currentWalletPath).delete(recursive: true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
haven_wallet.setPasswordSync(password);
|
||||
|
|
|
@ -149,6 +149,26 @@ class HavenWalletService extends WalletService<
|
|||
if (isExist) {
|
||||
await file.delete(recursive: true);
|
||||
}
|
||||
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
|
||||
await walletInfoSource.delete(walletInfo.key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rename(
|
||||
String currentName, String password, String newName) async {
|
||||
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
||||
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||
final currentWallet = HavenWallet(walletInfo: currentWalletInfo);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
|
||||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -24,4 +24,5 @@ abstract class MoneroTransactionHistoryBase
|
|||
@override
|
||||
void addMany(Map<String, MoneroTransactionInfo> transactions) =>
|
||||
this.transactions.addAll(transactions);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/monero_amount_format.dart';
|
||||
import 'package:cw_monero/monero_transaction_creation_exception.dart';
|
||||
|
@ -6,7 +8,6 @@ import 'package:cw_monero/monero_transaction_info.dart';
|
|||
import 'package:cw_monero/monero_wallet_addresses.dart';
|
||||
import 'package:cw_core/monero_wallet_utils.dart';
|
||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_monero/api/transaction_history.dart'
|
||||
as monero_transaction_history;
|
||||
|
@ -274,6 +275,29 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
await monero_wallet.store();
|
||||
}
|
||||
|
||||
Future<void> renameWalletFiles(String newWalletName) async {
|
||||
final currentWalletPath = await pathForWallet(name: name, type: type);
|
||||
final currentCacheFile = File(currentWalletPath);
|
||||
final currentKeysFile = File('$currentWalletPath.keys');
|
||||
final currentAddressListFile = File('$currentWalletPath.address.txt');
|
||||
|
||||
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
|
||||
|
||||
// Copies current wallet files into new wallet name's dir and files
|
||||
if (currentCacheFile.existsSync()) {
|
||||
await currentCacheFile.copy(newWalletPath);
|
||||
}
|
||||
if (currentKeysFile.existsSync()) {
|
||||
await currentKeysFile.copy('$newWalletPath.keys');
|
||||
}
|
||||
if (currentAddressListFile.existsSync()) {
|
||||
await currentAddressListFile.copy('$newWalletPath.address.txt');
|
||||
}
|
||||
|
||||
// Delete old name's dir and files
|
||||
await Directory(currentWalletPath).delete(recursive: true);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
monero_wallet.setPasswordSync(password);
|
||||
|
|
|
@ -150,6 +150,26 @@ class MoneroWalletService extends WalletService<
|
|||
if (isExist) {
|
||||
await file.delete(recursive: true);
|
||||
}
|
||||
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
|
||||
await walletInfoSource.delete(walletInfo.key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rename(
|
||||
String currentName, String password, String newName) async {
|
||||
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
||||
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||
final currentWallet = MoneroWallet(walletInfo: currentWalletInfo);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
|
||||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -64,7 +64,6 @@ class OnRamperBuyProvider {
|
|||
return Uri.https(_baseUrl, '', <String, dynamic>{
|
||||
'apiKey': _apiKey,
|
||||
'defaultCrypto': _normalizeCryptoCurrency,
|
||||
'defaultFiat': _settingsStore.fiatCurrency.title,
|
||||
'wallets': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
|
||||
'supportSell': "false",
|
||||
'supportSwap': "false",
|
||||
|
|
|
@ -21,4 +21,11 @@ class KeyService {
|
|||
|
||||
await _secureStorage.write(key: key, value: encodedPassword);
|
||||
}
|
||||
|
||||
Future<void> deleteWalletPassword({required String walletName}) async {
|
||||
final key = generateStoreKeyFor(
|
||||
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
|
||||
|
||||
await _secureStorage.delete(key: key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,43 +7,58 @@ import 'package:cw_core/wallet_type.dart';
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class WalletLoadingService {
|
||||
WalletLoadingService(
|
||||
this.sharedPreferences,
|
||||
this.keyService,
|
||||
this.walletServiceFactory);
|
||||
|
||||
final SharedPreferences sharedPreferences;
|
||||
final KeyService keyService;
|
||||
final WalletService Function(WalletType type) walletServiceFactory;
|
||||
WalletLoadingService(
|
||||
this.sharedPreferences, this.keyService, this.walletServiceFactory);
|
||||
|
||||
final SharedPreferences sharedPreferences;
|
||||
final KeyService keyService;
|
||||
final WalletService Function(WalletType type) walletServiceFactory;
|
||||
|
||||
Future<void> renameWallet(
|
||||
WalletType type, String name, String newName, {String? password}) async {
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||
|
||||
// Save the current wallet's password to the new wallet name's key
|
||||
await keyService.saveWalletPassword(
|
||||
walletName: newName, password: walletPassword);
|
||||
// Delete previous wallet name from keyService to keep only new wallet's name
|
||||
// otherwise keeps duplicate (old and new names)
|
||||
await keyService.deleteWalletPassword(walletName: name);
|
||||
|
||||
await walletService.rename(name, walletPassword, newName);
|
||||
}
|
||||
|
||||
Future<WalletBase> load(WalletType type, String name, {String? password}) async {
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||
final wallet = await walletService.openWallet(name, walletPassword);
|
||||
final wallet = await walletService.openWallet(name, walletPassword);
|
||||
|
||||
if (type == WalletType.monero) {
|
||||
await updateMoneroWalletPassword(wallet);
|
||||
}
|
||||
if (type == WalletType.monero) {
|
||||
await updateMoneroWalletPassword(wallet);
|
||||
}
|
||||
|
||||
return wallet;
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
|
||||
Future<void> updateMoneroWalletPassword(WalletBase wallet) async {
|
||||
final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name);
|
||||
var isPasswordUpdated = sharedPreferences.getBool(key) ?? false;
|
||||
Future<void> updateMoneroWalletPassword(WalletBase wallet) async {
|
||||
final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name);
|
||||
var isPasswordUpdated = sharedPreferences.getBool(key) ?? false;
|
||||
|
||||
if (isPasswordUpdated) {
|
||||
return;
|
||||
}
|
||||
if (isPasswordUpdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
final password = generateWalletPassword();
|
||||
// Save new generated password with backup key for case where
|
||||
// wallet will change password, but it will fail to update in secure storage
|
||||
final bakWalletName = '#__${wallet.name}_bak__#';
|
||||
await keyService.saveWalletPassword(walletName: bakWalletName, password: password);
|
||||
await wallet.changePassword(password);
|
||||
await keyService.saveWalletPassword(walletName: wallet.name, password: password);
|
||||
isPasswordUpdated = true;
|
||||
await sharedPreferences.setBool(key, isPasswordUpdated);
|
||||
}
|
||||
final password = generateWalletPassword();
|
||||
// Save new generated password with backup key for case where
|
||||
// wallet will change password, but it will fail to update in secure storage
|
||||
final bakWalletName = '#__${wallet.name}_bak__#';
|
||||
await keyService.saveWalletPassword(
|
||||
walletName: bakWalletName, password: password);
|
||||
await wallet.changePassword(password);
|
||||
await keyService.saveWalletPassword(
|
||||
walletName: wallet.name, password: password);
|
||||
isPasswordUpdated = true;
|
||||
await sharedPreferences.setBool(key, isPasswordUpdated);
|
||||
}
|
||||
}
|
18
lib/di.dart
18
lib/di.dart
|
@ -43,6 +43,7 @@ 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/wallet/wallet_edit_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';
|
||||
|
@ -79,6 +80,8 @@ import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart
|
|||
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_unlock_loadable_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_unlock_verifiable_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_unlock_view_model.dart';
|
||||
|
@ -582,6 +585,21 @@ Future setup({
|
|||
authService: getIt.get<AuthService>(),
|
||||
));
|
||||
|
||||
getIt.registerFactoryParam<WalletEditViewModel, WalletListViewModel, void>(
|
||||
(WalletListViewModel walletListViewModel, _) => WalletEditViewModel(
|
||||
walletListViewModel, getIt.get<WalletLoadingService>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletEditPage, List<dynamic>, void>((args, _) {
|
||||
final walletListViewModel = args.first as WalletListViewModel;
|
||||
final editingWallet = args.last as WalletListItem;
|
||||
return WalletEditPage(
|
||||
walletEditViewModel: getIt.get<WalletEditViewModel>(param1: walletListViewModel),
|
||||
authService: getIt.get<AuthService>(),
|
||||
walletNewVM: getIt.get<WalletNewVM>(param1: editingWallet.type),
|
||||
editingWallet: editingWallet);
|
||||
});
|
||||
|
||||
|
||||
getIt.registerFactory(() {
|
||||
final wallet = getIt.get<AppStore>().wallet!;
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/distribution_info.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -14,7 +18,7 @@ import 'package:cake_wallet/exchange/changenow/changenow_request.dart';
|
|||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
|
||||
class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
ChangeNowExchangeProvider()
|
||||
ChangeNowExchangeProvider({required this.settingsStore})
|
||||
: _lastUsedRateId = '',
|
||||
super(
|
||||
pairList: CryptoCurrency.all
|
||||
|
@ -25,7 +29,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
.expand((i) => i)
|
||||
.toList());
|
||||
|
||||
static final apiKey = DeviceInfo.instance.isMobile ? secrets.changeNowApiKey : secrets.changeNowApiKeyDesktop;
|
||||
static final apiKey =
|
||||
DeviceInfo.instance.isMobile ? secrets.changeNowApiKey : secrets.changeNowApiKeyDesktop;
|
||||
static const apiAuthority = 'api.changenow.io';
|
||||
static const createTradePath = '/v2/exchange';
|
||||
static const findTradeByIdPath = '/v2/exchange/by-id';
|
||||
|
@ -46,21 +51,22 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.changeNow;
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.changeNow;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
String _lastUsedRateId;
|
||||
|
||||
static String getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final normalizedFrom = normalizeCryptoCurrency(from);
|
||||
final normalizedTo = normalizeCryptoCurrency(to);
|
||||
|
@ -70,10 +76,11 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
'toCurrency': normalizedTo,
|
||||
'fromNetwork': networkFor(from),
|
||||
'toNetwork': networkFor(to),
|
||||
'flow': flow};
|
||||
'flow': flow
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, rangePath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error'] as String;
|
||||
|
@ -87,19 +94,24 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
return Limits(
|
||||
min: responseJSON['minAmount'] as double?,
|
||||
max: responseJSON['maxAmount'] as double?);
|
||||
min: responseJSON['minAmount'] as double?, max: responseJSON['maxAmount'] as double?);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as ChangeNowRequest;
|
||||
final headers = {
|
||||
apiHeaderKey: apiKey,
|
||||
'Content-Type': 'application/json'};
|
||||
final distributionPath = await DistributionInfo.instance.getDistributionPath();
|
||||
final formattedAppVersion = int.tryParse(settingsStore.appVersion.replaceAll('.', '')) ?? 0;
|
||||
final payload = {
|
||||
'app': isMoneroOnly ? 'monerocom' : 'cakewallet',
|
||||
'device': Platform.operatingSystem,
|
||||
'distribution': distributionPath,
|
||||
'version': formattedAppVersion
|
||||
};
|
||||
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final type = isFixedRateMode ? 'reverse' : 'direct';
|
||||
final body = <String, String>{
|
||||
final body = <String, dynamic>{
|
||||
'fromCurrency': normalizeCryptoCurrency(_request.from),
|
||||
'toCurrency': normalizeCryptoCurrency(_request.to),
|
||||
'fromNetwork': networkFor(_request.from),
|
||||
|
@ -109,7 +121,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
'address': _request.address,
|
||||
'flow': flow,
|
||||
'type': type,
|
||||
'refundAddress': _request.refundAddress
|
||||
'refundAddress': _request.refundAddress,
|
||||
'payload': payload,
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
|
@ -164,7 +177,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
Future<Trade> findTradeById({required String id}) async {
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final params = <String, String>{'id': id};
|
||||
final uri = Uri.https(apiAuthority,findTradeByIdPath, params);
|
||||
final uri = Uri.https(apiAuthority, findTradeByIdPath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
|
||||
if (response.statusCode == 404) {
|
||||
|
@ -175,8 +188,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['message'] as String;
|
||||
|
||||
throw TradeNotFoundException(id,
|
||||
provider: description, description: error);
|
||||
throw TradeNotFoundException(id, provider: description, description: error);
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
|
@ -234,19 +246,20 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
'fromNetwork': networkFor(from),
|
||||
'toNetwork': networkFor(to),
|
||||
'type': type,
|
||||
'flow': flow};
|
||||
'flow': flow
|
||||
};
|
||||
|
||||
if (isReverse) {
|
||||
params['toAmount'] = amount.toString();
|
||||
} else {
|
||||
params['fromAmount'] = amount.toString();
|
||||
}
|
||||
|
||||
|
||||
final uri = Uri.https(apiAuthority, estimatedAmountPath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromAmount = double.parse(responseJSON['fromAmount'].toString());
|
||||
final toAmount = double.parse(responseJSON['toAmount'].toString());
|
||||
final toAmount = double.parse(responseJSON['toAmount'].toString());
|
||||
final rateId = responseJSON['rateId'] as String? ?? '';
|
||||
|
||||
if (rateId.isNotEmpty) {
|
||||
|
@ -254,35 +267,31 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
return isReverse ? (amount / fromAmount) : (toAmount / amount);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String networkFor(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.usdt:
|
||||
return CryptoCurrency.btc.title.toLowerCase();
|
||||
default:
|
||||
return currency.tag != null
|
||||
? currency.tag!.toLowerCase()
|
||||
: currency.title.toLowerCase();
|
||||
}
|
||||
return currency.tag != null ? currency.tag!.toLowerCase() : currency.title.toLowerCase();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
switch(currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcmatic';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'maticmainnet';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
||||
String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcmatic';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'maticmainnet';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,12 +194,7 @@ class App extends StatefulWidget {
|
|||
}
|
||||
|
||||
class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||
AppState() : yatStore = getIt.get<YatStore>() {
|
||||
SystemChrome.setPreferredOrientations(
|
||||
ResponsiveLayoutUtil.instance.isIpad ?
|
||||
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight] :
|
||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
}
|
||||
AppState() : yatStore = getIt.get<YatStore>();
|
||||
|
||||
YatStore yatStore;
|
||||
StreamSubscription? stream;
|
||||
|
@ -291,7 +286,43 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
|||
locale: Locale(settingsStore.languageCode),
|
||||
onGenerateRoute: (settings) => Router.createRoute(settings),
|
||||
initialRoute: initialRoute,
|
||||
home: _Home(),
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class _Home extends StatefulWidget {
|
||||
const _Home();
|
||||
|
||||
@override
|
||||
State<_Home> createState() => _HomeState();
|
||||
}
|
||||
|
||||
class _HomeState extends State<_Home> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
if(!ResponsiveLayoutUtil.instance.isMobile){
|
||||
_setOrientation(context);
|
||||
}
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
|
||||
void _setOrientation(BuildContext context){
|
||||
final orientation = MediaQuery.of(context).orientation;
|
||||
final width = MediaQuery.of(context).size.width;
|
||||
final height = MediaQuery.of(context).size.height;
|
||||
if (orientation == Orientation.portrait && width < height) {
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||
} else if (orientation == Orientation.landscape && width > height) {
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -65,6 +66,7 @@ import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
|||
import 'package:cake_wallet/src/screens/receive/receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
||||
|
@ -275,6 +277,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<WalletListPage>());
|
||||
|
||||
case Routes.walletEdit:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<WalletEditPage>(
|
||||
param1: settings.arguments as List<dynamic>));
|
||||
|
||||
case Routes.auth:
|
||||
return MaterialPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
|
|
|
@ -11,6 +11,7 @@ class Routes {
|
|||
static const transactionDetails = '/transaction_info';
|
||||
static const receive = '/receive';
|
||||
static const newSubaddress = '/new_subaddress';
|
||||
static const walletEdit = '/walletEdit';
|
||||
static const disclaimer = '/disclaimer';
|
||||
static const readDisclaimer = '/read_disclaimer';
|
||||
static const seedLanguage = '/seed_language';
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/palette.dart';
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/nav_bar.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
enum AppBarStyle { regular, withShadow, transparent }
|
||||
|
||||
|
@ -58,7 +59,7 @@ abstract class BasePage extends StatelessWidget {
|
|||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: 'Back',
|
||||
label: S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith(
|
||||
|
|
|
@ -24,35 +24,40 @@ class ContactListPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget? trailing(BuildContext context) {
|
||||
return Container(
|
||||
width: 32.0,
|
||||
height: 32.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context)
|
||||
return MergeSemantics(
|
||||
child: Container(
|
||||
width: 32.0,
|
||||
height: 32.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.bodySmall!
|
||||
.color!),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add,
|
||||
color: Theme.of(context).primaryTextTheme!.titleLarge!.color!,
|
||||
size: 22.0),
|
||||
ButtonTheme(
|
||||
minWidth: 32.0,
|
||||
height: 32.0,
|
||||
child: TextButton(
|
||||
// FIX-ME: Style
|
||||
//shape: CircleBorder(),
|
||||
onPressed: () async {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.addressBookAddContact);
|
||||
},
|
||||
child: Offstage()),
|
||||
)
|
||||
],
|
||||
));
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Icon(Icons.add,
|
||||
color: Theme.of(context).primaryTextTheme!.titleLarge!.color!,
|
||||
size: 22.0),
|
||||
ButtonTheme(
|
||||
minWidth: 32.0,
|
||||
height: 32.0,
|
||||
child: Semantics(
|
||||
label: S.of(context).add,
|
||||
child: TextButton(
|
||||
// FIX-ME: Style
|
||||
//shape: CircleBorder(),
|
||||
onPressed: () async {
|
||||
await Navigator.of(context)
|
||||
.pushNamed(Routes.addressBookAddContact);
|
||||
},
|
||||
child: Offstage()),
|
||||
),
|
||||
)
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:cake_wallet/di.dart';
|
|||
import 'package:cake_wallet/entities/main_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -42,15 +43,30 @@ class DashboardPage extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ResponsiveLayoutUtil.instance.isMobile
|
||||
? _DashboardPageView(
|
||||
return Scaffold(body: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (DeviceInfo.instance.isDesktop) {
|
||||
if (constraints.maxWidth > ResponsiveLayoutUtil.kDesktopMaxDashBoardWidthConstraint) {
|
||||
return getIt.get<DesktopSidebarWrapper>();
|
||||
} else {
|
||||
return _DashboardPageView(
|
||||
balancePage: balancePage,
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
addressListViewModel: addressListViewModel,
|
||||
)
|
||||
: getIt.get<DesktopSidebarWrapper>(),
|
||||
);
|
||||
);
|
||||
}
|
||||
} else if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) {
|
||||
return _DashboardPageView(
|
||||
balancePage: balancePage,
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
addressListViewModel: addressListViewModel,
|
||||
);
|
||||
} else {
|
||||
return getIt.get<DesktopSidebarWrapper>();
|
||||
}
|
||||
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +127,8 @@ class _DashboardPageView extends BasePage {
|
|||
//splashColor: Colors.transparent,
|
||||
//padding: EdgeInsets.all(0),
|
||||
onPressed: () => onOpenEndDrawer(),
|
||||
child: Semantics(label: 'Menu', child: menuButton)));
|
||||
child: Semantics(
|
||||
label: S.of(context).wallet_menu, child: menuButton)));
|
||||
}
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
@ -248,17 +265,17 @@ class _DashboardPageView extends BasePage {
|
|||
}
|
||||
if (dashboardViewModel.shouldShowMarketPlaceInDashboard) {
|
||||
pages.add(Semantics(
|
||||
label: 'Marketplace Page',
|
||||
label: S.of(context).market_place,
|
||||
child: MarketPlacePage(
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
pages.add(Semantics(label: 'Balance Page', child: balancePage));
|
||||
pages.add(Semantics(label: S.of(context).balance_page, child: balancePage));
|
||||
pages.add(Semantics(
|
||||
label: 'Transactions Page',
|
||||
label: S.of(context).settings_transactions,
|
||||
child: TransactionsPage(dashboardViewModel: dashboardViewModel)));
|
||||
_isEffectsInstalled = true;
|
||||
|
||||
|
|
|
@ -14,72 +14,75 @@ class DesktopDashboardActions extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
DesktopActionButton(
|
||||
title: MainActions.exchangeAction.name(context),
|
||||
image: MainActions.exchangeAction.image,
|
||||
canShow: MainActions.exchangeAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.exchangeAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.exchangeAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.receiveAction.name(context),
|
||||
image: MainActions.receiveAction.image,
|
||||
canShow: MainActions.receiveAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.receiveAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async =>
|
||||
await MainActions.receiveAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.sendAction.name(context),
|
||||
image: MainActions.sendAction.image,
|
||||
canShow: MainActions.sendAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.sendAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.sendAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.buyAction.name(context),
|
||||
image: MainActions.buyAction.image,
|
||||
canShow: MainActions.buyAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.buyAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.buyAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.sellAction.name(context),
|
||||
image: MainActions.sellAction.image,
|
||||
canShow: MainActions.sellAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.sellAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.sellAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: MarketPlacePage(
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||
return Container(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
DesktopActionButton(
|
||||
title: MainActions.exchangeAction.name(context),
|
||||
image: MainActions.exchangeAction.image,
|
||||
canShow: MainActions.exchangeAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.exchangeAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.exchangeAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.receiveAction.name(context),
|
||||
image: MainActions.receiveAction.image,
|
||||
canShow: MainActions.receiveAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.receiveAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async =>
|
||||
await MainActions.receiveAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.sendAction.name(context),
|
||||
image: MainActions.sendAction.image,
|
||||
canShow: MainActions.sendAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.sendAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.sendAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.buyAction.name(context),
|
||||
image: MainActions.buyAction.image,
|
||||
canShow: MainActions.buyAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.buyAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.buyAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: DesktopActionButton(
|
||||
title: MainActions.sellAction.name(context),
|
||||
image: MainActions.sellAction.image,
|
||||
canShow: MainActions.sellAction.canShow?.call(dashboardViewModel),
|
||||
isEnabled: MainActions.sellAction.isEnabled?.call(dashboardViewModel),
|
||||
onTap: () async => await MainActions.sellAction.onTap(context, dashboardViewModel),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: MarketPlacePage(
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,27 +77,21 @@ class DesktopSidebarWrapper extends BasePage {
|
|||
SideMenuItem(
|
||||
imagePath: 'assets/images/wallet_outline.png',
|
||||
isSelected: desktopSidebarViewModel.currentPage == SidebarItem.dashboard,
|
||||
onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.dashboard),
|
||||
onTap: () {
|
||||
desktopSidebarViewModel.onPageChange(SidebarItem.dashboard);
|
||||
desktopNavigatorKey.currentState
|
||||
?.pushNamedAndRemoveUntil(Routes.desktop_actions, (route) => false);
|
||||
},
|
||||
),
|
||||
SideMenuItem(
|
||||
onTap: () {
|
||||
String? currentPath;
|
||||
|
||||
desktopNavigatorKey.currentState?.popUntil((route) {
|
||||
currentPath = route.settings.name;
|
||||
return true;
|
||||
});
|
||||
|
||||
switch (currentPath) {
|
||||
case Routes.transactionsPage:
|
||||
desktopSidebarViewModel.resetSidebar();
|
||||
break;
|
||||
default:
|
||||
desktopSidebarViewModel.resetSidebar();
|
||||
Future.delayed(Duration(milliseconds: 10), () {
|
||||
desktopSidebarViewModel.onPageChange(SidebarItem.transactions);
|
||||
desktopNavigatorKey.currentState?.pushNamed(Routes.transactionsPage);
|
||||
});
|
||||
if (desktopSidebarViewModel.currentPage == SidebarItem.transactions) {
|
||||
desktopNavigatorKey.currentState
|
||||
?.pushNamedAndRemoveUntil(Routes.desktop_actions, (route) => false);
|
||||
desktopSidebarViewModel.resetSidebar();
|
||||
} else {
|
||||
desktopSidebarViewModel.onPageChange(SidebarItem.transactions);
|
||||
desktopNavigatorKey.currentState?.pushNamed(Routes.transactionsPage);
|
||||
}
|
||||
},
|
||||
isSelected: desktopSidebarViewModel.currentPage == SidebarItem.transactions,
|
||||
|
@ -156,20 +150,11 @@ class DesktopSidebarWrapper extends BasePage {
|
|||
|
||||
void _setEffects() async {
|
||||
reaction<SidebarItem>((_) => desktopSidebarViewModel.currentPage, (page) {
|
||||
String? currentPath;
|
||||
|
||||
desktopNavigatorKey.currentState?.popUntil((route) {
|
||||
currentPath = route.settings.name;
|
||||
return true;
|
||||
});
|
||||
if (page == SidebarItem.transactions) {
|
||||
if (page == SidebarItem.dashboard) {
|
||||
pageController.jumpToPage(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPath == Routes.transactionsPage) {
|
||||
Navigator.of(desktopNavigatorKey.currentContext!).pop();
|
||||
}
|
||||
pageController.jumpToPage(page.index);
|
||||
pageController.jumpToPage(page.index - 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,7 +82,9 @@ class AddressPage extends BasePage {
|
|||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: !isMobileView ? 'Close' : 'Back',
|
||||
label: !isMobileView
|
||||
? S.of(context).close
|
||||
: S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith(
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -14,9 +17,6 @@ class BalancePage extends StatelessWidget {
|
|||
final DashboardViewModel dashboardViewModel;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
Color get backgroundLightColor =>
|
||||
settingsStore.currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
|
@ -44,7 +44,7 @@ class BalancePage extends StatelessWidget {
|
|||
textAlign: TextAlign.center);
|
||||
})),
|
||||
Observer(builder: (_) {
|
||||
if (dashboardViewModel.balanceViewModel.isShowCard) {
|
||||
if (dashboardViewModel.balanceViewModel.isShowCard && FeatureFlag.isCakePayEnabled) {
|
||||
return IntroducingCard(
|
||||
title: S.of(context).introducing_cake_pay,
|
||||
subTitle: S.of(context).cake_pay_learn_more,
|
||||
|
@ -104,63 +104,86 @@ class BalancePage extends StatelessWidget {
|
|||
color: Theme.of(context).textTheme!.titleLarge!.backgroundColor!),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 16, left: 24, right: 24, bottom: 24),
|
||||
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text('${availableBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displaySmall!
|
||||
.backgroundColor!,
|
||||
height: 1)),
|
||||
SizedBox(height: 5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
||||
Expanded(
|
||||
child: AutoSizeText(availableBalance,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => _showBalanceDescription(context),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text('${availableBalanceLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displaySmall!
|
||||
.backgroundColor!,
|
||||
height: 1)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displaySmall!
|
||||
.backgroundColor!),
|
||||
)
|
||||
],
|
||||
),SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
AutoSizeText(availableBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
height: 1),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.start),
|
||||
SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Text('${availableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
height: 1)),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(currency,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontSize: 28,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w900,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
height: 1),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.start),
|
||||
),
|
||||
Text(currency,
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
height: 1)),
|
||||
]),
|
||||
SizedBox(
|
||||
height: 4,
|
||||
height: 1)),
|
||||
],
|
||||
),
|
||||
Text('${availableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
height: 1)),
|
||||
SizedBox(height: 26),
|
||||
if (frozenBalance.isNotEmpty)
|
||||
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
|
@ -247,4 +270,10 @@ class BalancePage extends StatelessWidget {
|
|||
])),
|
||||
);
|
||||
}
|
||||
|
||||
void _showBalanceDescription(BuildContext context) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => InformationPage(information: S.current.available_balance_description));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/market_place_item.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||
|
@ -51,15 +51,17 @@ class MarketPlacePage extends StatelessWidget {
|
|||
child: ListView(
|
||||
controller: _scrollController,
|
||||
children: <Widget>[
|
||||
if (!SettingsStoreBase.walletPasswordDirectInput)
|
||||
...[SizedBox(height: 20),
|
||||
MarketPlaceItem(
|
||||
onTap: () => _navigatorToGiftCardsPage(context),
|
||||
title: S.of(context).cake_pay_title,
|
||||
subTitle: S.of(context).cake_pay_subtitle,
|
||||
)],
|
||||
SizedBox(height: 20),
|
||||
MarketPlaceItem(
|
||||
DashBoardRoundedCardWidget(
|
||||
onTap: () => launchUrl(
|
||||
Uri.parse("https://cakelabs.com/news/cake-pay-mobile-to-shut-down/"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
title: S.of(context).cake_pay_title,
|
||||
subTitle: S.of(context).cake_pay_subtitle,
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
DashBoardRoundedCardWidget(
|
||||
onTap: () => launchUrl(
|
||||
Uri.https("buy.cakepay.com"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
|
@ -77,6 +79,7 @@ class MarketPlacePage extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
// TODO: Remove ionia flow/files if we will discard it
|
||||
void _navigatorToGiftCardsPage(BuildContext context) {
|
||||
final walletType = dashboardViewModel.type;
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ class PresentReceiveOptionPicker extends StatelessWidget {
|
|||
Container(
|
||||
margin: EdgeInsets.only(bottom: 40),
|
||||
child: InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
onTap: () => Navigator.pop(popUpContext),
|
||||
child: CircleAvatar(
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/anonpay_transaction_row.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/order_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -37,6 +39,23 @@ class TransactionsPage extends StatelessWidget {
|
|||
padding: EdgeInsets.only(top: 24, bottom: 24),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Observer(builder: (_) {
|
||||
final status = dashboardViewModel.status;
|
||||
if (status is SyncingSyncStatus) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.webViewPage,
|
||||
arguments: ['', Uri.parse('https://guides.cakewallet.com/docs/bugs-service-status/why_are_my_funds_not_appearing/')]),
|
||||
title: S.of(context).syncing_wallet_alert_title,
|
||||
subTitle: S.of(context).syncing_wallet_alert_content,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
}),
|
||||
HeaderRow(dashboardViewModel: dashboardViewModel),
|
||||
Expanded(child: Observer(builder: (_) {
|
||||
final items = dashboardViewModel.items;
|
||||
|
|
|
@ -126,7 +126,9 @@ class ExchangePage extends BasePage {
|
|||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: !isMobileView ? 'Close' : 'Back',
|
||||
label: !isMobileView
|
||||
? S.of(context).close
|
||||
: S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith(
|
||||
|
|
|
@ -359,7 +359,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
Navigator.of(popupContext).pop();
|
||||
RequestReviewHandler.requestReview();
|
||||
},
|
||||
text: S.of(popupContext).send_got_it,
|
||||
text: S.of(popupContext).got_it,
|
||||
color: Theme.of(popupContext)
|
||||
.accentTextTheme!
|
||||
.bodyLarge!
|
||||
|
|
|
@ -30,6 +30,7 @@ class InformationPage extends StatelessWidget {
|
|||
padding: EdgeInsets.fromLTRB(24, 28, 24, 24),
|
||||
child: Text(
|
||||
information,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
|
@ -43,7 +44,7 @@ class InformationPage extends StatelessWidget {
|
|||
padding: EdgeInsets.fromLTRB(10, 0, 10, 10),
|
||||
child: PrimaryButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
text: S.of(context).send_got_it,
|
||||
text: S.of(context).got_it,
|
||||
color: Theme.of(context).accentTextTheme!.bodySmall!.backgroundColor!,
|
||||
textColor: Theme.of(context).primaryTextTheme!.titleLarge!.color!
|
||||
),
|
||||
|
|
|
@ -283,7 +283,7 @@ class IoniaBuyGiftCardDetailPage extends BasePage {
|
|||
})
|
||||
.expand((e) => e)
|
||||
.toList()),
|
||||
actionTitle: S.current.send_got_it,
|
||||
actionTitle: S.current.got_it,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ class IoniaDebitCardPage extends BasePage {
|
|||
onPressed: () => activate
|
||||
? Navigator.pushNamed(context, Routes.ioniaActivateDebitCardPage)
|
||||
: Navigator.pop(context),
|
||||
text: S.of(context).send_got_it,
|
||||
text: S.of(context).got_it,
|
||||
color: Color.fromRGBO(233, 242, 252, 1),
|
||||
textColor:
|
||||
Theme.of(context).textTheme!.displaySmall!.color!,
|
||||
|
|
|
@ -214,7 +214,7 @@ class IoniaGiftCardDetailPage extends BasePage {
|
|||
})
|
||||
.expand((e) => e)
|
||||
.toList()),
|
||||
actionTitle: S.of(context).send_got_it,
|
||||
actionTitle: S.of(context).got_it,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -66,40 +66,6 @@ class IoniaManageCardsPage extends BasePage {
|
|||
@override
|
||||
Widget get endDrawer => CardMenu();
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
size: 16,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
height: 37,
|
||||
width: 37,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: TextButton(
|
||||
// FIX-ME: Style
|
||||
//highlightColor: Colors.transparent,
|
||||
//splashColor: Colors.transparent,
|
||||
//padding: EdgeInsets.all(0),
|
||||
onPressed: (){
|
||||
if (searchFocusNode.hasFocus) {
|
||||
searchFocusNode.unfocus();
|
||||
return;
|
||||
}
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: _backButton),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
return Text(
|
||||
|
@ -123,26 +89,28 @@ class IoniaManageCardsPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final filterButton = InkWell(
|
||||
onTap: () async {
|
||||
await showCategoryFilter(context);
|
||||
_cardsListViewModel.getMerchants();
|
||||
},
|
||||
child: Container(
|
||||
width: 32,
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).textTheme!.titleLarge!.backgroundColor!,
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
final filterButton = Semantics(
|
||||
label: S.of(context).filter_by,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
await showCategoryFilter(context);
|
||||
_cardsListViewModel.getMerchants();
|
||||
},
|
||||
child: Container(
|
||||
width: 32,
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).textTheme!.titleLarge!.backgroundColor!,
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Image.asset(
|
||||
'assets/images/filter.png',
|
||||
color: Theme.of(context).textTheme!.bodySmall!.decorationColor!,
|
||||
),
|
||||
)
|
||||
child: Image.asset(
|
||||
'assets/images/filter.png',
|
||||
color: Theme.of(context).textTheme!.bodySmall!.decorationColor!,
|
||||
),
|
||||
)),
|
||||
);
|
||||
|
||||
return Padding(
|
||||
|
@ -281,11 +249,13 @@ class _SearchWidget extends StatelessWidget {
|
|||
final FocusNode focusNode;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final searchIcon = Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Image.asset(
|
||||
'assets/images/mini_search_icon.png',
|
||||
color: Theme.of(context).textTheme!.bodySmall!.decorationColor!,
|
||||
final searchIcon = ExcludeSemantics(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: Image.asset(
|
||||
'assets/images/mini_search_icon.png',
|
||||
color: Theme.of(context).textTheme!.bodySmall!.decorationColor!,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -335,18 +305,22 @@ class _TrailingIcon extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: BoxConstraints(),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: onPressed,
|
||||
icon: Image.asset(
|
||||
asset,
|
||||
color: Theme.of(context).accentTextTheme!.displayMedium!.backgroundColor!,
|
||||
return Semantics(
|
||||
label: S.of(context).profile,
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: BoxConstraints(),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: onPressed,
|
||||
icon: Image.asset(
|
||||
asset,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme!.displayMedium!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,176 +1,94 @@
|
|||
import 'package:cake_wallet/src/widgets/picker_inner_wrapper_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/monero_accounts/widgets/account_tile.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
|
||||
class MoneroAccountListPage extends StatelessWidget {
|
||||
MoneroAccountListPage({required this.accountListViewModel})
|
||||
: backgroundHeight = 194,
|
||||
thumbHeight = 72,
|
||||
isAlwaysShowScrollThumb = false,
|
||||
controller = ScrollController() {
|
||||
controller.addListener(() {
|
||||
final scrollOffsetFromTop = controller.hasClients
|
||||
? (controller.offset / controller.position.maxScrollExtent * (backgroundHeight - thumbHeight))
|
||||
: 0.0;
|
||||
accountListViewModel.setScrollOffsetFromTop(scrollOffsetFromTop);
|
||||
});
|
||||
}
|
||||
MoneroAccountListPage({required this.accountListViewModel});
|
||||
|
||||
final MoneroAccountListViewModel accountListViewModel;
|
||||
|
||||
ScrollController controller;
|
||||
double backgroundHeight;
|
||||
double thumbHeight;
|
||||
bool isAlwaysShowScrollThumb;
|
||||
final ScrollController controller = ScrollController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertBackground(
|
||||
child: Column(
|
||||
double itemHeight = 80;
|
||||
double buttonHeight = 62;
|
||||
|
||||
return Observer(builder: (_) {
|
||||
final accounts = accountListViewModel.accounts;
|
||||
|
||||
return PickerInnerWrapperWidget(
|
||||
title: S.of(context).choose_account,
|
||||
itemsHeight: (itemHeight * accounts.length) + buttonHeight,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
child: Scrollbar(
|
||||
controller: controller,
|
||||
child: ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
separatorBuilder: (context, index) => const SectionDivider(),
|
||||
itemCount: accounts.length,
|
||||
itemBuilder: (context, index) {
|
||||
final account = accounts[index];
|
||||
|
||||
return AccountTile(
|
||||
isCurrent: account.isSelected,
|
||||
accountName: account.label,
|
||||
accountBalance: account.balance ?? '0.00',
|
||||
currency: accountListViewModel.currency.toString(),
|
||||
onTap: () {
|
||||
if (account.isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
accountListViewModel.select(account);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
onEdit: () async => await Navigator.of(context)
|
||||
.pushNamed(Routes.accountCreation, arguments: account));
|
||||
},
|
||||
),
|
||||
)),
|
||||
GestureDetector(
|
||||
onTap: () async =>
|
||||
await Navigator.of(context).pushNamed(Routes.accountCreation),
|
||||
child: Container(
|
||||
height: buttonHeight,
|
||||
color: Theme.of(context).cardColor,
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(context).choose_account,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
height: 296,
|
||||
color: Theme.of(context).textTheme!.displayLarge!.decorationColor!,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
final accounts = accountListViewModel.accounts;
|
||||
isAlwaysShowScrollThumb = accounts == null
|
||||
? false
|
||||
: accounts.length > 3;
|
||||
|
||||
return Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
controller: controller,
|
||||
separatorBuilder: (context, index) =>
|
||||
const SectionDivider(),
|
||||
itemCount: accounts.length ?? 0,
|
||||
itemBuilder: (context, index) {
|
||||
final account = accounts[index];
|
||||
|
||||
return AccountTile(
|
||||
isCurrent: account.isSelected,
|
||||
accountName: account.label,
|
||||
accountBalance: account.balance ?? '0.00',
|
||||
currency: accountListViewModel
|
||||
.currency.toString(),
|
||||
onTap: () {
|
||||
if (account.isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
accountListViewModel
|
||||
.select(account);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
onEdit: () async =>
|
||||
await Navigator.of(context)
|
||||
.pushNamed(
|
||||
Routes.accountCreation,
|
||||
arguments: account));
|
||||
},
|
||||
),
|
||||
isAlwaysShowScrollThumb
|
||||
? CakeScrollbar(
|
||||
backgroundHeight: backgroundHeight,
|
||||
thumbHeight: thumbHeight,
|
||||
fromTop: accountListViewModel
|
||||
.scrollOffsetFromTop
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
);
|
||||
}
|
||||
)
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async => await Navigator.of(context)
|
||||
.pushNamed(Routes.accountCreation),
|
||||
child: Container(
|
||||
height: 62,
|
||||
color: Theme.of(context).cardColor,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 5),
|
||||
child: Text(
|
||||
S.of(context).create_new_account,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(left: 5),
|
||||
child: Text(
|
||||
S.of(context).create_new_account,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Colors.white,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
|
||||
AlertCloseButton()
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AccountTile extends StatelessWidget {
|
||||
AccountTile({
|
||||
required this.isCurrent,
|
||||
required this.accountName,
|
||||
this.accountBalance,
|
||||
required this.currency,
|
||||
required this.onTap,
|
||||
required this.onEdit
|
||||
});
|
||||
AccountTile(
|
||||
{required this.isCurrent,
|
||||
required this.accountName,
|
||||
this.accountBalance,
|
||||
required this.currency,
|
||||
required this.onTap,
|
||||
required this.onEdit});
|
||||
|
||||
final bool isCurrent;
|
||||
final String accountName;
|
||||
|
@ -32,11 +31,13 @@ class AccountTile extends StatelessWidget {
|
|||
height: 77,
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
color: color,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
alignment: WrapAlignment.spaceBetween,
|
||||
runAlignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
Container(
|
||||
child: Text(
|
||||
accountName,
|
||||
style: TextStyle(
|
||||
|
@ -49,19 +50,19 @@ class AccountTile extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
if (accountBalance != null)
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${accountBalance.toString()} $currency',
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).textTheme!.headlineMedium!.color!,
|
||||
decoration: TextDecoration.none,
|
||||
Container(
|
||||
child: Text(
|
||||
'${accountBalance.toString()} $currency',
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).textTheme!.headlineMedium!.color!,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -80,4 +81,4 @@ class AccountTile extends StatelessWidget {
|
|||
// onTap: () => onEdit?.call())
|
||||
// ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,19 +118,21 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
|||
textColor: Colors.white,
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.15),
|
||||
child: Text(
|
||||
S.of(context).settings_can_be_changed_later,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
LayoutBuilder(
|
||||
builder: (_, constraints) => SizedBox(
|
||||
width: constraints.maxWidth * 0.8,
|
||||
child: Text(
|
||||
S.of(context).settings_can_be_changed_later,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -149,7 +149,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
width: 1.0),
|
||||
),
|
||||
suffixIcon: Semantics(
|
||||
label: 'Generate Name',
|
||||
label: S.of(context).generate_name,
|
||||
child: IconButton(
|
||||
onPressed: () async {
|
||||
final rName = await generateName();
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.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/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/search_bar_widget.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/wallet_types.g.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NewWalletTypePage extends BasePage {
|
||||
NewWalletTypePage({required this.onTypeSelected});
|
||||
|
@ -40,92 +41,82 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
|
||||
static const aspectRatioImage = 1.22;
|
||||
|
||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||
final walletTypeImage = Image.asset('assets/images/wallet_type.png');
|
||||
final walletTypeLightImage = Image.asset('assets/images/wallet_type_light.png');
|
||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||
final TextEditingController searchController = TextEditingController();
|
||||
|
||||
WalletType? selected;
|
||||
List<WalletType> types;
|
||||
List<WalletType> filteredTypes = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
types = availableWalletTypes;
|
||||
types = filteredTypes = availableWalletTypes;
|
||||
super.initState();
|
||||
|
||||
searchController.addListener(() {
|
||||
setState(() {
|
||||
filteredTypes = List.from(types.where((type) => walletTypeToDisplayName(type)
|
||||
.toLowerCase()
|
||||
.contains(searchController.text.toLowerCase())));
|
||||
return;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
content: Center(
|
||||
return Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 48),
|
||||
child: Text(
|
||||
S.of(context).choose_wallet_currency,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.titleLarge!
|
||||
.color!),
|
||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 48),
|
||||
child: Text(
|
||||
S.of(context).choose_wallet_currency,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme!.titleLarge!.color!),
|
||||
),
|
||||
),
|
||||
),
|
||||
...types.map((type) => Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: SelectButton(
|
||||
image: _iconFor(type),
|
||||
text: walletTypeToDisplayName(type),
|
||||
isSelected: selected == type,
|
||||
onTap: () => setState(() => selected = type)),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: PrimaryButton(
|
||||
onPressed: () => onTypeSelected(),
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.bodyLarge!
|
||||
.color!,
|
||||
textColor: Colors.white,
|
||||
isDisabled: selected == null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Image _iconFor(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return moneroIcon;
|
||||
case WalletType.bitcoin:
|
||||
return bitcoinIcon;
|
||||
case WalletType.litecoin:
|
||||
return litecoinIcon;
|
||||
case WalletType.haven:
|
||||
return havenIcon;
|
||||
default:
|
||||
throw Exception(
|
||||
'_iconFor: Incorrect Wallet Type. Cannot find icon for Wallet Type: ${type.toString()}');
|
||||
}
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 12),
|
||||
child: SearchBarWidget(searchController: searchController, borderRadius: 24),
|
||||
),
|
||||
Expanded(
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
content: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
...filteredTypes.map((type) => Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: SelectButton(
|
||||
image: Image.asset(
|
||||
walletTypeToCryptoCurrency(type).iconPath ?? '',
|
||||
height: 24,
|
||||
width: 24),
|
||||
text: walletTypeToDisplayName(type),
|
||||
showTrailingIcon: false,
|
||||
height: 54,
|
||||
isSelected: selected == type,
|
||||
onTap: () => setState(() => selected = type)),
|
||||
))
|
||||
],
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: PrimaryButton(
|
||||
onPressed: () => onTypeSelected(),
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
|
||||
textColor: Colors.white,
|
||||
isDisabled: selected == null,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)));
|
||||
}
|
||||
|
||||
Future<void> onTypeSelected() async {
|
||||
|
|
|
@ -6,12 +6,16 @@ class SelectButton extends StatelessWidget {
|
|||
required this.onTap,
|
||||
this.image,
|
||||
this.isSelected = false,
|
||||
this.showTrailingIcon = true,
|
||||
this.height = 60,
|
||||
});
|
||||
|
||||
final Image? image;
|
||||
final String text;
|
||||
final bool isSelected;
|
||||
final VoidCallback onTap;
|
||||
final bool showTrailingIcon;
|
||||
final double height;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -44,7 +48,7 @@ class SelectButton extends StatelessWidget {
|
|||
onTap: onTap,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 60,
|
||||
height: height,
|
||||
padding: EdgeInsets.only(left: 30, right: 30),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
|
@ -76,7 +80,7 @@ class SelectButton extends StatelessWidget {
|
|||
)
|
||||
],
|
||||
),
|
||||
selectArrowImage
|
||||
if (showTrailingIcon) selectArrowImage
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -115,23 +117,42 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle:
|
||||
S.of(context).remove_node,
|
||||
alertContent: S
|
||||
.of(context)
|
||||
.remove_node_message,
|
||||
rightButtonText:
|
||||
S.of(context).remove,
|
||||
leftButtonText:
|
||||
S.of(context).cancel,
|
||||
actionRightButton: () =>
|
||||
Navigator.pop(context, true),
|
||||
actionLeftButton: () =>
|
||||
Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
await nodeCreateOrEditViewModel.connect();
|
||||
if (confirmed) {
|
||||
await editingNode!.delete();
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
isLoading: nodeCreateOrEditViewModel
|
||||
.connectionState is IsExecutingState,
|
||||
text: S.of(context).node_test,
|
||||
isDisabled: !nodeCreateOrEditViewModel.isReady,
|
||||
color: Colors.orange,
|
||||
text: S.of(context).delete,
|
||||
isDisabled: !nodeCreateOrEditViewModel.isReady ||
|
||||
(isSelected ?? false),
|
||||
color: Palette.red,
|
||||
textColor: Colors.white),
|
||||
)),
|
||||
Flexible(
|
||||
|
|
|
@ -9,8 +9,8 @@ class NodeIndicator extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 8.0,
|
||||
height: 8.0,
|
||||
width: 12.0,
|
||||
height: 12.0,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle, color: isLive ? Palette.green : Palette.red),
|
||||
);
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class NodeListRow extends StandardListRow {
|
||||
NodeListRow(
|
||||
{required String title,
|
||||
required this.node,
|
||||
required void Function(BuildContext context) onTap,
|
||||
required bool isSelected,
|
||||
required this.isAlive})
|
||||
required bool isSelected})
|
||||
: super(title: title, onTap: onTap, isSelected: isSelected);
|
||||
|
||||
final Future<bool> isAlive;
|
||||
final Node node;
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) {
|
||||
Widget buildLeading(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: isAlive,
|
||||
future: node.requestNode(),
|
||||
builder: (context, snapshot) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.done:
|
||||
|
@ -25,6 +27,24 @@ class NodeListRow extends StandardListRow {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.newNode,
|
||||
arguments: {'editingNode': node, 'isSelected': isSelected}),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineMedium!
|
||||
.decorationColor!),
|
||||
child: Icon(Icons.edit,
|
||||
size: 14,
|
||||
color: Theme.of(context).textTheme.headlineMedium!.color!)));
|
||||
}
|
||||
}
|
||||
|
||||
class NodeHeaderListRow extends StandardListRow {
|
||||
|
|
|
@ -226,7 +226,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
child: Container(
|
||||
margin: EdgeInsets.only(left: marginLeft, right: marginRight),
|
||||
child: Semantics(
|
||||
label: 'Delete',
|
||||
label: S.of(context).delete,
|
||||
button: true,
|
||||
onTap: () => _pop(),
|
||||
child: TextButton(
|
||||
|
|
|
@ -8,7 +8,6 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option
|
|||
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
|
@ -54,9 +53,7 @@ class AnonPayInvoicePage extends BasePage {
|
|||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
void onClose(BuildContext context) {
|
||||
Navigator.popUntil(context, ModalRoute.withName(Routes.dashboard));
|
||||
}
|
||||
void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) =>
|
||||
|
|
|
@ -32,28 +32,7 @@ class AnonPayReceivePage extends BasePage {
|
|||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.backgroundColor!,
|
||||
size: 16,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
height: 37,
|
||||
width: 37,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: TextButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false),
|
||||
child: _backButton),
|
||||
),
|
||||
);
|
||||
}
|
||||
void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
|
|
|
@ -87,7 +87,7 @@ class ReceivePage extends BasePage {
|
|||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: Semantics(
|
||||
label: 'Share',
|
||||
label: S.of(context).share,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: BoxConstraints(),
|
||||
|
|
|
@ -71,7 +71,7 @@ class AddressCell extends StatelessWidget {
|
|||
),
|
||||
));
|
||||
return Semantics(
|
||||
label: 'Slidable',
|
||||
label: S.of(context).slidable,
|
||||
selected: isCurrent,
|
||||
enabled: !isCurrent,
|
||||
child: Slidable(
|
||||
|
|
|
@ -2,7 +2,6 @@ import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
|||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
|
@ -37,46 +36,33 @@ class PreSeedPage extends BasePage {
|
|||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.all(24),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: FittedBox(child: image, fit: BoxFit.contain))),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 70, left: 16, right: 16),
|
||||
child: Text(
|
||||
S
|
||||
.of(context)
|
||||
.pre_seed_description(wordsCount.toString()),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.bodySmall!
|
||||
.color!),
|
||||
),
|
||||
),
|
||||
PrimaryButton(
|
||||
onPressed: () => Navigator.of(context)
|
||||
.popAndPushNamed(Routes.seed, arguments: true),
|
||||
text: S.of(context).pre_seed_button_text,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.bodyLarge!
|
||||
.color!,
|
||||
textColor: Colors.white)
|
||||
],
|
||||
))
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.3
|
||||
),
|
||||
child: AspectRatio(aspectRatio: 1, child: image),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: Text(
|
||||
S.of(context).pre_seed_description(wordsCount.toString()),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.bodySmall!.color!),
|
||||
),
|
||||
),
|
||||
PrimaryButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).popAndPushNamed(Routes.seed, arguments: true),
|
||||
text: S.of(context).pre_seed_button_text,
|
||||
color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
|
||||
textColor: Colors.white)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -52,8 +52,7 @@ class WalletSeedPage extends BasePage {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget? leading(BuildContext context) =>
|
||||
isNewWalletCreated ? null: super.leading(context);
|
||||
Widget? leading(BuildContext context) => isNewWalletCreated ? null : super.leading(context);
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
|
@ -67,16 +66,11 @@ class WalletSeedPage extends BasePage {
|
|||
margin: EdgeInsets.only(left: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.bodySmall!
|
||||
.color!),
|
||||
color: Theme.of(context).accentTextTheme.bodySmall!.color!),
|
||||
child: Text(
|
||||
S.of(context).seed_language_next,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Palette.blueCraiola),
|
||||
fontSize: 14, fontWeight: FontWeight.w600, color: Palette.blueCraiola),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -87,121 +81,99 @@ class WalletSeedPage extends BasePage {
|
|||
Widget body(BuildContext context) {
|
||||
final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight;
|
||||
|
||||
return WillPopScope(onWillPop: () async => false, child: Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
alignment: Alignment.center,
|
||||
child: ConstrainedBox(
|
||||
constraints:
|
||||
BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: FittedBox(child: image, fit: BoxFit.fill))),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
return WillPopScope(
|
||||
onWillPop: () async => false,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
alignment: Alignment.center,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
ConstrainedBox(
|
||||
constraints:
|
||||
BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3),
|
||||
child: AspectRatio(aspectRatio: 1, child: image),
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 33),
|
||||
child: Observer(builder: (_) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
walletSeedViewModel.name,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.titleLarge!
|
||||
.color!),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: 20, left: 16, right: 16),
|
||||
child: Text(
|
||||
walletSeedViewModel.seed,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.bodySmall!
|
||||
.color!),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
Text(
|
||||
walletSeedViewModel.name,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.titleLarge!.color!),
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
isNewWalletCreated
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: 52, left: 43, right: 43),
|
||||
child: Text(
|
||||
S.of(context).seed_reminder,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.labelSmall!
|
||||
.color!),
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: walletSeedViewModel.seed,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white),
|
||||
)),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: walletSeedViewModel.seed));
|
||||
showBar<void>(context,
|
||||
S.of(context).copied_to_clipboard);
|
||||
},
|
||||
text: S.of(context).copy,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.bodyMedium!
|
||||
.color!,
|
||||
textColor: Colors.white)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, left: 16, right: 16),
|
||||
child: Text(
|
||||
walletSeedViewModel.seed,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.bodySmall!.color!),
|
||||
),
|
||||
)
|
||||
],
|
||||
))
|
||||
],
|
||||
);
|
||||
}),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
isNewWalletCreated
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(bottom: 43, left: 43, right: 43),
|
||||
child: Text(
|
||||
S.of(context).seed_reminder,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.labelSmall!.color!),
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: walletSeedViewModel.seed,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white),
|
||||
)),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: Builder(
|
||||
builder: (context) => PrimaryButton(
|
||||
onPressed: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: walletSeedViewModel.seed));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
text: S.of(context).copy,
|
||||
color: Theme.of(context).accentTextTheme.bodyMedium!.color!,
|
||||
textColor: Colors.white)),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)));
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,9 @@ class SendPage extends BasePage {
|
|||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: !isMobileView ? 'Close' : 'Back',
|
||||
label: !isMobileView
|
||||
? S.of(context).close
|
||||
: S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith(
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
|||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
|
||||
class ConnectionSyncPage extends BasePage {
|
||||
ConnectionSyncPage(this.nodeListViewModel, this.dashboardViewModel);
|
||||
|
@ -64,49 +63,37 @@ class ConnectionSyncPage extends BasePage {
|
|||
itemBuilder: (_, sectionIndex, index) {
|
||||
final node = nodeListViewModel.nodes[index];
|
||||
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
|
||||
final nodeListRow = Semantics(
|
||||
label: 'Slidable',
|
||||
selected: isSelected,
|
||||
enabled: !isSelected,
|
||||
child: NodeListRow(
|
||||
title: node.uriRaw,
|
||||
isSelected: isSelected,
|
||||
isAlive: node.requestNode(),
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
final nodeListRow = NodeListRow(
|
||||
title: node.uriRaw,
|
||||
node: node,
|
||||
isSelected: isSelected,
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle:
|
||||
S.of(context).change_current_node_title,
|
||||
alertContent: nodeListViewModel
|
||||
.getAlertContent(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
),
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle:
|
||||
S.of(context).change_current_node_title,
|
||||
alertContent: nodeListViewModel
|
||||
.getAlertContent(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
final dismissibleRow = Slidable(
|
||||
key: Key('${node.keyIndex}'),
|
||||
startActionPane: _actionPane(context, node, isSelected),
|
||||
endActionPane: _actionPane(context, node, isSelected),
|
||||
child: nodeListRow,
|
||||
);
|
||||
|
||||
return dismissibleRow;
|
||||
return nodeListRow;
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -134,44 +121,4 @@ class ConnectionSyncPage extends BasePage {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
ActionPane _actionPane(BuildContext context, Node node, bool isSelected) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: isSelected ? 0.3 : 0.6,
|
||||
children: [
|
||||
if (!isSelected)
|
||||
SlidableAction(
|
||||
onPressed: (context) async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await nodeListViewModel.delete(node);
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: (_) => Navigator.of(context).pushNamed(Routes.newNode,
|
||||
arguments: {'editingNode': node, 'isSelected': isSelected}),
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
icon: Icons.edit,
|
||||
label: S.of(context).edit,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
175
lib/src/screens/wallet/wallet_edit_page.dart
Normal file
175
lib/src/screens/wallet/wallet_edit_page.dart
Normal file
|
@ -0,0 +1,175 @@
|
|||
import 'package:another_flushbar/flushbar.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class WalletEditPage extends BasePage {
|
||||
WalletEditPage(
|
||||
{required this.walletEditViewModel,
|
||||
required this.editingWallet,
|
||||
required this.walletNewVM,
|
||||
required this.authService})
|
||||
: _formKey = GlobalKey<FormState>(),
|
||||
_labelController = TextEditingController(),
|
||||
super() {
|
||||
_labelController.text = editingWallet.name;
|
||||
_labelController.addListener(() => walletEditViewModel.newName = _labelController.text);
|
||||
}
|
||||
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final TextEditingController _labelController;
|
||||
|
||||
final WalletEditViewModel walletEditViewModel;
|
||||
final WalletNewVM walletNewVM;
|
||||
final WalletListItem editingWallet;
|
||||
final AuthService authService;
|
||||
|
||||
@override
|
||||
String get title => S.current.wallet_list_edit_wallet;
|
||||
|
||||
Flushbar<void>? _progressBar;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(24.0),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: BaseTextFormField(
|
||||
controller: _labelController,
|
||||
hintText: S.of(context).wallet_list_wallet_name,
|
||||
validator: WalletNameValidator()))),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
final isLoading = walletEditViewModel.state is WalletEditRenamePending ||
|
||||
walletEditViewModel.state is WalletEditDeletePending;
|
||||
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
isDisabled: isLoading,
|
||||
onPressed: () => _removeWallet(context),
|
||||
text: S.of(context).delete,
|
||||
color: Palette.red,
|
||||
textColor: Colors.white),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState?.validate() ?? false) {
|
||||
if (walletNewVM.nameExists(walletEditViewModel.newName)) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: S.of(context).wallet_name_exists,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop(),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
await walletEditViewModel.changeName(editingWallet);
|
||||
Navigator.of(context).pop();
|
||||
walletEditViewModel.resetState();
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
},
|
||||
text: S.of(context).save,
|
||||
color: Theme.of(context).accentTextTheme.bodyLarge!.color!,
|
||||
textColor: Colors.white,
|
||||
isDisabled: walletEditViewModel.newName.isEmpty || isLoading,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _removeWallet(BuildContext context) async {
|
||||
authService.authenticateAction(context, onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
|
||||
_onSuccessfulAuth(context);
|
||||
});
|
||||
}
|
||||
|
||||
void _onSuccessfulAuth(BuildContext context) async {
|
||||
bool confirmed = false;
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).delete_wallet,
|
||||
alertContent: S.of(context).delete_wallet_confirm_message(editingWallet.name),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).delete,
|
||||
actionLeftButton: () => Navigator.of(dialogContext).pop(),
|
||||
actionRightButton: () {
|
||||
confirmed = true;
|
||||
Navigator.of(dialogContext).pop();
|
||||
});
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
try {
|
||||
changeProcessText(context, S.of(context).wallet_list_removing_wallet(editingWallet.name));
|
||||
await walletEditViewModel.remove(editingWallet);
|
||||
hideProgressText();
|
||||
} catch (e) {
|
||||
changeProcessText(
|
||||
context,
|
||||
S.of(context).wallet_list_failed_to_remove(editingWallet.name, e.toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void changeProcessText(BuildContext context, String text) {
|
||||
_progressBar = createBar<void>(text, duration: null)..show(context);
|
||||
}
|
||||
|
||||
Future<void> hideProgressText() async {
|
||||
await Future.delayed(Duration(milliseconds: 50), () {
|
||||
_progressBar?.dismiss();
|
||||
_progressBar = null;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:another_flushbar/flushbar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -17,7 +16,6 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
|||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
|
||||
class WalletListPage extends BasePage {
|
||||
|
@ -79,31 +77,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
? Theme.of(context).accentTextTheme!.titleSmall!.decorationColor!
|
||||
: Theme.of(context).colorScheme.background;
|
||||
final row = GestureDetector(
|
||||
onTap: () async {
|
||||
if (wallet.isCurrent || !wallet.isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_wallet_alert_title,
|
||||
alertContent:
|
||||
S.of(context).change_wallet_alert_content(wallet.name),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(dialogContext).pop(false),
|
||||
actionRightButton: () =>
|
||||
Navigator.of(dialogContext).pop(true));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await _loadWallet(wallet);
|
||||
}
|
||||
},
|
||||
onTap: () => wallet.isCurrent ? null : _loadWallet(wallet),
|
||||
child: Container(
|
||||
height: tileHeight,
|
||||
width: double.infinity,
|
||||
|
@ -131,16 +105,21 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
? _imageFor(type: wallet.type)
|
||||
: nonWalletTypeIcon,
|
||||
SizedBox(width: 10),
|
||||
Text(
|
||||
wallet.name,
|
||||
style: TextStyle(
|
||||
Flexible(
|
||||
child: Text(
|
||||
wallet.name,
|
||||
maxLines: null,
|
||||
softWrap: true,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.titleLarge!
|
||||
.color!),
|
||||
)
|
||||
.color!,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -151,12 +130,38 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
|
||||
return wallet.isCurrent
|
||||
? row
|
||||
: Slidable(
|
||||
key: Key('${wallet.key}'),
|
||||
startActionPane: _actionPane(wallet),
|
||||
endActionPane: _actionPane(wallet),
|
||||
child: row,
|
||||
);
|
||||
: Row(children: [
|
||||
Expanded(child: row),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.walletEdit,
|
||||
arguments: [widget.walletListViewModel, wallet]),
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 20),
|
||||
child: Center(
|
||||
child: Container(
|
||||
height: 40,
|
||||
width: 44,
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineMedium!
|
||||
.decorationColor!),
|
||||
child: Icon(
|
||||
Icons.edit,
|
||||
size: 14,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineMedium!
|
||||
.color!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
]);
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
@ -217,7 +222,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
await hideProgressText();
|
||||
// only pop the wallets route in mobile as it will go back to dashboard page
|
||||
// in desktop platforms the navigation tree is different
|
||||
if (ResponsiveLayoutUtil.instance.isMobile) {
|
||||
if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
|
@ -228,47 +233,6 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
});
|
||||
}
|
||||
|
||||
Future<void> _removeWallet(WalletListItem wallet) async {
|
||||
widget.authService.authenticateAction(context,
|
||||
onAuthSuccess: (isAuthenticatedSuccessfully) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
_onSuccessfulAuth(wallet);
|
||||
});
|
||||
}
|
||||
|
||||
void _onSuccessfulAuth(WalletListItem wallet) async {
|
||||
bool confirmed = false;
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).delete_wallet,
|
||||
alertContent: S.of(context).delete_wallet_confirm_message(wallet.name),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).delete,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
actionRightButton: () {
|
||||
confirmed = true;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
try {
|
||||
changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name));
|
||||
await widget.walletListViewModel.remove(wallet);
|
||||
hideProgressText();
|
||||
} catch (e) {
|
||||
changeProcessText(
|
||||
S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void changeProcessText(String text) {
|
||||
_progressBar = createBar<void>(text, duration: null)..show(context);
|
||||
}
|
||||
|
@ -279,18 +243,4 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
_progressBar = null;
|
||||
});
|
||||
}
|
||||
|
||||
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: 0.3,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (_) => _removeWallet(wallet),
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -46,145 +46,133 @@ class WelcomePage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final welcomeImage = currentTheme.type == ThemeType.dark ? welcomeImageDark : welcomeImageLight;
|
||||
final welcomeImage = currentTheme.type == ThemeType.dark
|
||||
? welcomeImageDark
|
||||
: welcomeImageLight;
|
||||
|
||||
final newWalletImage = Image.asset('assets/images/new_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.headlineSmall!
|
||||
.accentTextTheme.headlineSmall!
|
||||
.decorationColor!);
|
||||
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
||||
height: 12,
|
||||
|
||||
width: 12,
|
||||
color: Theme.of(context).primaryTextTheme!.titleLarge!.color!);
|
||||
|
||||
color: Theme.of(context).primaryTextTheme.titleLarge!.color!);
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () async => false,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints:
|
||||
BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: welcomeImage, fit: BoxFit.fill))),
|
||||
Flexible(
|
||||
flex: 3,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Text(
|
||||
S.of(context).welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
appTitle(context),
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.titleLarge!
|
||||
.color!,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
appDescription(context),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displayMedium!
|
||||
.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamed(context, Routes.newWalletFromWelcome),
|
||||
image: newWalletImage,
|
||||
text: S.of(context).create_new,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.titleSmall!
|
||||
.decorationColor!,
|
||||
textColor: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.headlineSmall!
|
||||
.decorationColor!,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, Routes.restoreOptions,
|
||||
arguments: true);
|
||||
},
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).restore_wallet,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.bodySmall!
|
||||
.color!,
|
||||
textColor: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.titleLarge!
|
||||
.color!),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
))
|
||||
],
|
||||
),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(
|
||||
child: welcomeImage, fit: BoxFit.contain),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: Text(
|
||||
S.of(context).welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme.displayMedium!
|
||||
.color!,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
appTitle(context),
|
||||
style: TextStyle(
|
||||
fontSize: 36,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme.titleLarge!
|
||||
.color!,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
appDescription(context),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme.displayMedium!
|
||||
.color!,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme.displayMedium!
|
||||
.color!,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context, Routes.newWalletFromWelcome),
|
||||
image: newWalletImage,
|
||||
text: S.of(context).create_new,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme.titleSmall!
|
||||
.decorationColor!,
|
||||
textColor: Theme.of(context)
|
||||
.accentTextTheme.headlineSmall!
|
||||
.decorationColor!,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(
|
||||
context, Routes.restoreOptions,
|
||||
arguments: true);
|
||||
},
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).restore_wallet,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme.bodySmall!
|
||||
.color!,
|
||||
textColor: Theme.of(context)
|
||||
.primaryTextTheme.titleLarge!
|
||||
.color!),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
|
|
@ -114,55 +114,66 @@ class AddressTextField extends StatelessWidget {
|
|||
width: prefixIconWidth,
|
||||
height: prefixIconHeight,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () async => _pasteAddress(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor ??
|
||||
Theme.of(context)
|
||||
.accentTextTheme!
|
||||
child: Semantics(
|
||||
label: S.of(context).paste,
|
||||
child: InkWell(
|
||||
onTap: () async => _pasteAddress(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor ??
|
||||
Theme.of(context)
|
||||
.accentTextTheme
|
||||
!
|
||||
.titleLarge!
|
||||
.color!,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/paste_ios.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.color!,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/paste_ios.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme
|
||||
!
|
||||
.headlineMedium!
|
||||
.decorationColor!,
|
||||
)),
|
||||
.decorationColor!,
|
||||
)),
|
||||
),
|
||||
)),
|
||||
],
|
||||
if (this.options.contains(AddressTextFieldOption.qrCode) && DeviceInfo.instance.isMobile)
|
||||
...[
|
||||
if (this.options.contains(AddressTextFieldOption.qrCode) &&
|
||||
DeviceInfo.instance.isMobile) ...[
|
||||
Container(
|
||||
width: prefixIconWidth,
|
||||
height: prefixIconHeight,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () async => _presentQRScanner(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor ??
|
||||
Theme.of(context)
|
||||
.accentTextTheme
|
||||
child: Semantics(
|
||||
label: S.of(context).scan_qr_code,
|
||||
child: InkWell(
|
||||
onTap: () async => _presentQRScanner(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor ??
|
||||
Theme.of(context)
|
||||
.accentTextTheme
|
||||
|
||||
.titleLarge!
|
||||
.color!,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/qr_code_icon.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme!.headlineMedium!
|
||||
.decorationColor!,
|
||||
)),
|
||||
.color!,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/qr_code_icon.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme
|
||||
!.headlineMedium!
|
||||
.decorationColor!,
|
||||
)),
|
||||
),
|
||||
))
|
||||
] else SizedBox(width: 5),
|
||||
] else
|
||||
SizedBox(width: 5),
|
||||
if (this
|
||||
.options
|
||||
.contains(AddressTextFieldOption.addressBook)) ...[
|
||||
|
@ -170,26 +181,32 @@ class AddressTextField extends StatelessWidget {
|
|||
width: prefixIconWidth,
|
||||
height: prefixIconHeight,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: InkWell(
|
||||
onTap: () async => _presetAddressBookPicker(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor ??
|
||||
Theme.of(context)
|
||||
.accentTextTheme!
|
||||
child: Semantics(
|
||||
label: S.of(context).address_book,
|
||||
child: InkWell(
|
||||
onTap: () async =>
|
||||
_presetAddressBookPicker(context),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: buttonColor ??
|
||||
Theme.of(context)
|
||||
.accentTextTheme
|
||||
!
|
||||
.titleLarge!
|
||||
.color!,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/open_book.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.color!,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/open_book.png',
|
||||
color: iconColor ??
|
||||
Theme.of(context)
|
||||
.primaryTextTheme
|
||||
!
|
||||
.headlineMedium!
|
||||
.decorationColor!,
|
||||
)),
|
||||
.decorationColor!,
|
||||
)),
|
||||
),
|
||||
))
|
||||
]
|
||||
],
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class MarketPlaceItem extends StatelessWidget {
|
||||
class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
|
||||
|
||||
MarketPlaceItem({
|
||||
DashBoardRoundedCardWidget({
|
||||
required this.onTap,
|
||||
required this.title,
|
||||
required this.subTitle,
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class IntroducingCard extends StatelessWidget {
|
||||
IntroducingCard(
|
||||
|
@ -70,7 +71,7 @@ class IntroducingCard extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(0,16,16,0),
|
||||
child: Semantics(
|
||||
label: 'Close',
|
||||
label: S.of(context).close,
|
||||
child: GestureDetector(
|
||||
onTap: closeCard,
|
||||
child: Container(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
|
||||
import 'package:cake_wallet/src/widgets/search_bar_widget.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
|
@ -158,37 +159,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
|
|||
if (widget.hintText != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextFormField(
|
||||
controller: searchController,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme!
|
||||
.titleLarge!
|
||||
.color!),
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.hintText,
|
||||
prefixIcon:
|
||||
Image.asset("assets/images/search_icon.png"),
|
||||
filled: true,
|
||||
fillColor: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.displaySmall!
|
||||
.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,
|
||||
)),
|
||||
),
|
||||
),
|
||||
child: SearchBarWidget(searchController: searchController),
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context)
|
||||
|
|
91
lib/src/widgets/picker_inner_wrapper_widget.dart
Normal file
91
lib/src/widgets/picker_inner_wrapper_widget.dart
Normal file
|
@ -0,0 +1,91 @@
|
|||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
|
||||
|
||||
class PickerInnerWrapperWidget extends StatelessWidget {
|
||||
PickerInnerWrapperWidget(
|
||||
{required this.children, this.title, this.itemsHeight});
|
||||
|
||||
final List<Widget> children;
|
||||
final String? title;
|
||||
final double? itemsHeight;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final mq = MediaQuery.of(context);
|
||||
final bottom = mq.viewInsets.bottom;
|
||||
final height = mq.size.height - bottom;
|
||||
|
||||
double containerHeight = height * 0.65;
|
||||
if (bottom > 0) {
|
||||
// increase a bit or it gets too squished in the top
|
||||
containerHeight = height * 0.75;
|
||||
}
|
||||
|
||||
if (title != null) {
|
||||
return PickerWrapperWidget(
|
||||
hasTitle: true,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Text(
|
||||
title!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
color: Theme.of(context).textTheme.displayLarge!.decorationColor!,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight:
|
||||
itemsHeight != null && itemsHeight! <= containerHeight
|
||||
? itemsHeight!
|
||||
: containerHeight,
|
||||
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
|
||||
),
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return PickerWrapperWidget(
|
||||
hasTitle: false,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
color: Theme.of(context).textTheme.displayLarge!.decorationColor!,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: containerHeight,
|
||||
maxWidth: ResponsiveLayoutUtil.kPopupWidth,
|
||||
),
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
40
lib/src/widgets/search_bar_widget.dart
Normal file
40
lib/src/widgets/search_bar_widget.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class SearchBarWidget extends StatelessWidget {
|
||||
const SearchBarWidget({
|
||||
required this.searchController,
|
||||
this.hintText,
|
||||
this.borderRadius = 14,
|
||||
});
|
||||
|
||||
final TextEditingController searchController;
|
||||
final String? hintText;
|
||||
final double borderRadius;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
controller: searchController,
|
||||
style: TextStyle(color: Theme.of(context).primaryTextTheme!.titleLarge!.color!),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText ?? S.of(context).search_currency,
|
||||
prefixIcon: Image.asset("assets/images/search_icon.png"),
|
||||
filled: true,
|
||||
fillColor: Theme.of(context).accentTextTheme!.displaySmall!.color!,
|
||||
alignLabelWithHint: false,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -231,7 +231,7 @@ class SectionStandardList extends StatelessWidget {
|
|||
return Container();
|
||||
}
|
||||
|
||||
return StandardListSeparator(padding: EdgeInsets.only(left: 24));
|
||||
return StandardListSeparator(padding: dividerPadding);
|
||||
},
|
||||
itemCount: totalRows.length,
|
||||
itemBuilder: (_, index) => totalRows[index]);
|
||||
|
|
|
@ -146,15 +146,13 @@ abstract class SettingsStoreBase with Store {
|
|||
});
|
||||
}
|
||||
|
||||
reaction(
|
||||
(_) => disableBuy,
|
||||
(bool disableBuy) => sharedPreferences.setBool(
|
||||
PreferencesKey.disableBuyKey, disableBuy));
|
||||
reaction((_) => disableBuy,
|
||||
(bool disableBuy) => sharedPreferences.setBool(PreferencesKey.disableBuyKey, disableBuy));
|
||||
|
||||
reaction(
|
||||
(_) => disableSell,
|
||||
(bool disableSell) => sharedPreferences.setBool(
|
||||
PreferencesKey.disableSellKey, disableSell));
|
||||
(bool disableSell) =>
|
||||
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
|
||||
|
||||
reaction(
|
||||
(_) => fiatApiMode,
|
||||
|
@ -352,12 +350,9 @@ abstract class SettingsStoreBase with Store {
|
|||
// FIX-ME: Check for which default value we should have here
|
||||
final shouldSaveRecipientAddress =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? false;
|
||||
final isAppSecure =
|
||||
sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
|
||||
final disableBuy =
|
||||
sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
|
||||
final disableSell =
|
||||
sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
|
||||
final isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
|
||||
final disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
|
||||
final disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
|
||||
final currentFiatApiMode = FiatApiMode.deserialize(
|
||||
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
|
||||
FiatApiMode.enabled.raw);
|
||||
|
@ -494,16 +489,14 @@ abstract class SettingsStoreBase with Store {
|
|||
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;
|
||||
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;
|
||||
shouldShowMarketPlaceInDashboard =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ??
|
||||
shouldShowMarketPlaceInDashboard;
|
||||
|
|
39
lib/utils/distribution_info.dart
Normal file
39
lib/utils/distribution_info.dart
Normal file
|
@ -0,0 +1,39 @@
|
|||
import 'dart:io';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
||||
enum DistributionType { googleplay, github, appstore, fdroid }
|
||||
|
||||
class DistributionInfo {
|
||||
DistributionInfo._();
|
||||
|
||||
static DistributionInfo get instance => DistributionInfo._();
|
||||
|
||||
Future<String> getDistributionPath() async {
|
||||
final isPlayStore = await isInstalledFromPlayStore();
|
||||
final distributionPath = _getDistributionPath(isPlayStore);
|
||||
|
||||
return distributionPath.name;
|
||||
}
|
||||
|
||||
DistributionType _getDistributionPath(bool isPlayStore) {
|
||||
if (isPlayStore) {
|
||||
return DistributionType.googleplay;
|
||||
} else if (Platform.isAndroid) {
|
||||
return DistributionType.github;
|
||||
} else if (Platform.isIOS) {
|
||||
return DistributionType.appstore;
|
||||
} else {
|
||||
return DistributionType.github;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> isInstalledFromPlayStore() async {
|
||||
try {
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
return packageInfo.packageName == 'com.android.vending';
|
||||
} catch (e) {
|
||||
print('Error: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
3
lib/utils/feature_flag.dart
Normal file
3
lib/utils/feature_flag.dart
Normal file
|
@ -0,0 +1,3 @@
|
|||
class FeatureFlag {
|
||||
static const bool isCakePayEnabled = false;
|
||||
}
|
|
@ -1,22 +1,32 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ResponsiveLayoutUtil {
|
||||
static const double _kMobileThreshold = 768;
|
||||
static const double _kMobileThreshold = 550;
|
||||
static const double kDesktopMaxWidthConstraint = 400;
|
||||
static const double kDesktopMaxDashBoardWidthConstraint = 900;
|
||||
static const double kPopupWidth = 400;
|
||||
static const double kPopupSpaceHeight = 100;
|
||||
static const _kIpadMaxWidth = 2560.0;
|
||||
|
||||
const ResponsiveLayoutUtil._();
|
||||
|
||||
static final instance = ResponsiveLayoutUtil._();
|
||||
|
||||
bool get isMobile =>
|
||||
MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width < _kMobileThreshold;
|
||||
MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.shortestSide <=
|
||||
_kMobileThreshold;
|
||||
|
||||
bool get isIpad {
|
||||
final width = MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;
|
||||
return width >= _kMobileThreshold && !(width > _kIpadMaxWidth);
|
||||
bool shouldRenderMobileUI() {
|
||||
final mediaQuery = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
|
||||
final orientation = mediaQuery.orientation;
|
||||
final width = mediaQuery.size.width;
|
||||
final height = mediaQuery.size.height;
|
||||
if (isMobile ||
|
||||
(orientation == Orientation.portrait && width < height) ||
|
||||
(orientation == Orientation.landscape && width < height)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns dynamic size.
|
||||
|
|
|
@ -4,9 +4,9 @@ part 'desktop_sidebar_view_model.g.dart';
|
|||
|
||||
enum SidebarItem {
|
||||
dashboard,
|
||||
transactions,
|
||||
support,
|
||||
settings,
|
||||
transactions;
|
||||
}
|
||||
|
||||
class DesktopSidebarViewModel = DesktopSidebarViewModelBase with _$DesktopSidebarViewModel;
|
||||
|
|
|
@ -36,7 +36,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
_provider = XMRTOExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
_provider = ChangeNowExchangeProvider();
|
||||
_provider =
|
||||
ChangeNowExchangeProvider(settingsStore: sendViewModel.balanceViewModel.settingsStore);
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
_provider = MorphTokenExchangeProvider(trades: trades);
|
||||
|
|
|
@ -130,7 +130,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
final SharedPreferences sharedPreferences;
|
||||
|
||||
List<ExchangeProvider> get _allProviders => [
|
||||
ChangeNowExchangeProvider(),
|
||||
ChangeNowExchangeProvider(settingsStore: _settingsStore),
|
||||
SideShiftExchangeProvider(),
|
||||
SimpleSwapExchangeProvider(),
|
||||
TrocadorExchangeProvider(useTorOnly: _useTorOnly),
|
||||
|
@ -221,7 +221,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
|
||||
bool get hasAllAmount =>
|
||||
wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency;
|
||||
(wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) && depositCurrency == wallet.currency;
|
||||
|
||||
bool get isMoneroWallet => wallet.type == WalletType.monero;
|
||||
|
||||
|
@ -566,7 +566,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
@action
|
||||
void calculateDepositAllAmount() {
|
||||
if (wallet.type == WalletType.bitcoin) {
|
||||
if (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) {
|
||||
final availableBalance = wallet.balance[wallet.currency]!.available;
|
||||
final priority = _settingsStore.priority[wallet.type]!;
|
||||
final fee = wallet.calculateEstimatedFee(priority, null);
|
||||
|
|
|
@ -24,6 +24,7 @@ abstract class RescanViewModelBase with Store {
|
|||
Future<void> rescanCurrentWallet({required int restoreHeight}) async {
|
||||
state = RescanWalletState.rescaning;
|
||||
await _wallet.rescan(height: restoreHeight);
|
||||
_wallet.transactionHistory.clear();
|
||||
state = RescanWalletState.none;
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ abstract class TradeDetailsViewModelBase with Store {
|
|||
_provider = XMRTOExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
_provider = ChangeNowExchangeProvider();
|
||||
_provider = ChangeNowExchangeProvider(settingsStore: settingsStore);
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
_provider = MorphTokenExchangeProvider(trades: trades);
|
||||
|
|
55
lib/view_model/wallet_list/wallet_edit_view_model.dart
Normal file
55
lib/view_model/wallet_list/wallet_edit_view_model.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
|
||||
part 'wallet_edit_view_model.g.dart';
|
||||
|
||||
class WalletEditViewModel = WalletEditViewModelBase with _$WalletEditViewModel;
|
||||
|
||||
abstract class WalletEditViewModelState {}
|
||||
|
||||
class WalletEditViewModelInitialState extends WalletEditViewModelState {}
|
||||
|
||||
class WalletEditRenamePending extends WalletEditViewModelState {}
|
||||
|
||||
class WalletEditDeletePending extends WalletEditViewModelState {}
|
||||
|
||||
abstract class WalletEditViewModelBase with Store {
|
||||
WalletEditViewModelBase(this._walletListViewModel, this._walletLoadingService)
|
||||
: state = WalletEditViewModelInitialState(),
|
||||
newName = '';
|
||||
|
||||
@observable
|
||||
WalletEditViewModelState state;
|
||||
|
||||
@observable
|
||||
String newName;
|
||||
|
||||
final WalletListViewModel _walletListViewModel;
|
||||
final WalletLoadingService _walletLoadingService;
|
||||
|
||||
@action
|
||||
Future<void> changeName(WalletListItem walletItem) async {
|
||||
state = WalletEditRenamePending();
|
||||
await _walletLoadingService.renameWallet(
|
||||
walletItem.type, walletItem.name, newName);
|
||||
_walletListViewModel.updateList();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> remove(WalletListItem wallet) async {
|
||||
state = WalletEditDeletePending();
|
||||
final walletService = getIt.get<WalletService>(param1: wallet.type);
|
||||
await walletService.remove(wallet.name);
|
||||
resetState();
|
||||
_walletListViewModel.updateList();
|
||||
}
|
||||
|
||||
@action
|
||||
void resetState() {
|
||||
state = WalletEditViewModelInitialState();
|
||||
}
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -25,8 +24,8 @@ abstract class WalletListViewModelBase with Store {
|
|||
this._walletLoadingService,
|
||||
this._authService,
|
||||
) : wallets = ObservableList<WalletListItem>() {
|
||||
_updateList();
|
||||
reaction((_) => _appStore.wallet, (_) => _updateList());
|
||||
updateList();
|
||||
reaction((_) => _appStore.wallet, (_) => updateList());
|
||||
}
|
||||
|
||||
@observable
|
||||
|
@ -41,20 +40,14 @@ abstract class WalletListViewModelBase with Store {
|
|||
|
||||
@action
|
||||
Future<void> loadWallet(WalletListItem walletItem) async {
|
||||
final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
|
||||
final wallet =
|
||||
await _walletLoadingService.load(walletItem.type, walletItem.name);
|
||||
|
||||
_appStore.changeCurrentWallet(wallet);
|
||||
_updateList();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> remove(WalletListItem wallet) async {
|
||||
final walletService = getIt.get<WalletService>(param1: wallet.type);
|
||||
await walletService.remove(wallet.name);
|
||||
await _walletInfoSource.delete(wallet.key);
|
||||
_updateList();
|
||||
}
|
||||
|
||||
void _updateList() {
|
||||
void updateList() {
|
||||
wallets.clear();
|
||||
wallets.addAll(
|
||||
_walletInfoSource.values.map(
|
||||
|
@ -62,7 +55,8 @@ abstract class WalletListViewModelBase with Store {
|
|||
name: info.name,
|
||||
type: info.type,
|
||||
key: info.key,
|
||||
isCurrent: info.name == _appStore.wallet!.name && info.type == _appStore.wallet!.type,
|
||||
isCurrent: info.name == _appStore.wallet!.name &&
|
||||
info.type == _appStore.wallet!.type,
|
||||
isEnabled: availableWalletTypes.contains(info.type),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -115,7 +115,7 @@ SPEC CHECKSUMS:
|
|||
platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
||||
shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451
|
||||
wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -5,19 +5,14 @@
|
|||
"please_make_selection": "Don Allah zaɓi ƙasa don ƙirƙira ko dawo da kwalinku.",
|
||||
"create_new": "Ƙirƙira Sabon Kwalinku",
|
||||
"restore_wallet": "Dawo da Kwalinku",
|
||||
|
||||
"monero_com": "Monero.com ta Cake Wallet",
|
||||
"monero_com_wallet_text": "Aikace-aikacen e-wallet ga Monero",
|
||||
|
||||
"haven_app": "Haven da Cake Wallet",
|
||||
"haven_app_wallet_text": "Aikace-aikacen e-wallet ga Haven",
|
||||
|
||||
"accounts": "Lissafi",
|
||||
"edit": "Gyara",
|
||||
"account": "Asusu",
|
||||
"add": "Ƙara",
|
||||
|
||||
|
||||
"address_book": "Littafin adireshi",
|
||||
"contact": "Tuntuɓar",
|
||||
"please_select": "Don Allah zaɓi:",
|
||||
|
@ -28,13 +23,9 @@
|
|||
"save": "Ajiye",
|
||||
"address_remove_contact": "Cire lamba",
|
||||
"address_remove_content": "Kuna tabbatar kuna so ku cire wannan Contact?",
|
||||
|
||||
|
||||
"authenticated": "Ingantacce",
|
||||
"authentication": "Tabbatarwa",
|
||||
"failed_authentication": "Binne wajen shiga. ${state_error}",
|
||||
|
||||
|
||||
"wallet_menu": "Menu",
|
||||
"Blocks_remaining": "${status} Katanga ya rage",
|
||||
"please_try_to_connect_to_another_node": "Don Allah yi ƙoƙarin haɗa da wani node",
|
||||
|
@ -62,8 +53,6 @@
|
|||
"address_book_menu": "Littafin adireshi",
|
||||
"reconnection": "Sake haɗawa",
|
||||
"reconnect_alert_text": "Shin kun tabbata kuna son sake haɗawa?",
|
||||
|
||||
|
||||
"exchange": "Exchange",
|
||||
"clear": "Share",
|
||||
"refund_address": "Adireshin maidowa",
|
||||
|
@ -80,7 +69,6 @@
|
|||
"change_currency": "Canja Kuɗi",
|
||||
"overwrite_amount": "Rubuta adadin",
|
||||
"qr_payment_amount": "Wannan QR code yana da adadin kuɗi. Kuna so ku overwrite wannan adadi?",
|
||||
|
||||
"copy_id": "Kwafi ID",
|
||||
"exchange_result_write_down_trade_id": "Da fatan za a kwafa ko rubuta ID ɗin ciniki don ci gaba.",
|
||||
"trade_id": "ID na kasuwanci:",
|
||||
|
@ -106,20 +94,13 @@
|
|||
"time": "${minutes}m ${seconds}s",
|
||||
"send_xmr": "Aika XMR",
|
||||
"exchange_new_template": "Sabon template",
|
||||
|
||||
"faq": "FAQ",
|
||||
|
||||
|
||||
"enter_your_pin": "Shigar da PIN",
|
||||
"loading_your_wallet": "Ana loda walat ɗin ku",
|
||||
|
||||
|
||||
"new_wallet": "Sabuwar Wallet",
|
||||
"wallet_name": "Sunan walat",
|
||||
"continue_text": "Ci gaba",
|
||||
"choose_wallet_currency": "Da fatan za a zaɓi kuɗin walat:",
|
||||
|
||||
|
||||
"node_new": "Sabon Node",
|
||||
"node_address": "Address Node",
|
||||
"node_port": "Node tashar jiragen ruwa",
|
||||
|
@ -140,24 +121,18 @@
|
|||
"node_connection_successful": "Haɗin ya yi nasara",
|
||||
"node_connection_failed": "Haɗin ya gaza",
|
||||
"new_node_testing": "Sabbin gwajin kumburi",
|
||||
|
||||
|
||||
"use": "Canja zuwa",
|
||||
"digit_pin": "-lambar PIN",
|
||||
|
||||
|
||||
"share_address": "Raba adireshin",
|
||||
"receive_amount": "Adadi",
|
||||
"subaddresses": "Subaddresses",
|
||||
"addresses": "Addresses",
|
||||
"scan_qr_code": "Duba lambar QR don samun adireshin",
|
||||
"scan_qr_code": "Gani QR kodin",
|
||||
"qr_fullscreen": "Matsa don buɗe lambar QR na cikakken allo",
|
||||
"rename": "Sake suna",
|
||||
"choose_account": "Zaɓi asusu",
|
||||
"create_new_account": "Ƙirƙiri sabon asusu",
|
||||
"accounts_subaddresses": "Accounts da subaddresses",
|
||||
|
||||
|
||||
"restore_restore_wallet": "Maida Wallet",
|
||||
"restore_title_from_seed_keys": "Dawo da iri/maɓallai",
|
||||
"restore_description_from_seed_keys": "Maido da walat ɗin ku daga iri/maɓallan da kuka adana don amintaccen wuri",
|
||||
|
@ -181,14 +156,10 @@
|
|||
"restore_bitcoin_description_from_keys": "Dawo da kwalinku daga WIF string dake generate daga maɓallan sirri",
|
||||
"restore_bitcoin_title_from_keys": "Dawo daga WIF",
|
||||
"restore_from_date_or_blockheight": "Don Allah shigar da wata kwanan a kafin ku ƙirƙirar wannan kwalinku. Ko idan kun san blockheight, don Allah shigar da shi",
|
||||
|
||||
|
||||
"seed_reminder": "Don Allah rubuta wadannan in case ka manta ko ka sake kwallon wayarka",
|
||||
"seed_title": "iri",
|
||||
"seed_share": "Raba iri",
|
||||
"copy": "Kwafi",
|
||||
|
||||
|
||||
"seed_language_choose": "Don Allah zaɓi harshen seed:",
|
||||
"seed_choose": "Zaɓi harshen seed",
|
||||
"seed_language_next": "Na gaba",
|
||||
|
@ -202,8 +173,6 @@
|
|||
"seed_language_spanish": "Spanish",
|
||||
"seed_language_french": "Faransanci",
|
||||
"seed_language_italian": "Italiyanci",
|
||||
|
||||
|
||||
"send_title": "Aika",
|
||||
"send_your_wallet": "Walat ɗin ku",
|
||||
"send_address": "${cryptoCurrency} address",
|
||||
|
@ -219,11 +188,9 @@
|
|||
"send_amount": "Adadi:",
|
||||
"send_fee": "Kudin:",
|
||||
"send_name": "Sunan",
|
||||
"send_got_it": "Gama",
|
||||
"got_it": "Gama",
|
||||
"send_sending": "Aika...",
|
||||
"send_success": "${crypto} kwalinku ya aika da nasara",
|
||||
|
||||
|
||||
"settings_title": "Saitunan",
|
||||
"settings_nodes": "Nodes",
|
||||
"settings_current_node": "Node yanzu",
|
||||
|
@ -247,13 +214,9 @@
|
|||
"settings_support": "Taimako",
|
||||
"settings_terms_and_conditions": "Sharuɗɗa da Ka'idoji",
|
||||
"pin_is_incorrect": "PIN ba daidai ba ne",
|
||||
|
||||
|
||||
"setup_pin": "Saita PIN",
|
||||
"enter_your_pin_again": "Shigar da PIN ɗinku na sake",
|
||||
"setup_successful": "An saita PIN ɗinku da nasara!",
|
||||
|
||||
|
||||
"wallet_keys": "Iri/maɓalli na walat",
|
||||
"wallet_seed": "kalmar sirri na walat",
|
||||
"private_key": "Keɓaɓɓen maɓalli",
|
||||
|
@ -263,17 +226,11 @@
|
|||
"spend_key_private": "makullin biya (maɓallin kalmar sirri)",
|
||||
"spend_key_public": "makullin biya (maɓallin jama'a)",
|
||||
"copied_key_to_clipboard": "An kwafa ${key} a cikin kwafin",
|
||||
|
||||
|
||||
"new_subaddress_title": "Adireshin sabuwa",
|
||||
"new_subaddress_label_name": "Lakabin suna",
|
||||
"new_subaddress_create": "Ƙirƙiri",
|
||||
|
||||
"address_label": "Labari adireshi",
|
||||
|
||||
"subaddress_title": "Jagorar subaddress",
|
||||
|
||||
|
||||
"trade_details_title": "Bayanai game da kasuwancin",
|
||||
"trade_details_id": "ID",
|
||||
"trade_details_state": "Matsayi",
|
||||
|
@ -282,11 +239,7 @@
|
|||
"trade_details_created_at": "An ƙirƙira a",
|
||||
"trade_details_pair": "miji da matarsa",
|
||||
"trade_details_copied": "${title} an kwafa zuwa cikin kwafin",
|
||||
|
||||
|
||||
"trade_history_title": "Tarihin kasuwancin",
|
||||
|
||||
|
||||
"transaction_details_title": "Bayanai game da aikace-aikacen",
|
||||
"transaction_details_transaction_id": "ID na kasuwanci",
|
||||
"transaction_details_date": "Kwanan wata",
|
||||
|
@ -295,28 +248,22 @@
|
|||
"transaction_details_fee": "Kudin",
|
||||
"transaction_details_copied": "${title} an kwafa zuwa cikin kwafin",
|
||||
"transaction_details_recipient_address": "Adireshin masu amfani",
|
||||
|
||||
|
||||
"wallet_list_title": "Monero walat",
|
||||
"wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet",
|
||||
"wallet_list_edit_wallet" : "Gyara walat",
|
||||
"wallet_list_wallet_name" : "Sunan walat",
|
||||
"wallet_list_restore_wallet": "Maida Wallet",
|
||||
"wallet_list_load_wallet": "Ana loda wallet na Monero",
|
||||
"wallet_list_loading_wallet": "Ana loda ${wallet_name} walat",
|
||||
"wallet_list_failed_to_load": "An kasa loda ${wallet_name} walat. ${error}",
|
||||
"wallet_list_removing_wallet": "Cirewa ${wallet_name} walat",
|
||||
"wallet_list_failed_to_remove": "Ba a iya cirewa ${wallet_name} walat. ${error}",
|
||||
|
||||
|
||||
"widgets_address": "Adireshin",
|
||||
"widgets_restore_from_blockheight": "Sake dawo da daga blockheight",
|
||||
"widgets_restore_from_date": "Sake dawo da daga kwanan wata",
|
||||
"widgets_or": "ko",
|
||||
"widgets_seed": "iri",
|
||||
|
||||
|
||||
"router_no_route": "Babu wata hanya da aka bayyana don ${name}",
|
||||
|
||||
|
||||
"error_text_account_name": "Sunan ajiya zai iya ɗauka ne kawai da haruffa, lambobi\nkuma ya zama tsakanin 1 zuwa 15 haruffa",
|
||||
"error_text_contact_name": "Sunan kira ba zai iya ɗaukar ` , ' \" haruffa\nkuma ya zama tsakanin 1 zuwa 32 haruffa",
|
||||
"error_text_address": "Adireshin hujja ya kamata ya dace da irin\nna cryptocurrency",
|
||||
|
@ -334,21 +281,15 @@
|
|||
"error_text_maximum_limit": "Kasuwanci ga ${provider} ba a yi ba. Adadin shine fiye da ƙimanin: ${max} ${currency}",
|
||||
"error_text_limits_loading_failed": "Kasuwanci ga ${provider} ba a yi ba. An kasa saukewa masanan",
|
||||
"error_text_template": "Sunan na tushe da adireshin ba zai iya ɗaukar ` , ' \" haruffa\nkuma ya zama tsakanin 1 zuwa 106 haruffa",
|
||||
|
||||
|
||||
"auth_store_ban_timeout": "ban_timeout",
|
||||
"auth_store_banned_for": "An haramta don",
|
||||
"auth_store_banned_minutes": "da minti",
|
||||
"auth_store_incorrect_password": "PIN na gaskiya",
|
||||
"wallet_store_monero_wallet": "Monero walat",
|
||||
"wallet_restoration_store_incorrect_seed_length": "kalmar sirrin iri ba daidai ba",
|
||||
|
||||
|
||||
"full_balance": "DUKAN KUDI",
|
||||
"available_balance": "KUDI",
|
||||
"hidden_balance": "BOYE KUDI",
|
||||
|
||||
|
||||
"sync_status_syncronizing": "KWAFI",
|
||||
"sync_status_syncronized": "KYAU",
|
||||
"sync_status_not_connected": "BABU INTERNET",
|
||||
|
@ -357,21 +298,15 @@
|
|||
"sync_status_connecting": "HADA",
|
||||
"sync_status_connected": "HANNU",
|
||||
"sync_status_attempting_sync": "KWAFI",
|
||||
|
||||
|
||||
"transaction_priority_slow": "SAURI DA SAURI",
|
||||
"transaction_priority_regular": "SAURI NORMAL",
|
||||
"transaction_priority_medium": "SAURI DA DADI",
|
||||
"transaction_priority_fast": "sauri",
|
||||
"transaction_priority_fastest": "mafi sauri",
|
||||
|
||||
|
||||
"trade_for_not_created": "Ba a ƙirƙira ciniki don ${title} ba.",
|
||||
"trade_not_created": "Ba a ƙirƙira ciniki ba",
|
||||
"trade_id_not_found": "Ba a samo cinikin ${tradeId} na ${title} ba.",
|
||||
"trade_not_found": "Ba a sami ciniki ba.",
|
||||
|
||||
|
||||
"trade_state_pending": "Jira",
|
||||
"trade_state_confirming": "Tabbatar",
|
||||
"trade_state_trading": "Ciniki",
|
||||
|
@ -386,59 +321,42 @@
|
|||
"trade_state_timeout": "lokacin da ya ƙare",
|
||||
"trade_state_created": "an halicci",
|
||||
"trade_state_finished": "an kammala",
|
||||
|
||||
"change_language": "canja harshen",
|
||||
"change_language_to": "canja harshen zuwa ${language}?",
|
||||
|
||||
"paste": "Manna",
|
||||
"restore_from_seed_placeholder": "Da fatan za a shigar da ko manna maɓallin ku a nan",
|
||||
"add_new_word": "Ƙara kalma sabuwa",
|
||||
"incorrect_seed": "rubutun da aka shigar ba shi da inganci.",
|
||||
|
||||
"biometric_auth_reason": "Duba hoton yatsa don tantancewa",
|
||||
"version": "Sigar ${currentVersion}",
|
||||
|
||||
"openalias_alert_title": "An gano adireshin",
|
||||
"openalias_alert_content": "Zaka aika kuɗi zuwa \n${recipient_name}",
|
||||
|
||||
"card_address": "Adireshin:",
|
||||
"buy": "Sayi",
|
||||
"sell": "sayar",
|
||||
|
||||
"placeholder_transactions": "Za a nuna ma'amalolin ku anan",
|
||||
"placeholder_contacts": "Za a nuna lambobin sadarwar ku anan",
|
||||
|
||||
"template": "Samfura",
|
||||
"confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?",
|
||||
"confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?",
|
||||
|
||||
"picker_description": "Don zaɓar ChangeNOW ko MorphToken, da farko canja kasuwancin pair din ku",
|
||||
|
||||
"change_wallet_alert_title": "Canja walat yanzu",
|
||||
"change_wallet_alert_content": "Kana so ka canja walat yanzu zuwa ${wallet_name}?",
|
||||
|
||||
"creating_new_wallet": "Haliccin walat sabuwa",
|
||||
"creating_new_wallet_error": "Kuskure: ${description}",
|
||||
|
||||
"seed_alert_title": "Hankali",
|
||||
"seed_alert_content": "Irin ita ce kawai hanya don dawo da walat ɗin ku. Kun rubuta shi?",
|
||||
"seed_alert_back": "juya baya",
|
||||
"seed_alert_yes": "E, Na yi",
|
||||
|
||||
"exchange_sync_alert_content": "Da fatan za a jira har sai an daidaita walat ɗin ku",
|
||||
|
||||
"pre_seed_title": "MUHIMMANCI",
|
||||
"pre_seed_description": "A kan shafin nan za ku ga wata ƙungiya na ${words} kalmomi. Wannan shine tsarin daban-daban ku kuma na sirri kuma shine hanya ɗaya kadai don mai da purse dinku a cikin yanayin rasa ko rashin aiki. Yana da damar da kuke a cikin tabbatar da kuyi rubuta shi kuma kuyi ajiye shi a wuri na aminci wanda ya wuce wurin app na Cake Wallet.",
|
||||
"pre_seed_button_text": "Ina fahimta. Nuna mini seed din nawa",
|
||||
|
||||
"xmr_to_error": "XMR.TO kuskure",
|
||||
"xmr_to_error_description": "Adadin ba shi da inganci. Maksimum ɗaura 8 digiri bayan decimal point",
|
||||
|
||||
"provider_error": "${provider} kuskure",
|
||||
|
||||
"use_ssl": "Yi amfani da SSL",
|
||||
"trusted": "Amintacce",
|
||||
|
||||
"color_theme": "Jigon launi",
|
||||
"light_theme": "Haske",
|
||||
"bright_theme": "Mai haske",
|
||||
|
@ -451,11 +369,9 @@
|
|||
"transaction_key": "Aikace-aikacen key",
|
||||
"confirmations": "Tabbatar",
|
||||
"recipient_address": "Adireshin mai karɓa",
|
||||
|
||||
"extra_id": "Karin ID:",
|
||||
"destination_tag": "Tambarin makoma:",
|
||||
"memo": "Memo:",
|
||||
|
||||
"backup": "Ajiyayyen",
|
||||
"change_password": "Canza kalmar shiga",
|
||||
"backup_password": "Ajiyayyen kalmar sirri",
|
||||
|
@ -463,55 +379,40 @@
|
|||
"export_backup": "Ajiyayyen fitarwa",
|
||||
"save_backup_password": "Da fatan za a tabbatar cewa kun adana kalmar sirrin ajiyar ku. Ba za ku iya shigo da fayilolin ajiyar ku ba tare da shi ba.",
|
||||
"backup_file": "Ajiyayyen fayil",
|
||||
|
||||
"edit_backup_password": "Shirya Kalmar wucewa ta Ajiyayyen",
|
||||
"save_backup_password_alert": "Ajiye kalmar sirri ta ajiya",
|
||||
"change_backup_password_alert": "Fayilolin madadin ku na baya ba za su kasance don shigo da sabon kalmar sirri ta madadin ba. Sabuwar kalmar sirri ta ajiya za a yi amfani da ita kawai don sabbin fayilolin madadin. Shin kun tabbata cewa kuna son canza kalmar wucewa?",
|
||||
|
||||
"enter_backup_password": "Shigar da kalmar wucewa ta madadin nan",
|
||||
"select_backup_file": "Zaɓi fayil ɗin madadin",
|
||||
"import": "Shigo da",
|
||||
"please_select_backup_file": "Da fatan za a zaɓi fayil ɗin madadin kuma shigar da kalmar wucewa ta madadin.",
|
||||
|
||||
"fixed_rate": "Kafaffen ƙima",
|
||||
"fixed_rate_alert": "Za ku iya shigar da adadin karɓa lokacin da aka duba ƙayyadadden zaɓin ƙimar kuɗi. Kuna so ku canza zuwa ƙayyadadden yanayin ƙimar kuɗi?",
|
||||
|
||||
"xlm_extra_info": "Don Allah kar a manta da saka Memo ID yayin aika ma'amalar XLM don musayar",
|
||||
"xrp_extra_info": "Don Allah kar a manta da saka alamar Ƙaddamarwa yayin aika ma'amalar XRP don musayar",
|
||||
|
||||
"exchange_incorrect_current_wallet_for_xmr": "Idan kana son musanya XMR daga ma'aunin Cake Wallet Monero, da fatan za a fara canza wallet ɗin Monero ɗin ku.",
|
||||
"confirmed": "An tabbatar",
|
||||
"unconfirmed": "Ba a tabbatar ba",
|
||||
"displayable": "Ana iya nunawa",
|
||||
|
||||
"submit_request": "gabatar da bukata",
|
||||
|
||||
"buy_alert_content": "A halin yanzu muna tallafawa kawai siyan Bitcoin da Litecoin. Don siyan Bitcoin ko Litecoin, da fatan za a ƙirƙira ko canza zuwa walat ɗin ku na Bitcoin ko Litecoin.",
|
||||
"sell_alert_content": "A halin yanzu muna tallafawa siyar da Bitcoin da Litecoin kawai. Da fatan za a ƙirƙira ko canza zuwa walat ɗin ku na Bitcoin ko Litecoin.",
|
||||
|
||||
"outdated_electrum_wallet_description": "Sabbin walat ɗin Bitcoin da aka kirkira a cikin Cake yanzu suna da nau'in kalma 24. Ya zama dole ka ƙirƙiri sabon walat ɗin Bitcoin kuma canza duk kuɗin ku zuwa sabon walat ɗin kalmomi 24, kuma ku daina amfani da walat tare da iri mai kalma 12. Da fatan za a yi haka nan take don samun kuɗin ku.",
|
||||
"understand": "na gane",
|
||||
|
||||
"apk_update": "apk sabunta",
|
||||
|
||||
"buy_bitcoin": "Sayi Bitcoin",
|
||||
"buy_with": "Saya da",
|
||||
"moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}",
|
||||
|
||||
"outdated_electrum_wallet_receive_warning": "Idan wannan walat ɗin yana da nau'in kalma 12 kuma an ƙirƙira shi a cikin Cake, KAR KA saka Bitcoin cikin wannan jakar. Duk wani BTC da aka canjawa wuri zuwa wannan walat na iya ɓacewa. Ƙirƙiri sabon walat mai kalmomi 24 (matsa menu a saman dama, zaɓi Wallets, zaɓi Ƙirƙiri Sabon Wallet, sannan zaɓi Bitcoin) kuma NAN nan take matsar da BTC ɗin ku a can. Sabbin (kalmomi 24) BTC wallets daga Cake suna da tsaro",
|
||||
"do_not_show_me": "Kar ka sake nuna min wannan",
|
||||
|
||||
"unspent_coins_title": "Tsabar da ba a kashe ba",
|
||||
"unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba",
|
||||
"freeze": "Daskare",
|
||||
"frozen": "Daskararre",
|
||||
"coin_control": "Sarrafa tsabar kuɗi (na zaɓi)",
|
||||
|
||||
"address_detected": "An gano adireshin",
|
||||
"address_from_domain": "Wannan adireshin ya fito daga ${domain} akan Unstoppable Domain",
|
||||
|
||||
"add_receiver": "Ƙara wani mai karɓa (na zaɓi)",
|
||||
|
||||
"manage_yats": "Sarrafa Yats",
|
||||
"yat_alert_title": "Aika da karɓar crypto cikin sauƙi tare da Yat",
|
||||
"yat_alert_content": "Masu amfani da Wallet ɗin Cake yanzu za su iya aikawa da karɓar duk kuɗin da suka fi so tare da sunan mai amfani na tushen emoji iri ɗaya.",
|
||||
|
@ -681,11 +582,10 @@
|
|||
"contact_list_contacts": "Lambobin sadarwa",
|
||||
"contact_list_wallets": "Wallets dina",
|
||||
"bitcoin_payments_require_1_confirmation": "Akwatin Bitcoin na buɗe 1 sambumbu, da yake za ta samu mintuna 20 ko yawa. Ina kira ga sabuwar lafiya! Zaka sanarwa ta email lokacin da aka samu akwatin samun lambar waya.",
|
||||
"send_to_this_address" : "Aiko ${currency} ${tag} zuwa adireshin wannan",
|
||||
"arrive_in_this_address" : "${currency} ${tag} zai je wurin wannan adireshi",
|
||||
"send_to_this_address": "Aiko ${currency} ${tag} zuwa adireshin wannan",
|
||||
"arrive_in_this_address": "${currency} ${tag} zai je wurin wannan adireshi",
|
||||
"do_not_send": "Kada ka aika",
|
||||
"error_dialog_content": "Ai, yanzu muka ga alamar kuskure. \n\nDa fatan, aika rahoton kuskuren da muka kira zuwa gasar tsarinmu don gaskiyar shirya.",
|
||||
"scan_qr_code": "Gani QR kodin",
|
||||
"cold_or_recover_wallet": "Samun kashi na baya ko samun kashi na kasa",
|
||||
"please_wait": "Don Allah a rufe",
|
||||
"sweeping_wallet": "Kashi na kasa",
|
||||
|
@ -705,10 +605,18 @@
|
|||
"frozen_balance": "Falin kuma maɓallin",
|
||||
"settings": "Saiti",
|
||||
"sell_monero_com_alert_content": "Selling Monero bai sami ƙarshen mai bukatar samun ba",
|
||||
"error_text_input_below_minimum_limit" : "Kudin ba a kamai",
|
||||
"error_text_input_above_maximum_limit" : "Kudin da ya kamata",
|
||||
"show_market_place" :"Nuna dan kasuwa",
|
||||
"error_text_input_below_minimum_limit": "Kudin ba a kamai",
|
||||
"error_text_input_above_maximum_limit": "Kudin da ya kamata",
|
||||
"show_market_place": "Nuna dan kasuwa",
|
||||
"prevent_screenshots": "Fada lambobi da jarrabobi na kayan lambobi",
|
||||
"disable_buy": "Kashe alama",
|
||||
"disable_sell": "Kashe karbuwa"
|
||||
}
|
||||
"disable_sell": "Kashe karbuwa",
|
||||
"available_balance_description": "Ma'auni mai samuwa” ko ”,Tabbataccen Ma'auni”, kudade ne da za a iya kashewa nan da nan. Idan kudade sun bayyana a cikin ƙananan ma'auni amma ba babban ma'auni ba, to dole ne ku jira 'yan mintoci kaɗan don kudaden shiga don samun ƙarin tabbaci na hanyar sadarwa. Bayan sun sami ƙarin tabbaci, za a kashe su.",
|
||||
"syncing_wallet_alert_title": "Walat ɗin ku yana aiki tare",
|
||||
"syncing_wallet_alert_content": "Ma'aunin ku da lissafin ma'amala bazai cika ba har sai an ce \"SYNCHRONIZED\" a saman. Danna/matsa don ƙarin koyo.",
|
||||
"generate_name": "Ƙirƙirar Suna",
|
||||
"balance_page": "Ma'auni Page",
|
||||
"share": "Raba",
|
||||
"slidable": "Mai iya zamewa"
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue