mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-23 19:16:09 +00:00
Merge branch '4.1.0' into CAKE-222-fix-fee-picker-on-the-settings-screen
This commit is contained in:
commit
0e721b7795
47 changed files with 1402 additions and 642 deletions
|
@ -354,7 +354,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 10;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -494,7 +494,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 10;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
@ -528,7 +528,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = 10;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
DEVELOPMENT_TEAM = 32J6BB6VUS;
|
||||
ENABLE_BITCODE = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:cake_wallet/entities/crypto_amount_format.dart';
|
||||
|
||||
|
@ -7,10 +9,32 @@ final bitcoinAmountFormat = NumberFormat()
|
|||
..maximumFractionDigits = bitcoinAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
|
||||
String bitcoinAmountToString({int amount}) =>
|
||||
bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||
String bitcoinAmountToString({int amount}) => bitcoinAmountFormat.format(
|
||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||
|
||||
double bitcoinAmountToDouble({int amount}) => cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
||||
double bitcoinAmountToDouble({int amount}) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
||||
|
||||
int doubleToBitcoinAmount(double amount) =>
|
||||
(amount * bitcoinAmountDivider).toInt();
|
||||
int stringDoubleToBitcoinAmount(String amount) {
|
||||
final splitted = amount.split('');
|
||||
final dotIndex = amount.indexOf('.');
|
||||
int result = 0;
|
||||
|
||||
|
||||
for (var i = 0; i < splitted.length; i++) {
|
||||
try {
|
||||
if (dotIndex == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final char = splitted[i];
|
||||
final multiplier = dotIndex < i
|
||||
? bitcoinAmountDivider ~/ pow(10, (i - dotIndex))
|
||||
: (bitcoinAmountDivider * pow(10, (dotIndex - i -1))).toInt();
|
||||
final num = int.parse(char) * multiplier;
|
||||
result += num;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ class BitcoinBalance extends Balance {
|
|||
final int confirmed;
|
||||
final int unconfirmed;
|
||||
|
||||
int get total =>
|
||||
confirmed + (unconfirmed < 0 ? unconfirmed * -1 : unconfirmed);
|
||||
int get total => confirmed + unconfirmed;
|
||||
|
||||
int get availableBalance => confirmed + (unconfirmed < 0 ? unconfirmed : 0);
|
||||
int get availableBalance =>
|
||||
(confirmed ?? 0) + (unconfirmed < 0 ? unconfirmed : 0);
|
||||
|
||||
String get confirmedFormatted => bitcoinAmountToString(amount: confirmed);
|
||||
|
||||
|
|
|
@ -4,6 +4,6 @@ class BitcoinTransactionCredentials {
|
|||
BitcoinTransactionCredentials(this.address, this.amount, this.priority);
|
||||
|
||||
final String address;
|
||||
final double amount;
|
||||
final String amount;
|
||||
TransactionPriority priority;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
|
|||
final out = vin['tx']['vout'][vout] as Map;
|
||||
final outAddresses =
|
||||
(out['scriptPubKey']['addresses'] as List<Object>)?.toSet();
|
||||
inputsAmount += doubleToBitcoinAmount(out['value'] as double ?? 0);
|
||||
inputsAmount += stringDoubleToBitcoinAmount((out['value'] as double ?? 0).toString());
|
||||
|
||||
if (outAddresses?.intersection(addressesSet)?.isNotEmpty ?? false) {
|
||||
direction = TransactionDirection.outgoing;
|
||||
|
@ -58,7 +58,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
|
|||
final outAddresses =
|
||||
out['scriptPubKey']['addresses'] as List<Object> ?? [];
|
||||
final ntrs = outAddresses.toSet().intersection(addressesSet);
|
||||
final value = doubleToBitcoinAmount(out['value'] as double ?? 0.0);
|
||||
final value = stringDoubleToBitcoinAmount((out['value'] as double ?? 0.0).toString());
|
||||
totalOutAmount += value;
|
||||
|
||||
if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
|
||||
|
|
|
@ -116,6 +116,19 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
walletInfo: walletInfo);
|
||||
}
|
||||
|
||||
static int feeAmountForPriority(TransactionPriority priority) {
|
||||
switch (priority) {
|
||||
case TransactionPriority.slow:
|
||||
return 6000;
|
||||
case TransactionPriority.regular:
|
||||
return 22080;
|
||||
case TransactionPriority.fast:
|
||||
return 24000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
final BitcoinTransactionHistory transactionHistory;
|
||||
final String path;
|
||||
|
@ -243,16 +256,20 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
Object credentials) async {
|
||||
final transactionCredentials = credentials as BitcoinTransactionCredentials;
|
||||
final inputs = <BitcoinUnspent>[];
|
||||
final fee = _feeMultiplier(transactionCredentials.priority);
|
||||
final fee = feeAmountForPriority(transactionCredentials.priority);
|
||||
final amount = transactionCredentials.amount != null
|
||||
? doubleToBitcoinAmount(transactionCredentials.amount)
|
||||
: balance.total - fee;
|
||||
? stringDoubleToBitcoinAmount(transactionCredentials.amount)
|
||||
: balance.availableBalance - fee;
|
||||
final totalAmount = amount + fee;
|
||||
final txb = bitcoin.TransactionBuilder(network: bitcoin.bitcoin);
|
||||
var leftAmount = totalAmount;
|
||||
final changeAddress = address;
|
||||
var leftAmount = totalAmount;
|
||||
var totalInputAmount = 0;
|
||||
|
||||
if (totalAmount > balance.availableBalance) {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
}
|
||||
|
||||
final unspent = addresses.map((address) => eclient
|
||||
.getListUnspentWithAddress(address.address)
|
||||
.then((unspent) => unspent
|
||||
|
@ -334,7 +351,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
|
||||
@override
|
||||
double calculateEstimatedFee(TransactionPriority priority) =>
|
||||
bitcoinAmountToDouble(amount: _feeMultiplier(priority));
|
||||
bitcoinAmountToDouble(amount: feeAmountForPriority(priority));
|
||||
|
||||
@override
|
||||
Future<void> save() async {
|
||||
|
@ -386,17 +403,4 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
|
|||
|
||||
String _getAddress({@required int index}) =>
|
||||
generateAddress(hd: hd, index: index);
|
||||
|
||||
int _feeMultiplier(TransactionPriority priority) {
|
||||
switch (priority) {
|
||||
case TransactionPriority.slow:
|
||||
return 6000;
|
||||
case TransactionPriority.regular:
|
||||
return 22080;
|
||||
case TransactionPriority.fast:
|
||||
return 24000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,8 @@ String jsonrpcparams(List<Object> params) {
|
|||
}
|
||||
|
||||
String jsonrpc(
|
||||
{String method, List<Object> params, int id, double version = 2.0}) =>
|
||||
'{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json
|
||||
.encode(params)}}\n';
|
||||
{String method, List<Object> params, int id, double version = 2.0}) =>
|
||||
'{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n';
|
||||
|
||||
class SocketTask {
|
||||
SocketTask({this.completer, this.isSubscription, this.subject});
|
||||
|
@ -75,7 +74,9 @@ class ElectrumClient {
|
|||
|
||||
socket.listen((Uint8List event) {
|
||||
try {
|
||||
_handleResponse(utf8.decode(event.toList()));
|
||||
final response =
|
||||
json.decode(utf8.decode(event.toList())) as Map<String, Object>;
|
||||
_handleResponse(response);
|
||||
} on FormatException catch (e) {
|
||||
final msg = e.message.toLowerCase();
|
||||
|
||||
|
@ -87,12 +88,33 @@ class ElectrumClient {
|
|||
unterminatedString += e.source as String;
|
||||
}
|
||||
|
||||
if (msg.contains("not a subtype of type")) {
|
||||
unterminatedString += e.source as String;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJSONStringCorrect(unterminatedString)) {
|
||||
_handleResponse(unterminatedString);
|
||||
final response =
|
||||
json.decode(unterminatedString) as Map<String, Object>;
|
||||
_handleResponse(response);
|
||||
unterminatedString = null;
|
||||
}
|
||||
} on TypeError catch (e) {
|
||||
if (!e.toString().contains('Map<String, Object>')) {
|
||||
return;
|
||||
}
|
||||
|
||||
final source = utf8.decode(event.toList());
|
||||
unterminatedString += source;
|
||||
|
||||
if (isJSONStringCorrect(unterminatedString)) {
|
||||
final response =
|
||||
json.decode(unterminatedString) as Map<String, Object>;
|
||||
_handleResponse(response);
|
||||
unterminatedString = null;
|
||||
}
|
||||
} catch (e) {
|
||||
print(e);
|
||||
print(e.toString());
|
||||
}
|
||||
}, onError: (Object error) {
|
||||
print(error.toString());
|
||||
|
@ -153,7 +175,7 @@ class ElectrumClient {
|
|||
});
|
||||
|
||||
Future<List<Map<String, dynamic>>> getListUnspentWithAddress(
|
||||
String address) =>
|
||||
String address) =>
|
||||
call(
|
||||
method: 'blockchain.scripthash.listunspent',
|
||||
params: [scriptHash(address)]).then((dynamic result) {
|
||||
|
@ -204,7 +226,7 @@ class ElectrumClient {
|
|||
});
|
||||
|
||||
Future<Map<String, Object>> getTransactionRaw(
|
||||
{@required String hash}) async =>
|
||||
{@required String hash}) async =>
|
||||
call(method: 'blockchain.transaction.get', params: [hash, true])
|
||||
.then((dynamic result) {
|
||||
if (result is Map<String, Object>) {
|
||||
|
@ -233,25 +255,25 @@ class ElectrumClient {
|
|||
}
|
||||
|
||||
Future<String> broadcastTransaction(
|
||||
{@required String transactionRaw}) async =>
|
||||
{@required String transactionRaw}) async =>
|
||||
call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
|
||||
.then((dynamic result) {
|
||||
if (result is String) {
|
||||
return result;
|
||||
}
|
||||
|
||||
print(result);
|
||||
return '';
|
||||
});
|
||||
|
||||
Future<Map<String, dynamic>> getMerkle(
|
||||
{@required String hash, @required int height}) async =>
|
||||
{@required String hash, @required int height}) async =>
|
||||
await call(
|
||||
method: 'blockchain.transaction.get_merkle',
|
||||
params: [hash, height]) as Map<String, dynamic>;
|
||||
|
||||
Future<Map<String, dynamic>> getHeader({@required int height}) async =>
|
||||
await call(method: 'blockchain.block.get_header', params: [height])
|
||||
as Map<String, dynamic>;
|
||||
as Map<String, dynamic>;
|
||||
|
||||
Future<double> estimatefee({@required int p}) =>
|
||||
call(method: 'blockchain.estimatefee', params: [p])
|
||||
|
@ -275,9 +297,10 @@ class ElectrumClient {
|
|||
params: [scripthash]);
|
||||
}
|
||||
|
||||
BehaviorSubject<T> subscribe<T>({@required String id,
|
||||
@required String method,
|
||||
List<Object> params = const []}) {
|
||||
BehaviorSubject<T> subscribe<T>(
|
||||
{@required String id,
|
||||
@required String method,
|
||||
List<Object> params = const []}) {
|
||||
final subscription = BehaviorSubject<T>();
|
||||
_regisrySubscription(id, subscription);
|
||||
socket.write(jsonrpc(method: method, id: _id, params: params));
|
||||
|
@ -296,9 +319,10 @@ class ElectrumClient {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
Future<dynamic> callWithTimeout({String method,
|
||||
List<Object> params = const [],
|
||||
int timeout = 2000}) async {
|
||||
Future<dynamic> callWithTimeout(
|
||||
{String method,
|
||||
List<Object> params = const [],
|
||||
int timeout = 2000}) async {
|
||||
final completer = Completer<dynamic>();
|
||||
_id += 1;
|
||||
final id = _id;
|
||||
|
@ -325,9 +349,8 @@ class ElectrumClient {
|
|||
onConnectionStatusChange = null;
|
||||
}
|
||||
|
||||
void _regisryTask(int id, Completer completer) =>
|
||||
_tasks[id.toString()] =
|
||||
SocketTask(completer: completer, isSubscription: false);
|
||||
void _regisryTask(int id, Completer completer) => _tasks[id.toString()] =
|
||||
SocketTask(completer: completer, isSubscription: false);
|
||||
|
||||
void _regisrySubscription(String id, BehaviorSubject subject) =>
|
||||
_tasks[id] = SocketTask(subject: subject, isSubscription: true);
|
||||
|
@ -371,22 +394,20 @@ class ElectrumClient {
|
|||
_isConnected = isConnected;
|
||||
}
|
||||
|
||||
void _handleResponse(String response) {
|
||||
print('Response: $response');
|
||||
final jsoned = json.decode(response) as Map<String, Object>;
|
||||
// print(jsoned);
|
||||
final method = jsoned['method'];
|
||||
final id = jsoned['id'] as String;
|
||||
final result = jsoned['result'];
|
||||
void _handleResponse(Map<String, Object> response) {
|
||||
final method = response['method'];
|
||||
final id = response['id'] as String;
|
||||
final result = response['result'];
|
||||
|
||||
if (method is String) {
|
||||
_methodHandler(method: method, request: jsoned);
|
||||
_methodHandler(method: method, request: response);
|
||||
return;
|
||||
}
|
||||
|
||||
_finish(id, result);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: move me
|
||||
bool isJSONStringCorrect(String source) {
|
||||
try {
|
||||
|
|
24
lib/di.dart
24
lib/di.dart
|
@ -28,6 +28,7 @@ import 'package:cake_wallet/src/screens/send/send_template_page.dart';
|
|||
import 'package:cake_wallet/src/screens/settings/change_language.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/settings.dart';
|
||||
import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
|
@ -55,6 +56,8 @@ import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/rescan_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/setup_pin_code_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/trade_details_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
|
@ -355,7 +358,8 @@ Future setup(
|
|||
getIt.get<AppStore>().wallet,
|
||||
tradesSource,
|
||||
getIt.get<ExchangeTemplateStore>(),
|
||||
getIt.get<TradesStore>()));
|
||||
getIt.get<TradesStore>(),
|
||||
getIt.get<AppStore>().settingsStore));
|
||||
|
||||
getIt.registerFactory(() => ExchangeTradeViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet,
|
||||
|
@ -415,11 +419,17 @@ Future setup(
|
|||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) =>
|
||||
WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
|
||||
|
||||
getIt.registerFactoryParam<TransactionDetailsViewModel, TransactionInfo, void>
|
||||
((TransactionInfo transactionInfo, _) => TransactionDetailsViewModel(
|
||||
transactionInfo: transactionInfo,
|
||||
transactionDescriptionBox: transactionDescriptionBox,
|
||||
settingsStore: getIt.get<SettingsStore>()
|
||||
));
|
||||
|
||||
getIt.registerFactoryParam<TransactionDetailsPage, TransactionInfo, void>(
|
||||
(TransactionInfo transactionInfo, _) => TransactionDetailsPage(
|
||||
transactionInfo,
|
||||
getIt.get<SettingsStore>().shouldSaveRecipientAddress,
|
||||
transactionDescriptionBox));
|
||||
transactionDetailsViewModel: getIt
|
||||
.get<TransactionDetailsViewModel>(param1: transactionInfo)));
|
||||
|
||||
getIt.registerFactoryParam<NewWalletTypePage,
|
||||
void Function(BuildContext, WalletType), bool>(
|
||||
|
@ -428,4 +438,10 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<PreSeedPage, WalletType, void>(
|
||||
(WalletType type, _) => PreSeedPage(type));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||
TradeDetailsViewModel(tradeForDetails: trade, trades: tradesSource));
|
||||
|
||||
getIt.registerFactoryParam<TradeDetailsPage, Trade, void>((Trade trade, _) =>
|
||||
TradeDetailsPage(getIt.get<TradeDetailsViewModel>(param1: trade)));
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ part 'transaction_description.g.dart';
|
|||
|
||||
@HiveType(typeId: 2)
|
||||
class TransactionDescription extends HiveObject {
|
||||
TransactionDescription({this.id, this.recipientAddress});
|
||||
TransactionDescription({this.id, this.recipientAddress, this.transactionNote});
|
||||
|
||||
static const boxName = 'TransactionDescriptions';
|
||||
static const boxKey = 'transactionDescriptionsBoxKey';
|
||||
|
@ -14,4 +14,9 @@ class TransactionDescription extends HiveObject {
|
|||
|
||||
@HiveField(1)
|
||||
String recipientAddress;
|
||||
|
||||
@HiveField(2)
|
||||
String transactionNote;
|
||||
|
||||
String get note => transactionNote ?? '';
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -279,7 +279,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
|
||||
case Routes.tradeDetails:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => TradeDetailsPage(settings.arguments as Trade));
|
||||
builder: (_) =>
|
||||
getIt.get<TradeDetailsPage>(param1: settings.arguments as Trade));
|
||||
|
||||
case Routes.restoreWalletFromSeedDetails:
|
||||
final args = settings.arguments as List;
|
||||
|
|
|
@ -62,10 +62,11 @@ class ExchangePage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => TrailButton(
|
||||
caption: S.of(context).reset, onPressed: () {
|
||||
caption: S.of(context).reset,
|
||||
onPressed: () {
|
||||
_formKey.currentState.reset();
|
||||
exchangeViewModel.reset();
|
||||
});
|
||||
});
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
|
@ -95,8 +96,8 @@ class ExchangePage extends BasePage {
|
|||
return KeyboardActions(
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).accentTextTheme.body2
|
||||
.backgroundColor,
|
||||
keyboardBarColor:
|
||||
Theme.of(context).accentTextTheme.body2.backgroundColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
|
@ -160,6 +161,11 @@ class ExchangePage extends BasePage {
|
|||
padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
|
||||
child: Observer(
|
||||
builder: (_) => ExchangeCard(
|
||||
hasAllAmount: exchangeViewModel.hasAllAmount,
|
||||
allAmount: exchangeViewModel.hasAllAmount
|
||||
? () => exchangeViewModel
|
||||
.calculateDepositAllAmount()
|
||||
: null,
|
||||
amountFocusNode: _depositAmountFocus,
|
||||
key: depositKey,
|
||||
title: S.of(context).you_will_send,
|
||||
|
@ -394,30 +400,35 @@ class ExchangePage extends BasePage {
|
|||
}),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
text: S.of(context).exchange,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
if ((exchangeViewModel.depositCurrency == CryptoCurrency.xmr)
|
||||
&&(!(exchangeViewModel.status is SyncedSyncStatus))) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).exchange,
|
||||
alertContent: S.of(context).exchange_sync_alert_content,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
} else {
|
||||
exchangeViewModel.createTrade();
|
||||
}
|
||||
}
|
||||
},
|
||||
color: Theme.of(context).accentTextTheme.body2.color,
|
||||
textColor: Colors.white,
|
||||
isLoading: exchangeViewModel.tradeState
|
||||
is TradeIsCreating)),
|
||||
builder: (_) => LoadingPrimaryButton(
|
||||
text: S.of(context).exchange,
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
if ((exchangeViewModel.depositCurrency ==
|
||||
CryptoCurrency.xmr) &&
|
||||
(!(exchangeViewModel.status
|
||||
is SyncedSyncStatus))) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).exchange,
|
||||
alertContent: S
|
||||
.of(context)
|
||||
.exchange_sync_alert_content,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () =>
|
||||
Navigator.of(context).pop());
|
||||
});
|
||||
} else {
|
||||
exchangeViewModel.createTrade();
|
||||
}
|
||||
}
|
||||
},
|
||||
color: Theme.of(context).accentTextTheme.body2.color,
|
||||
textColor: Colors.white,
|
||||
isLoading:
|
||||
exchangeViewModel.tradeState is TradeIsCreating)),
|
||||
]),
|
||||
)),
|
||||
));
|
||||
|
|
|
@ -27,7 +27,9 @@ class ExchangeCard extends StatefulWidget {
|
|||
this.borderColor = Colors.transparent,
|
||||
this.currencyValueValidator,
|
||||
this.addressTextFieldValidator,
|
||||
this.amountFocusNode})
|
||||
this.amountFocusNode,
|
||||
this.hasAllAmount = false,
|
||||
this.allAmount})
|
||||
: super(key: key);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
|
@ -47,6 +49,8 @@ class ExchangeCard extends StatefulWidget {
|
|||
final FormFieldValidator<String> currencyValueValidator;
|
||||
final FormFieldValidator<String> addressTextFieldValidator;
|
||||
final FocusNode amountFocusNode;
|
||||
final bool hasAllAmount;
|
||||
Function allAmount;
|
||||
|
||||
@override
|
||||
ExchangeCardState createState() => ExchangeCardState();
|
||||
|
@ -197,7 +201,36 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
]),
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
if (widget.hasAllAmount)
|
||||
Positioned(
|
||||
top: 5,
|
||||
right: 55,
|
||||
child: Container(
|
||||
height: 32,
|
||||
width: 32,
|
||||
margin: EdgeInsets.only(left: 14, top: 4, bottom: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.color,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
child: InkWell(
|
||||
onTap: () => widget.allAmount?.call(),
|
||||
child: Center(
|
||||
child: Text(S.of(context).all,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.display1
|
||||
.decorationColor)),
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
|
@ -232,18 +265,17 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
),
|
||||
!_isAddressEditable && widget.hasRefundAddress
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
))
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
))
|
||||
: Offstage(),
|
||||
_isAddressEditable
|
||||
? Padding(
|
||||
|
@ -251,7 +283,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
child: AddressTextField(
|
||||
controller: addressController,
|
||||
placeholder: widget.hasRefundAddress
|
||||
? S.of(context).refund_address : null,
|
||||
? S.of(context).refund_address
|
||||
: null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
|
@ -265,8 +298,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color:
|
||||
Theme.of(context)
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display4
|
||||
.decorationColor),
|
||||
|
@ -281,8 +313,8 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: addressController.text));
|
||||
showBar<void>(context,
|
||||
S.of(context).copied_to_clipboard);
|
||||
showBar<void>(
|
||||
context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
|
|
@ -6,8 +6,6 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
|
@ -172,36 +170,14 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
),
|
||||
itemBuilder: (context, index) {
|
||||
final item = widget.exchangeTradeViewModel.items[index];
|
||||
String value;
|
||||
final value = item.data ?? fetchingLabel;
|
||||
|
||||
final content = Observer(builder: (_) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
value =
|
||||
'${widget.exchangeTradeViewModel.trade.id ?? fetchingLabel}';
|
||||
break;
|
||||
case 1:
|
||||
value =
|
||||
'${widget.exchangeTradeViewModel.trade.amount ?? fetchingLabel}';
|
||||
break;
|
||||
case 2:
|
||||
value =
|
||||
'${widget.exchangeTradeViewModel.trade.state ?? fetchingLabel}';
|
||||
break;
|
||||
case 3:
|
||||
value = widget.exchangeTradeViewModel.trade
|
||||
.inputAddress ??
|
||||
fetchingLabel;
|
||||
break;
|
||||
}
|
||||
|
||||
return StandartListRow(
|
||||
title: item.title,
|
||||
value: value,
|
||||
valueFontSize: 14,
|
||||
image: item.isCopied ? copyImage : null,
|
||||
);
|
||||
});
|
||||
final content = StandartListRow(
|
||||
title: item.title,
|
||||
value: value,
|
||||
valueFontSize: 14,
|
||||
image: item.isCopied ? copyImage : null,
|
||||
);
|
||||
|
||||
return item.isCopied
|
||||
? Builder(
|
||||
|
@ -382,7 +358,16 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
});
|
||||
});
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(context).pop());
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
feeFiatAmount: widget.exchangeTradeViewModel.sendViewModel
|
||||
.pendingTransaction.feeFormatted,
|
||||
fiatAmountValue: widget.exchangeTradeViewModel.sendViewModel
|
||||
.pendingTransactionFeeFiatAmount +
|
||||
' ' +
|
||||
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
|
||||
recipientTitle: S.of(context).recipient_address,
|
||||
recipientAddress:
|
||||
widget.exchangeTradeViewModel.sendViewModel.address);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ class PreSeedPage extends BasePage {
|
|||
Padding(
|
||||
padding: EdgeInsets.only(top: 70, left: 16, right: 16),
|
||||
child: Text(
|
||||
S.of(context).pre_seed_description(wordsCount),
|
||||
S.of(context).pre_seed_description(wordsCount.toString()),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
|
|
|
@ -31,6 +31,7 @@ class SendPage extends BasePage {
|
|||
: _addressController = TextEditingController(),
|
||||
_cryptoAmountController = TextEditingController(),
|
||||
_fiatAmountController = TextEditingController(),
|
||||
_noteController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>(),
|
||||
_cryptoAmountFocus = FocusNode(),
|
||||
_fiatAmountFocus = FocusNode(),
|
||||
|
@ -46,6 +47,7 @@ class SendPage extends BasePage {
|
|||
final TextEditingController _addressController;
|
||||
final TextEditingController _cryptoAmountController;
|
||||
final TextEditingController _fiatAmountController;
|
||||
final TextEditingController _noteController;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final FocusNode _cryptoAmountFocus;
|
||||
final FocusNode _fiatAmountFocus;
|
||||
|
@ -304,6 +306,30 @@ class SendPage extends BasePage {
|
|||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14),
|
||||
)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: BaseTextFormField(
|
||||
controller: _noteController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white),
|
||||
hintText: S.of(context).note_optional,
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.decorationColor),
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => GestureDetector(
|
||||
onTap: () =>
|
||||
|
@ -313,6 +339,7 @@ class SendPage extends BasePage {
|
|||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S
|
||||
|
@ -326,23 +353,50 @@ class SendPage extends BasePage {
|
|||
color: Colors.white)),
|
||||
Container(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
sendViewModel
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
sendViewModel
|
||||
.estimatedFee
|
||||
.toString() +
|
||||
' ' +
|
||||
sendViewModel
|
||||
' ' +
|
||||
sendViewModel
|
||||
.currency.title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight:
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight:
|
||||
FontWeight.w600,
|
||||
//color: Theme.of(context).primaryTextTheme.display2.color,
|
||||
color:
|
||||
//color: Theme.of(context).primaryTextTheme.display2.color,
|
||||
color:
|
||||
Colors.white)),
|
||||
Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
sendViewModel
|
||||
.estimatedFeeFiatAmount
|
||||
+ ' ' +
|
||||
sendViewModel
|
||||
.fiat.title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight:
|
||||
FontWeight.w600,
|
||||
color: Theme
|
||||
.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.decorationColor))
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 2,
|
||||
left: 5),
|
||||
child: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
|
@ -534,6 +588,14 @@ class SendPage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
_noteController.addListener(() {
|
||||
final note = _noteController.text ?? '';
|
||||
|
||||
if (note != sendViewModel.note) {
|
||||
sendViewModel.note = note;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.sendAll, (bool all) {
|
||||
if (all) {
|
||||
_cryptoAmountController.text = S.current.all;
|
||||
|
@ -571,6 +633,12 @@ class SendPage extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.note, (String note) {
|
||||
if (note != _noteController.text) {
|
||||
_noteController.text = note;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
@ -596,8 +664,14 @@ class SendPage extends BasePage {
|
|||
amount: S.of(context).send_amount,
|
||||
amountValue:
|
||||
sendViewModel.pendingTransaction.amountFormatted,
|
||||
fiatAmountValue: sendViewModel.pendingTransactionFiatAmount
|
||||
+ ' ' + sendViewModel.fiat.title,
|
||||
fee: S.of(context).send_fee,
|
||||
feeValue: sendViewModel.pendingTransaction.feeFormatted,
|
||||
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmount
|
||||
+ ' ' + sendViewModel.fiat.title,
|
||||
recipientTitle: S.of(context).recipient_address,
|
||||
recipientAddress: sendViewModel.address,
|
||||
rightButtonText: S.of(context).ok,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
|
@ -614,96 +688,17 @@ class SendPage extends BasePage {
|
|||
}
|
||||
|
||||
if (state is TransactionCommitted) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Center(
|
||||
child: Image.asset(
|
||||
'assets/images/birthday_cake.png'),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 220, left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(context).send_success(
|
||||
sendViewModel.currency
|
||||
.toString()),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 24,
|
||||
right: 24,
|
||||
bottom: 24,
|
||||
child: PrimaryButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(),
|
||||
text: S.of(context).send_got_it,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.body2
|
||||
.color,
|
||||
textColor: Colors.white))
|
||||
],
|
||||
);
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: S.of(context).send_success(
|
||||
sendViewModel.currency
|
||||
.toString()),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () =>
|
||||
Navigator.of(context).pop());
|
||||
}
|
||||
|
||||
if (state is TransactionCommitting) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Center(
|
||||
child: Image.asset(
|
||||
'assets/images/birthday_cake.png'),
|
||||
),
|
||||
),
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.backgroundColor
|
||||
.withOpacity(0.25)),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 220),
|
||||
child: Text(
|
||||
S.of(context).send_sending,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Container();
|
||||
return Offstage();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
|
||||
|
||||
|
@ -6,8 +7,12 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
@required this.alertTitle,
|
||||
@required this.amount,
|
||||
@required this.amountValue,
|
||||
@required this.fiatAmountValue,
|
||||
@required this.fee,
|
||||
@required this.feeValue,
|
||||
@required this.feeFiatAmount,
|
||||
@required this.recipientTitle,
|
||||
@required this.recipientAddress,
|
||||
@required this.leftButtonText,
|
||||
@required this.rightButtonText,
|
||||
@required this.actionLeftButton,
|
||||
|
@ -18,8 +23,12 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
final String alertTitle;
|
||||
final String amount;
|
||||
final String amountValue;
|
||||
final String fiatAmountValue;
|
||||
final String fee;
|
||||
final String feeValue;
|
||||
final String feeFiatAmount;
|
||||
final String recipientTitle;
|
||||
final String recipientAddress;
|
||||
final String leftButtonText;
|
||||
final String rightButtonText;
|
||||
final VoidCallback actionLeftButton;
|
||||
|
@ -29,74 +38,145 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
|||
@override
|
||||
String get titleText => alertTitle;
|
||||
|
||||
@override
|
||||
bool get isDividerExists => true;
|
||||
|
||||
@override
|
||||
String get leftActionButtonText => leftButtonText;
|
||||
|
||||
@override
|
||||
String get rightActionButtonText => rightButtonText;
|
||||
|
||||
@override
|
||||
VoidCallback get actionLeft => actionLeftButton;
|
||||
|
||||
@override
|
||||
VoidCallback get actionRight => actionRightButton;
|
||||
|
||||
@override
|
||||
bool get barrierDismissible => alertBarrierDismissible;
|
||||
|
||||
@override
|
||||
Widget content(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
amount,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
amountValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
amountValue,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
fiatAmountValue,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: PaletteDark.pigeonBlue,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
fee,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 16),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
fee,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
feeValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
feeValue,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
feeFiatAmount,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: PaletteDark.pigeonBlue,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(8, 16, 8, 0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
recipientTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
recipientAddress,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Lato',
|
||||
color: PaletteDark.pigeonBlue,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
|
|
@ -1,82 +1,43 @@
|
|||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/trade_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
|
||||
class TradeDetailsPage extends BasePage {
|
||||
TradeDetailsPage(this.trade) : _items = [] {
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
_items.addAll([
|
||||
StandartListItem(title: S.current.trade_details_id, value: trade.id),
|
||||
StandartListItem(
|
||||
title: S.current.trade_details_state,
|
||||
value: trade.state != null
|
||||
? trade.state.toString()
|
||||
: S.current.trade_details_fetching)
|
||||
]);
|
||||
|
||||
if (trade.provider != null) {
|
||||
_items.add(StandartListItem(
|
||||
title: S.current.trade_details_provider,
|
||||
value: trade.provider.toString()));
|
||||
}
|
||||
|
||||
if (trade.createdAt != null) {
|
||||
_items.add(StandartListItem(
|
||||
title: S.current.trade_details_created_at,
|
||||
value: dateFormat.format(trade.createdAt).toString()));
|
||||
}
|
||||
|
||||
if (trade.from != null && trade.to != null) {
|
||||
_items.add(StandartListItem(
|
||||
title: S.current.trade_details_pair,
|
||||
value: '${trade.from.toString()} → ${trade.to.toString()}'));
|
||||
}
|
||||
}
|
||||
TradeDetailsPage(this.tradeDetailsViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.trade_details_title;
|
||||
|
||||
final Trade trade;
|
||||
final List<StandartListItem> _items;
|
||||
final TradeDetailsViewModel tradeDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(child: Observer(builder: (_) {
|
||||
return ListView.separated(
|
||||
separatorBuilder: (_, __) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.backgroundColor)),
|
||||
itemCount: _items.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final item = _items[index];
|
||||
final isDrawBottom = index == _items.length - 1 ? true : false;
|
||||
return Observer(builder: (_) {
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
itemCounter: (int _) => tradeDetailsViewModel.items.length,
|
||||
itemBuilder: (_, __, index) {
|
||||
final item = tradeDetailsViewModel.items[index];
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: '${item.value}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
showBar<void>(context, S
|
||||
.of(context)
|
||||
.copied_to_clipboard);
|
||||
},
|
||||
child: StandartListRow(
|
||||
title: '${item.title}',
|
||||
value: '${item.value}',
|
||||
isDrawBottom: isDrawBottom,
|
||||
title: '${item.title}',
|
||||
value: '${item.value}'
|
||||
));
|
||||
});
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
class StandartListItem {
|
||||
StandartListItem({this.title, this.value});
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
class StandartListItem extends TransactionDetailsListItem {
|
||||
StandartListItem({String title, String value})
|
||||
: super(title: title, value: value);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
|
||||
|
||||
class TextFieldListItem extends TransactionDetailsListItem {
|
||||
TextFieldListItem({String title, String value, this.onSubmitted})
|
||||
: super(title: title, value: value);
|
||||
|
||||
final Function(String value) onSubmitted;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
abstract class TransactionDetailsListItem {
|
||||
TransactionDetailsListItem({this.title, this.value});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
}
|
|
@ -1,107 +1,32 @@
|
|||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_info.dart';
|
||||
import 'package:cake_wallet/entities/transaction_info.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
class TransactionDetailsPage extends BasePage {
|
||||
TransactionDetailsPage(this.transactionInfo, bool showRecipientAddress,
|
||||
Box<TransactionDescription> transactionDescriptionBox)
|
||||
: _items = [] {
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
final tx = transactionInfo;
|
||||
|
||||
if (tx is MoneroTransactionInfo) {
|
||||
final items = [
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date,
|
||||
value: dateFormat.format(tx.date)),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_amount,
|
||||
value: tx.amountFormatted()),
|
||||
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
|
||||
];
|
||||
|
||||
if (tx.key?.isNotEmpty ?? null) {
|
||||
// FIXME: add translation
|
||||
items.add(StandartListItem(title: 'Transaction Key', value: tx.key));
|
||||
}
|
||||
|
||||
_items.addAll(items);
|
||||
}
|
||||
|
||||
if (tx is BitcoinTransactionInfo) {
|
||||
final items = [
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date,
|
||||
value: dateFormat.format(tx.date)),
|
||||
StandartListItem(
|
||||
title: 'Confirmations', value: tx.confirmations?.toString()),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_amount,
|
||||
value: tx.amountFormatted()),
|
||||
if (tx.feeFormatted()?.isNotEmpty)
|
||||
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
|
||||
];
|
||||
|
||||
_items.addAll(items);
|
||||
}
|
||||
|
||||
if (showRecipientAddress) {
|
||||
final recipientAddress = transactionDescriptionBox.values
|
||||
.firstWhere((val) => val.id == transactionInfo.id, orElse: () => null)
|
||||
?.recipientAddress;
|
||||
|
||||
if (recipientAddress?.isNotEmpty ?? false) {
|
||||
_items.add(StandartListItem(
|
||||
title: S.current.transaction_details_recipient_address,
|
||||
value: recipientAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
TransactionDetailsPage({this.transactionDetailsViewModel});
|
||||
|
||||
@override
|
||||
String get title => S.current.transaction_details_title;
|
||||
|
||||
final TransactionInfo transactionInfo;
|
||||
|
||||
final List<StandartListItem> _items;
|
||||
final TransactionDetailsViewModel transactionDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
child: ListView.separated(
|
||||
separatorBuilder: (context, index) => Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
),
|
||||
),
|
||||
itemCount: _items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _items[index];
|
||||
final isDrawBottom = index == _items.length - 1 ? true : false;
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
itemCounter: (int _) => transactionDetailsViewModel.items.length,
|
||||
itemBuilder: (_, __, index) {
|
||||
final item = transactionDetailsViewModel.items[index];
|
||||
|
||||
if (item is StandartListItem) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
|
@ -110,10 +35,19 @@ class TransactionDetailsPage extends BasePage {
|
|||
},
|
||||
child: StandartListRow(
|
||||
title: '${item.title}:',
|
||||
value: item.value,
|
||||
isDrawBottom: isDrawBottom),
|
||||
value: item.value),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (item is TextFieldListItem) {
|
||||
return TextFieldListRow(
|
||||
title: item.title,
|
||||
value: item.value,
|
||||
onSubmitted: item.onSubmitted,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class TextFieldListRow extends StatelessWidget {
|
||||
TextFieldListRow(
|
||||
{this.title,
|
||||
this.value,
|
||||
this.titleFontSize = 14,
|
||||
this.valueFontSize = 16,
|
||||
this.onSubmitted}) {
|
||||
|
||||
_textController = TextEditingController();
|
||||
_textController.text = value;
|
||||
}
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
final double titleFontSize;
|
||||
final double valueFontSize;
|
||||
final Function(String value) onSubmitted;
|
||||
|
||||
TextEditingController _textController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: titleFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme.overline.color),
|
||||
textAlign: TextAlign.left),
|
||||
TextField(
|
||||
controller: _textController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textInputAction: TextInputAction.done,
|
||||
maxLines: null,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme.title.color),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.only(top: 12, bottom: 0),
|
||||
hintText: S.of(context).enter_your_note,
|
||||
hintStyle: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme.overline.color),
|
||||
border: InputBorder.none
|
||||
),
|
||||
onSubmitted: (value) => onSubmitted.call(value),
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
String get contentText => '';
|
||||
String get leftActionButtonText => '';
|
||||
String get rightActionButtonText => '';
|
||||
bool get isDividerExists => false;
|
||||
VoidCallback get actionLeft => () {};
|
||||
VoidCallback get actionRight => () {};
|
||||
bool get barrierDismissible => true;
|
||||
|
@ -127,18 +128,27 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(24, 32, 24, 32),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
title(context),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
child: content(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 32, 24, 0),
|
||||
child: title(context),
|
||||
),
|
||||
isDividerExists
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 16, bottom: 8),
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 8, 24, 32),
|
||||
child: content(context),
|
||||
)
|
||||
],
|
||||
),
|
||||
Container(
|
||||
height: 1,
|
||||
|
|
|
@ -51,7 +51,7 @@ class BaseTextFormField extends StatelessWidget {
|
|||
final FocusNode focusNode;
|
||||
final bool readOnly;
|
||||
final bool enableInteractiveSelection;
|
||||
String initialValue;
|
||||
final String initialValue;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
|
@ -7,77 +7,60 @@ class StandartListRow extends StatelessWidget {
|
|||
this.value,
|
||||
this.titleFontSize = 14,
|
||||
this.valueFontSize = 16,
|
||||
this.image,
|
||||
this.isDrawBottom = false});
|
||||
this.image});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
final double titleFontSize;
|
||||
final double valueFontSize;
|
||||
final Image image;
|
||||
final bool isDrawBottom;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: titleFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.overline.color),
|
||||
textAlign: TextAlign.left),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(value,
|
||||
style: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color)),
|
||||
),
|
||||
image != null
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
child: image,
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: titleFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.overline.color),
|
||||
textAlign: TextAlign.left),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 12),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(value,
|
||||
style: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color)),
|
||||
),
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
isDrawBottom
|
||||
? Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
image != null
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
child: image,
|
||||
)
|
||||
: Offstage()
|
||||
],
|
||||
),
|
||||
)
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,11 @@ abstract class SettingsStoreBase with Store {
|
|||
(String languageCode) => sharedPreferences.setString(
|
||||
PreferencesKey.currentLanguageCode, languageCode));
|
||||
|
||||
reaction((_) => balanceDisplayMode,
|
||||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey,
|
||||
mode.serialize()));
|
||||
|
||||
this
|
||||
.nodes
|
||||
.observe((change) => _saveCurrentNode(change.newValue, change.key));
|
||||
|
@ -153,7 +158,7 @@ abstract class SettingsStoreBase with Store {
|
|||
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||
false;
|
||||
final legacyTheme =
|
||||
sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy)
|
||||
(sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
|
||||
? ThemeType.dark.index
|
||||
: ThemeType.bright.index;
|
||||
final savedTheme = ThemeList.deserialize(
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_balance.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/entities/balance.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/monero/monero_balance.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet.dart';
|
||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
|
||||
|
@ -18,8 +22,30 @@ abstract class BalanceViewModelBase with Store {
|
|||
BalanceViewModelBase(
|
||||
{@required this.appStore,
|
||||
@required this.settingsStore,
|
||||
@required this.fiatConvertationStore})
|
||||
: isReversing = false;
|
||||
@required this.fiatConvertationStore}) {
|
||||
isReversing = false;
|
||||
|
||||
wallet ??= appStore.wallet;
|
||||
|
||||
_reaction = reaction((_) => appStore.wallet, _onWalletChange);
|
||||
|
||||
final _wallet = wallet;
|
||||
|
||||
if (_wallet is MoneroWallet) {
|
||||
balance = _wallet.balance;
|
||||
}
|
||||
|
||||
if (_wallet is BitcoinWallet) {
|
||||
balance = _wallet.balance;
|
||||
}
|
||||
|
||||
_onCurrentWalletChangeReaction =
|
||||
reaction<void>((_) => wallet.balance, (dynamic balance) {
|
||||
if (balance is Balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final AppStore appStore;
|
||||
final SettingsStore settingsStore;
|
||||
|
@ -31,6 +57,12 @@ abstract class BalanceViewModelBase with Store {
|
|||
@observable
|
||||
bool isReversing;
|
||||
|
||||
@observable
|
||||
Balance balance;
|
||||
|
||||
@observable
|
||||
WalletBase wallet;
|
||||
|
||||
@computed
|
||||
double get price => fiatConvertationStore.prices[appStore.wallet.currency];
|
||||
|
||||
|
@ -47,24 +79,24 @@ abstract class BalanceViewModelBase with Store {
|
|||
@computed
|
||||
String get cryptoBalance {
|
||||
final walletBalance = _walletBalance;
|
||||
var balance = '---';
|
||||
var _balance = '---';
|
||||
|
||||
if (displayMode == BalanceDisplayMode.availableBalance) {
|
||||
balance = walletBalance.unlockedBalance ?? '0.0';
|
||||
_balance = walletBalance.unlockedBalance ?? '0.0';
|
||||
}
|
||||
|
||||
if (displayMode == BalanceDisplayMode.fullBalance) {
|
||||
balance = walletBalance.totalBalance ?? '0.0';
|
||||
_balance = walletBalance.totalBalance ?? '0.0';
|
||||
}
|
||||
|
||||
return balance;
|
||||
return _balance;
|
||||
}
|
||||
|
||||
@computed
|
||||
String get fiatBalance {
|
||||
final walletBalance = _walletBalance;
|
||||
final fiatCurrency = settingsStore.fiatCurrency;
|
||||
var balance = '---';
|
||||
var _balance = '---';
|
||||
|
||||
final totalBalance =
|
||||
_getFiatBalance(price: price, cryptoAmount: walletBalance.totalBalance);
|
||||
|
@ -73,30 +105,30 @@ abstract class BalanceViewModelBase with Store {
|
|||
price: price, cryptoAmount: walletBalance.unlockedBalance);
|
||||
|
||||
if (displayMode == BalanceDisplayMode.availableBalance) {
|
||||
balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00';
|
||||
_balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00';
|
||||
}
|
||||
|
||||
if (displayMode == BalanceDisplayMode.fullBalance) {
|
||||
balance = fiatCurrency.toString() + ' ' + totalBalance ?? '0.00';
|
||||
_balance = fiatCurrency.toString() + ' ' + totalBalance ?? '0.00';
|
||||
}
|
||||
|
||||
return balance;
|
||||
return _balance;
|
||||
}
|
||||
|
||||
@computed
|
||||
WalletBalance get _walletBalance {
|
||||
final _wallet = appStore.wallet;
|
||||
final _balance = balance;
|
||||
|
||||
if (_wallet is MoneroWallet) {
|
||||
if (_balance is MoneroBalance) {
|
||||
return WalletBalance(
|
||||
unlockedBalance: _wallet.balance.formattedUnlockedBalance,
|
||||
totalBalance: _wallet.balance.formattedFullBalance);
|
||||
unlockedBalance: _balance.formattedUnlockedBalance,
|
||||
totalBalance: _balance.formattedFullBalance);
|
||||
}
|
||||
|
||||
if (_wallet is BitcoinWallet) {
|
||||
if (_balance is BitcoinBalance) {
|
||||
return WalletBalance(
|
||||
unlockedBalance: _wallet.balance.availableBalanceFormatted,
|
||||
totalBalance: _wallet.balance.totalFormatted);
|
||||
unlockedBalance: _balance.availableBalanceFormatted,
|
||||
totalBalance: _balance.totalFormatted);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -105,6 +137,30 @@ abstract class BalanceViewModelBase with Store {
|
|||
@computed
|
||||
CryptoCurrency get currency => appStore.wallet.currency;
|
||||
|
||||
ReactionDisposer _onCurrentWalletChangeReaction;
|
||||
ReactionDisposer _reaction;
|
||||
|
||||
@action
|
||||
void _onWalletChange(WalletBase wallet) {
|
||||
this.wallet = wallet;
|
||||
|
||||
if (wallet is MoneroWallet) {
|
||||
balance = wallet.balance;
|
||||
}
|
||||
|
||||
if (wallet is BitcoinWallet) {
|
||||
balance = wallet.balance;
|
||||
}
|
||||
|
||||
_onCurrentWalletChangeReaction?.reaction?.dispose();
|
||||
_onCurrentWalletChangeReaction =
|
||||
reaction<void>((_) => wallet.balance, (dynamic balance) {
|
||||
if (balance is Balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String _getFiatBalance({double price, String cryptoAmount}) {
|
||||
if (cryptoAmount == null) {
|
||||
return '0.00';
|
||||
|
|
|
@ -231,6 +231,8 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
_onMoneroTransactionsUpdate(wallet);
|
||||
} else {
|
||||
subname = null;
|
||||
|
||||
transactions.clear();
|
||||
|
||||
transactions.addAll(wallet.transactionHistory.transactions.values.map(
|
||||
|
|
|
@ -39,20 +39,11 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
}
|
||||
|
||||
items = ObservableList<ExchangeTradeItem>();
|
||||
items.addAll([
|
||||
ExchangeTradeItem(
|
||||
title: S.current.id, data: '${trade.id}', isCopied: true),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.status, data: '${trade.state}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.widgets_address + ':',
|
||||
data: trade.inputAddress,
|
||||
isCopied: true),
|
||||
]);
|
||||
|
||||
_updateItems();
|
||||
|
||||
_updateTrade();
|
||||
|
||||
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
|
||||
}
|
||||
|
||||
|
@ -95,8 +86,27 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
}
|
||||
|
||||
trade = updatedTrade;
|
||||
|
||||
_updateItems();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void _updateItems() {
|
||||
items?.clear();
|
||||
|
||||
items.addAll([
|
||||
ExchangeTradeItem(
|
||||
title: S.current.id, data: '${trade.id}', isCopied: true),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.status, data: '${trade.state}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.widgets_address + ':',
|
||||
data: trade.inputAddress,
|
||||
isCopied: true),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/entities/crypto_currency.dart';
|
||||
import 'package:cake_wallet/entities/sync_status.dart';
|
||||
|
@ -7,6 +9,7 @@ import 'package:cake_wallet/exchange/limits.dart';
|
|||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits_state.dart';
|
||||
import 'package:cake_wallet/store/dashboard/trades_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -27,8 +30,8 @@ part 'exchange_view_model.g.dart';
|
|||
class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
|
||||
|
||||
abstract class ExchangeViewModelBase with Store {
|
||||
ExchangeViewModelBase(
|
||||
this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore) {
|
||||
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
|
||||
this.tradesStore, this._settingsStore) {
|
||||
providerList = [
|
||||
XMRTOExchangeProvider(),
|
||||
ChangeNowExchangeProvider(),
|
||||
|
@ -104,10 +107,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
@observable
|
||||
bool isReceiveAmountEntered;
|
||||
|
||||
Limits limits;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
@computed
|
||||
SyncStatus get status => wallet.syncStatus;
|
||||
|
||||
|
@ -115,6 +114,15 @@ abstract class ExchangeViewModelBase with Store {
|
|||
ObservableList<ExchangeTemplate> get templates =>
|
||||
_exchangeTemplateStore.templates;
|
||||
|
||||
bool get hasAllAmount =>
|
||||
wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency;
|
||||
|
||||
Limits limits;
|
||||
|
||||
NumberFormat _cryptoNumberFormat;
|
||||
|
||||
SettingsStore _settingsStore;
|
||||
|
||||
@action
|
||||
void changeProvider({ExchangeProvider provider}) {
|
||||
this.provider = provider;
|
||||
|
@ -264,9 +272,8 @@ abstract class ExchangeViewModelBase with Store {
|
|||
await trades.add(trade);
|
||||
tradeState = TradeIsCreatedSuccessfully(trade: trade);
|
||||
} catch (e) {
|
||||
tradeState = TradeIsCreatedFailure(
|
||||
title: provider.title,
|
||||
error: e.toString());
|
||||
tradeState =
|
||||
TradeIsCreatedFailure(title: provider.title, error: e.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -291,6 +298,22 @@ abstract class ExchangeViewModelBase with Store {
|
|||
_onPairChange();
|
||||
}
|
||||
|
||||
@action
|
||||
void calculateDepositAllAmount() {
|
||||
if (wallet is BitcoinWallet) {
|
||||
final availableBalance = wallet.balance.availableBalance as int;
|
||||
final fee = BitcoinWalletBase.feeAmountForPriority(
|
||||
_settingsStore.transactionPriority);
|
||||
|
||||
if (availableBalance < fee || availableBalance == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final amount = availableBalance - fee;
|
||||
changeDepositAmount(amount: bitcoinAmountToString(amount: amount));
|
||||
}
|
||||
}
|
||||
|
||||
void updateTemplate() => _exchangeTemplateStore.update();
|
||||
|
||||
void addTemplate(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
@ -37,6 +38,7 @@ abstract class SendViewModelBase with Store {
|
|||
this._fiatConversationStore, this.transactionDescriptionBox)
|
||||
: state = InitialExecutionState(),
|
||||
_cryptoNumberFormat = NumberFormat(),
|
||||
note = '',
|
||||
sendAll = false {
|
||||
final _priority = _settingsStore.transactionPriority;
|
||||
|
||||
|
@ -60,6 +62,9 @@ abstract class SendViewModelBase with Store {
|
|||
@observable
|
||||
String address;
|
||||
|
||||
@observable
|
||||
String note;
|
||||
|
||||
@observable
|
||||
bool sendAll;
|
||||
|
||||
|
@ -67,6 +72,50 @@ abstract class SendViewModelBase with Store {
|
|||
double get estimatedFee =>
|
||||
_wallet.calculateEstimatedFee(_settingsStore.transactionPriority);
|
||||
|
||||
@computed
|
||||
String get estimatedFeeFiatAmount {
|
||||
try {
|
||||
final fiat = calculateFiatAmountRaw(
|
||||
price: _fiatConversationStore.prices[_wallet.currency],
|
||||
cryptoAmount: estimatedFee);
|
||||
return fiat;
|
||||
} catch (_) {
|
||||
return '0.00';
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFiatAmount {
|
||||
try {
|
||||
if (pendingTransaction != null) {
|
||||
final fiat = calculateFiatAmount(
|
||||
price: _fiatConversationStore.prices[_wallet.currency],
|
||||
cryptoAmount: pendingTransaction.amountFormatted);
|
||||
return fiat;
|
||||
} else {
|
||||
return '0.00';
|
||||
}
|
||||
} catch (_) {
|
||||
return '0.00';
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFeeFiatAmount {
|
||||
try {
|
||||
if (pendingTransaction != null) {
|
||||
final fiat = calculateFiatAmount(
|
||||
price: _fiatConversationStore.prices[_wallet.currency],
|
||||
cryptoAmount: pendingTransaction.feeFormatted);
|
||||
return fiat;
|
||||
} else {
|
||||
return '0.00';
|
||||
}
|
||||
} catch (_) {
|
||||
return '0.00';
|
||||
}
|
||||
}
|
||||
|
||||
FiatCurrency get fiat => _settingsStore.fiatCurrency;
|
||||
|
||||
TransactionPriority get transactionPriority =>
|
||||
|
@ -112,6 +161,7 @@ abstract class SendViewModelBase with Store {
|
|||
cryptoAmount = '';
|
||||
fiatAmount = '';
|
||||
address = '';
|
||||
note = '';
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -131,10 +181,13 @@ abstract class SendViewModelBase with Store {
|
|||
state = TransactionCommitting();
|
||||
await pendingTransaction.commit();
|
||||
|
||||
if (_settingsStore.shouldSaveRecipientAddress &&
|
||||
(pendingTransaction.id?.isNotEmpty ?? false)) {
|
||||
await transactionDescriptionBox.add(TransactionDescription(
|
||||
id: pendingTransaction.id, recipientAddress: address));
|
||||
if (pendingTransaction.id?.isNotEmpty ?? false) {
|
||||
_settingsStore.shouldSaveRecipientAddress
|
||||
? await transactionDescriptionBox.add(TransactionDescription(
|
||||
id: pendingTransaction.id, recipientAddress: address,
|
||||
transactionNote: note))
|
||||
: await transactionDescriptionBox.add(TransactionDescription(
|
||||
id: pendingTransaction.id, transactionNote: note));
|
||||
}
|
||||
|
||||
state = TransactionCommitted();
|
||||
|
@ -204,7 +257,7 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
switch (_wallet.type) {
|
||||
case WalletType.bitcoin:
|
||||
final amount = !sendAll ? double.parse(_amount) : null;
|
||||
final amount = !sendAll ? _amount : null;
|
||||
|
||||
return BitcoinTransactionCredentials(
|
||||
address, amount, _settingsStore.transactionPriority);
|
||||
|
|
105
lib/view_model/trade_details_view_model.dart
Normal file
105
lib/view_model/trade_details_view_model.dart
Normal file
|
@ -0,0 +1,105 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
|
||||
part 'trade_details_view_model.g.dart';
|
||||
|
||||
class TradeDetailsViewModel = TradeDetailsViewModelBase
|
||||
with _$TradeDetailsViewModel;
|
||||
|
||||
abstract class TradeDetailsViewModelBase with Store {
|
||||
TradeDetailsViewModelBase({Trade tradeForDetails, this.trades}) {
|
||||
trade = tradeForDetails;
|
||||
|
||||
switch (trade.provider) {
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
_provider = XMRTOExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.changeNow:
|
||||
_provider = ChangeNowExchangeProvider();
|
||||
break;
|
||||
case ExchangeProviderDescription.morphToken:
|
||||
_provider = MorphTokenExchangeProvider(trades: trades);
|
||||
break;
|
||||
}
|
||||
|
||||
items = ObservableList<StandartListItem>();
|
||||
|
||||
_updateItems();
|
||||
|
||||
_updateTrade();
|
||||
|
||||
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
|
||||
}
|
||||
|
||||
final Box<Trade> trades;
|
||||
|
||||
@observable
|
||||
Trade trade;
|
||||
|
||||
@observable
|
||||
ObservableList<StandartListItem> items;
|
||||
|
||||
ExchangeProvider _provider;
|
||||
|
||||
Timer _timer;
|
||||
|
||||
@action
|
||||
Future<void> _updateTrade() async {
|
||||
try {
|
||||
final updatedTrade = await _provider.findTradeById(id: trade.id);
|
||||
|
||||
if (updatedTrade.createdAt == null && trade.createdAt != null) {
|
||||
updatedTrade.createdAt = trade.createdAt;
|
||||
}
|
||||
|
||||
trade = updatedTrade;
|
||||
|
||||
_updateItems();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void _updateItems() {
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
|
||||
items?.clear();
|
||||
|
||||
items.addAll([
|
||||
StandartListItem(title: S.current.trade_details_id, value: trade.id),
|
||||
StandartListItem(
|
||||
title: S.current.trade_details_state,
|
||||
value: trade.state != null
|
||||
? trade.state.toString()
|
||||
: S.current.trade_details_fetching)
|
||||
]);
|
||||
|
||||
if (trade.provider != null) {
|
||||
items.add(StandartListItem(
|
||||
title: S.current.trade_details_provider,
|
||||
value: trade.provider.toString()));
|
||||
}
|
||||
|
||||
if (trade.createdAt != null) {
|
||||
items.add(StandartListItem(
|
||||
title: S.current.trade_details_created_at,
|
||||
value: dateFormat.format(trade.createdAt).toString()));
|
||||
}
|
||||
|
||||
if (trade.from != null && trade.to != null) {
|
||||
items.add(StandartListItem(
|
||||
title: S.current.trade_details_pair,
|
||||
value: '${trade.from.toString()} → ${trade.to.toString()}'));
|
||||
}
|
||||
}
|
||||
}
|
114
lib/view_model/transaction_details_view_model.dart
Normal file
114
lib/view_model/transaction_details_view_model.dart
Normal file
|
@ -0,0 +1,114 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
|
||||
import 'package:cake_wallet/entities/transaction_info.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_info.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
part 'transaction_details_view_model.g.dart';
|
||||
|
||||
class TransactionDetailsViewModel = TransactionDetailsViewModelBase
|
||||
with _$TransactionDetailsViewModel;
|
||||
|
||||
abstract class TransactionDetailsViewModelBase with Store {
|
||||
TransactionDetailsViewModelBase(
|
||||
{this.transactionInfo,
|
||||
this.transactionDescriptionBox,
|
||||
this.settingsStore})
|
||||
: items = [] {
|
||||
showRecipientAddress = settingsStore?.shouldSaveRecipientAddress ?? false;
|
||||
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
final tx = transactionInfo;
|
||||
|
||||
if (tx is MoneroTransactionInfo) {
|
||||
final _items = [
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date,
|
||||
value: dateFormat.format(tx.date)),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_amount,
|
||||
value: tx.amountFormatted()),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_fee, value: tx.feeFormatted()),
|
||||
];
|
||||
|
||||
if (tx.key?.isNotEmpty ?? null) {
|
||||
_items.add(
|
||||
StandartListItem(title: S.current.transaction_key, value: tx.key));
|
||||
}
|
||||
|
||||
items.addAll(_items);
|
||||
}
|
||||
|
||||
if (tx is BitcoinTransactionInfo) {
|
||||
final _items = [
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date,
|
||||
value: dateFormat.format(tx.date)),
|
||||
StandartListItem(
|
||||
title: S.current.confirmations,
|
||||
value: tx.confirmations?.toString()),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_amount,
|
||||
value: tx.amountFormatted()),
|
||||
if (tx.feeFormatted()?.isNotEmpty)
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_fee,
|
||||
value: tx.feeFormatted())
|
||||
];
|
||||
|
||||
items.addAll(_items);
|
||||
}
|
||||
|
||||
if (showRecipientAddress) {
|
||||
final recipientAddress = transactionDescriptionBox.values
|
||||
.firstWhere((val) => val.id == transactionInfo.id, orElse: () => null)
|
||||
?.recipientAddress;
|
||||
|
||||
if (recipientAddress?.isNotEmpty ?? false) {
|
||||
items.add(StandartListItem(
|
||||
title: S.current.transaction_details_recipient_address,
|
||||
value: recipientAddress));
|
||||
}
|
||||
}
|
||||
|
||||
final description = transactionDescriptionBox.values.firstWhere(
|
||||
(val) => val.id == transactionInfo.id,
|
||||
orElse: () => TransactionDescription(id: transactionInfo.id));
|
||||
|
||||
items.add(TextFieldListItem(
|
||||
title: S.current.note_tap_to_change,
|
||||
value: description.note,
|
||||
onSubmitted: (value) {
|
||||
description.transactionNote = value;
|
||||
|
||||
if (description.isInBox) {
|
||||
description.save();
|
||||
} else {
|
||||
transactionDescriptionBox.add(description);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
final TransactionInfo transactionInfo;
|
||||
final Box<TransactionDescription> transactionDescriptionBox;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
final List<TransactionDetailsListItem> items;
|
||||
bool showRecipientAddress;
|
||||
}
|
|
@ -11,7 +11,7 @@ description: Cake Wallet.
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 4.1.0+26
|
||||
version: 4.1.0+28
|
||||
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Name",
|
||||
"send_got_it" : "Ich habs",
|
||||
"send_sending" : "Senden...",
|
||||
"send_success" : "Ihr Monero wurde erfolgreich gesendet",
|
||||
"send_success" : "Ihr ${crypto} wurde erfolgreich gesendet",
|
||||
|
||||
|
||||
"settings_title" : "die Einstellungen",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Datum",
|
||||
"transaction_details_height" : "Höhe",
|
||||
"transaction_details_amount" : "Menge",
|
||||
"transaction_details_fee" : "Gebühr",
|
||||
"transaction_details_copied" : "${title} in die Zwischenablage kopiert",
|
||||
"transaction_details_recipient_address" : "Empfängeradresse",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Bitte warten Sie, bis Ihre Brieftasche synchronisiert ist",
|
||||
|
||||
"pre_seed_title" : "WICHTIG",
|
||||
"pre_seed_description" : "Auf der nächsten Seite sehen Sie eine Reihe von 25 Wörtern. Dies ist Ihr einzigartiger und privater Samen und der EINZIGE Weg, um Ihren Geldbeutel im Falle eines Verlusts oder einer Fehlfunktion wiederherzustellen. Es liegt in IHRER Verantwortung, es aufzuschreiben und an einem sicheren Ort außerhalb der Cake Wallet App aufzubewahren.",
|
||||
"pre_seed_description" : "Auf der nächsten Seite sehen Sie eine Reihe von ${words} Wörtern. Dies ist Ihr einzigartiger und privater Samen und der EINZIGE Weg, um Ihren Geldbeutel im Falle eines Verlusts oder einer Fehlfunktion wiederherzustellen. Es liegt in IHRER Verantwortung, es aufzuschreiben und an einem sicheren Ort außerhalb der Cake Wallet App aufzubewahren.",
|
||||
"pre_seed_button_text" : "Ich verstehe. Zeig mir meinen Samen",
|
||||
|
||||
"xmr_to_error" : "XMR.TO-Fehler",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Farbthema",
|
||||
"light_theme" : "Licht",
|
||||
"bright_theme" : "Hell",
|
||||
"dark_theme" : "Dunkel"
|
||||
"dark_theme" : "Dunkel",
|
||||
"enter_your_note" : "Geben Sie Ihre Notiz ein…",
|
||||
"note_optional" : "Hinweis (optional)",
|
||||
"note_tap_to_change" : "Hinweis (zum Ändern tippen)",
|
||||
"transaction_key" : "Transaktionsschlüssel",
|
||||
"confirmations" : "Bestätigungen",
|
||||
"recipient_address" : "Empfängeradresse"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Name",
|
||||
"send_got_it" : "Got it",
|
||||
"send_sending" : "Sending...",
|
||||
"send_success" : "Your Monero was successfully sent",
|
||||
"send_success" : "Your ${crypto} was successfully sent",
|
||||
|
||||
|
||||
"settings_title" : "Settings",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Date",
|
||||
"transaction_details_height" : "Height",
|
||||
"transaction_details_amount" : "Amount",
|
||||
"transaction_details_fee" : "Fee",
|
||||
"transaction_details_copied" : "${title} copied to Clipboard",
|
||||
"transaction_details_recipient_address" : "Recipient address",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Please wait until your wallet is synchronized",
|
||||
|
||||
"pre_seed_title" : "IMPORTANT",
|
||||
"pre_seed_description" : "On the next page you will see a series of 25 words. This is your unique and private seed and it is the ONLY way to recover your wallet in case of loss or malfunction. It is YOUR responsibility to write it down and store it in a safe place outside of the Cake Wallet app.",
|
||||
"pre_seed_description" : "On the next page you will see a series of ${words} words. This is your unique and private seed and it is the ONLY way to recover your wallet in case of loss or malfunction. It is YOUR responsibility to write it down and store it in a safe place outside of the Cake Wallet app.",
|
||||
"pre_seed_button_text" : "I understand. Show me my seed",
|
||||
|
||||
"xmr_to_error" : "XMR.TO error",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Color theme",
|
||||
"light_theme" : "Light",
|
||||
"bright_theme" : "Bright",
|
||||
"dark_theme" : "Dark"
|
||||
"dark_theme" : "Dark",
|
||||
"enter_your_note" : "Enter your note…",
|
||||
"note_optional" : "Note (optional)",
|
||||
"note_tap_to_change" : "Note (tap to change)",
|
||||
"transaction_key" : "Transaction Key",
|
||||
"confirmations" : "Confirmations",
|
||||
"recipient_address" : "Recipient address"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Nombre",
|
||||
"send_got_it" : "Entendido",
|
||||
"send_sending" : "Enviando...",
|
||||
"send_success" : "Su Monero fue enviado con éxito",
|
||||
"send_success" : "Su ${crypto} fue enviado con éxito",
|
||||
|
||||
|
||||
"settings_title" : "Configuraciones",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Fecha",
|
||||
"transaction_details_height" : "Altura",
|
||||
"transaction_details_amount" : "Cantidad",
|
||||
"transaction_details_fee" : "Cuota",
|
||||
"transaction_details_copied" : "${title} Copiado al portapapeles",
|
||||
"transaction_details_recipient_address" : "Dirección del receptor",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Espere hasta que su billetera esté sincronizada",
|
||||
|
||||
"pre_seed_title" : "IMPORTANTE",
|
||||
"pre_seed_description" : "En la página siguiente verá una serie de 25 palabras. Esta es su semilla única y privada y es la ÚNICA forma de recuperar su billetera en caso de pérdida o mal funcionamiento. Es SU responsabilidad escribirlo y guardarlo en un lugar seguro fuera de la aplicación Cake Wallet.",
|
||||
"pre_seed_description" : "En la página siguiente verá una serie de ${words} palabras. Esta es su semilla única y privada y es la ÚNICA forma de recuperar su billetera en caso de pérdida o mal funcionamiento. Es SU responsabilidad escribirlo y guardarlo en un lugar seguro fuera de la aplicación Cake Wallet.",
|
||||
"pre_seed_button_text" : "Entiendo. Muéstrame mi semilla",
|
||||
|
||||
"xmr_to_error" : "Error de XMR.TO",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Tema de color",
|
||||
"light_theme" : "Ligera",
|
||||
"bright_theme" : "Brillante",
|
||||
"dark_theme" : "Oscura"
|
||||
"dark_theme" : "Oscura",
|
||||
"enter_your_note" : "Ingresa tu nota…",
|
||||
"note_optional" : "Nota (opcional)",
|
||||
"note_tap_to_change" : "Nota (toque para cambiar)",
|
||||
"transaction_key" : "Clave de transacción",
|
||||
"confirmations" : "Confirmaciones",
|
||||
"recipient_address" : "Dirección del receptor"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "नाम",
|
||||
"send_got_it" : "समझ गया",
|
||||
"send_sending" : "भेजना...",
|
||||
"send_success" : "आपका Monero सफलतापूर्वक भेजा गया",
|
||||
"send_success" : "आपका ${crypto} सफलतापूर्वक भेजा गया",
|
||||
|
||||
|
||||
"settings_title" : "सेटिंग्स",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "तारीख",
|
||||
"transaction_details_height" : "ऊंचाई",
|
||||
"transaction_details_amount" : "रकम",
|
||||
"transaction_details_fee" : "शुल्क",
|
||||
"transaction_details_copied" : "${title} क्लिपबोर्ड पर नकल",
|
||||
"transaction_details_recipient_address" : "प्राप्तकर्ता का पता",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "कृपया प्रतीक्षा करें जब तक आपका बटुआ सिंक्रनाइज़ नहीं किया जाता है",
|
||||
|
||||
"pre_seed_title" : "महत्वपूर्ण",
|
||||
"pre_seed_description" : "अगले पेज पर आपको 25 शब्दों की एक श्रृंखला दिखाई देगी। यह आपका अद्वितीय और निजी बीज है और नुकसान या खराबी के मामले में अपने बटुए को पुनर्प्राप्त करने का एकमात्र तरीका है। यह आपकी जिम्मेदारी है कि इसे नीचे लिखें और इसे Cake Wallet ऐप के बाहर सुरक्षित स्थान पर संग्रहीत करें।",
|
||||
"pre_seed_description" : "अगले पेज पर आपको ${words} शब्दों की एक श्रृंखला दिखाई देगी। यह आपका अद्वितीय और निजी बीज है और नुकसान या खराबी के मामले में अपने बटुए को पुनर्प्राप्त करने का एकमात्र तरीका है। यह आपकी जिम्मेदारी है कि इसे नीचे लिखें और इसे Cake Wallet ऐप के बाहर सुरक्षित स्थान पर संग्रहीत करें।",
|
||||
"pre_seed_button_text" : "मै समझता हुँ। मुझे अपना बीज दिखाओ",
|
||||
|
||||
"xmr_to_error" : "XMR.TO त्रुटि",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "रंग विषय",
|
||||
"light_theme" : "रोशनी",
|
||||
"bright_theme" : "उज्ज्वल",
|
||||
"dark_theme" : "अंधेरा"
|
||||
"dark_theme" : "अंधेरा",
|
||||
"enter_your_note" : "अपना नोट दर्ज करें ...",
|
||||
"note_optional" : "नोट (वैकल्पिक)",
|
||||
"note_tap_to_change" : "नोट (टैप टू चेंज)",
|
||||
"transaction_key" : "लेन-देन की",
|
||||
"confirmations" : "पुष्टिकरण",
|
||||
"recipient_address" : "प्राप्तकर्ता का पता"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "名前",
|
||||
"send_got_it" : "とった",
|
||||
"send_sending" : "送信...",
|
||||
"send_success" : "Moneroが送信されました",
|
||||
"send_success" : "${crypto}が送信されました",
|
||||
|
||||
|
||||
"settings_title" : "設定",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "日付",
|
||||
"transaction_details_height" : "高さ",
|
||||
"transaction_details_amount" : "量",
|
||||
"transaction_details_fee" : "費用",
|
||||
"transaction_details_copied" : "${title} クリップボードにコピーしました",
|
||||
"transaction_details_recipient_address" : "受取人の住所",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "ウォレットが同期されるまでお待ちください",
|
||||
|
||||
"pre_seed_title" : "重要",
|
||||
"pre_seed_description" : "次のページでは、一連の25語が表示されます。 これはあなたのユニークでプライベートなシードであり、紛失や誤動作が発生した場合にウォレットを回復する唯一の方法です。 それを書き留めて、Cake Wallet アプリの外の安全な場所に保管するのはあなたの責任です。",
|
||||
"pre_seed_description" : "次のページでは、一連の${words}語が表示されます。 これはあなたのユニークでプライベートなシードであり、紛失や誤動作が発生した場合にウォレットを回復する唯一の方法です。 それを書き留めて、Cake Wallet アプリの外の安全な場所に保管するのはあなたの責任です。",
|
||||
"pre_seed_button_text" : "わかります。 種を見せて",
|
||||
|
||||
"xmr_to_error" : "XMR.TOエラー",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "カラーテーマ",
|
||||
"light_theme" : "光",
|
||||
"bright_theme" : "明るい",
|
||||
"dark_theme" : "闇"
|
||||
"dark_theme" : "闇",
|
||||
"enter_your_note" : "メモを入力してください…",
|
||||
"note_optional" : "注(オプション)",
|
||||
"note_tap_to_change" : "注(タップして変更)",
|
||||
"transaction_key" : "トランザクションキー",
|
||||
"confirmations" : "確認",
|
||||
"recipient_address" : "受信者のアドレス"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "이름",
|
||||
"send_got_it" : "알았다",
|
||||
"send_sending" : "배상...",
|
||||
"send_success" : "Monero가 성공적으로 전송되었습니다",
|
||||
"send_success" : "${crypto}가 성공적으로 전송되었습니다",
|
||||
|
||||
|
||||
"settings_title" : "설정",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "날짜",
|
||||
"transaction_details_height" : "신장",
|
||||
"transaction_details_amount" : "양",
|
||||
"transaction_details_fee" : "회비",
|
||||
"transaction_details_copied" : "${title} 클립 보드에 복사",
|
||||
"transaction_details_recipient_address" : "받는 사람 주소",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "지갑이 동기화 될 때까지 기다리십시오",
|
||||
|
||||
"pre_seed_title" : "중대한",
|
||||
"pre_seed_description" : "다음 페이지에서 25 개의 단어를 볼 수 있습니다. 이것은 귀하의 고유하고 개인적인 시드이며 분실 또는 오작동시 지갑을 복구하는 유일한 방법입니다. 기록해두고 Cake Wallet 앱 외부의 안전한 장소에 보관하는 것은 귀하의 책임입니다.",
|
||||
"pre_seed_description" : "다음 페이지에서 ${words} 개의 단어를 볼 수 있습니다. 이것은 귀하의 고유하고 개인적인 시드이며 분실 또는 오작동시 지갑을 복구하는 유일한 방법입니다. 기록해두고 Cake Wallet 앱 외부의 안전한 장소에 보관하는 것은 귀하의 책임입니다.",
|
||||
"pre_seed_button_text" : "이해 했어요. 내 씨앗을 보여줘",
|
||||
|
||||
"xmr_to_error" : "XMR.TO 오류",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "색상 테마",
|
||||
"light_theme" : "빛",
|
||||
"bright_theme" : "선명한",
|
||||
"dark_theme" : "어두운"
|
||||
"dark_theme" : "어두운",
|
||||
"enter_your_note" : "메모를 입력하세요…",
|
||||
"note_optional" : "참고 (선택 사항)",
|
||||
"note_tap_to_change" : "메모 (변경하려면 탭하세요)",
|
||||
"transaction_key" : "거래 키",
|
||||
"confirmations" : "확인",
|
||||
"recipient_address" : "받는 사람 주소"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Naam",
|
||||
"send_got_it" : "Ik snap het",
|
||||
"send_sending" : "Bezig met verzenden...",
|
||||
"send_success" : "Uw Monero is succesvol verzonden",
|
||||
"send_success" : "Uw ${crypto} is succesvol verzonden",
|
||||
|
||||
|
||||
"settings_title" : "Instellingen",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Datum",
|
||||
"transaction_details_height" : "Hoogte",
|
||||
"transaction_details_amount" : "Bedrag",
|
||||
"transaction_details_fee" : "Vergoeding",
|
||||
"transaction_details_copied" : "${title} gekopieerd naar het klembord",
|
||||
"transaction_details_recipient_address" : "Adres van de ontvanger",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Wacht tot uw portemonnee is gesynchroniseerd",
|
||||
|
||||
"pre_seed_title" : "BELANGRIJK",
|
||||
"pre_seed_description" : "Op de volgende pagina ziet u een reeks van 25 woorden. Dit is uw unieke en persoonlijke zaadje en het is de ENIGE manier om uw portemonnee te herstellen in geval van verlies of storing. Het is JOUW verantwoordelijkheid om het op te schrijven en op een veilige plaats op te slaan buiten de Cake Wallet app.",
|
||||
"pre_seed_description" : "Op de volgende pagina ziet u een reeks van ${words} woorden. Dit is uw unieke en persoonlijke zaadje en het is de ENIGE manier om uw portemonnee te herstellen in geval van verlies of storing. Het is JOUW verantwoordelijkheid om het op te schrijven en op een veilige plaats op te slaan buiten de Cake Wallet app.",
|
||||
"pre_seed_button_text" : "Ik begrijp het. Laat me mijn zaad zien",
|
||||
|
||||
"xmr_to_error" : "XMR.TO-fout",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Kleur thema",
|
||||
"light_theme" : "Licht",
|
||||
"bright_theme" : "Helder",
|
||||
"dark_theme" : "Donker"
|
||||
"dark_theme" : "Donker",
|
||||
"enter_your_note" : "Voer uw notitie in ...",
|
||||
"note_optional" : "Opmerking (optioneel)",
|
||||
"note_tap_to_change" : "Opmerking (tik om te wijzigen)",
|
||||
"transaction_key" : "Transactiesleutel",
|
||||
"confirmations" : "Bevestigingen",
|
||||
"recipient_address" : "Adres ontvanger"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Imię",
|
||||
"send_got_it" : "Rozumiem",
|
||||
"send_sending" : "Wysyłanie...",
|
||||
"send_success" : "Twoje Monero zostało pomyślnie wysłane",
|
||||
"send_success" : "Twoje ${crypto} zostało pomyślnie wysłane",
|
||||
|
||||
|
||||
"settings_title" : "Ustawienia",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Data",
|
||||
"transaction_details_height" : "Wysokość",
|
||||
"transaction_details_amount" : "Ilość",
|
||||
"transaction_details_fee" : "Opłata",
|
||||
"transaction_details_copied" : "${title} skopiowane do schowka",
|
||||
"transaction_details_recipient_address" : "Adres odbiorcy",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Poczekaj, aż portfel zostanie zsynchronizowany",
|
||||
|
||||
"pre_seed_title" : "WAŻNY",
|
||||
"pre_seed_description" : "Na następnej stronie zobaczysz serię 25 słów. To jest Twoje unikalne i prywatne ziarno i jest to JEDYNY sposób na odzyskanie portfela w przypadku utraty lub awarii. Twoim obowiązkiem jest zapisanie go i przechowywanie w bezpiecznym miejscu poza aplikacją Cake Wallet.",
|
||||
"pre_seed_description" : "Na następnej stronie zobaczysz serię ${words} słów. To jest Twoje unikalne i prywatne ziarno i jest to JEDYNY sposób na odzyskanie portfela w przypadku utraty lub awarii. Twoim obowiązkiem jest zapisanie go i przechowywanie w bezpiecznym miejscu poza aplikacją Cake Wallet.",
|
||||
"pre_seed_button_text" : "Rozumiem. Pokaż mi moje nasienie",
|
||||
|
||||
"xmr_to_error" : "Pomyłka XMR.TO",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Motyw kolorystyczny",
|
||||
"light_theme" : "Lekki",
|
||||
"bright_theme" : "Jasny",
|
||||
"dark_theme" : "Ciemny"
|
||||
"dark_theme" : "Ciemny",
|
||||
"enter_your_note" : "Wpisz notatkę…",
|
||||
"note_optional" : "Notatka (opcjonalnie)",
|
||||
"note_tap_to_change" : "Notatka (dotknij, aby zmienić)",
|
||||
"transaction_key" : "Klucz transakcji",
|
||||
"confirmations" : "Potwierdzenia",
|
||||
"recipient_address" : "Adres odbiorcy"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Nome",
|
||||
"send_got_it" : "Entendi",
|
||||
"send_sending" : "Enviando...",
|
||||
"send_success" : "Seu Monero foi enviado com sucesso",
|
||||
"send_success" : "Seu ${crypto} foi enviado com sucesso",
|
||||
|
||||
|
||||
"settings_title" : "Configurações",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Data",
|
||||
"transaction_details_height" : "Altura",
|
||||
"transaction_details_amount" : "Quantia",
|
||||
"transaction_details_fee" : "Taxa",
|
||||
"transaction_details_copied" : "${title} copiados para a área de transferência",
|
||||
"transaction_details_recipient_address" : "Endereço do destinatário",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Por favor, espere até que sua carteira seja sincronizada",
|
||||
|
||||
"pre_seed_title" : "IMPORTANTE",
|
||||
"pre_seed_description" : "Na próxima página, você verá uma série de 25 palavras. Esta é a sua semente única e privada e é a ÚNICA maneira de recuperar sua carteira em caso de perda ou mau funcionamento. É SUA responsabilidade anotá-lo e armazená-lo em um local seguro fora do aplicativo Cake Wallet.",
|
||||
"pre_seed_description" : "Na próxima página, você verá uma série de ${words} palavras. Esta é a sua semente única e privada e é a ÚNICA maneira de recuperar sua carteira em caso de perda ou mau funcionamento. É SUA responsabilidade anotá-lo e armazená-lo em um local seguro fora do aplicativo Cake Wallet.",
|
||||
"pre_seed_button_text" : "Compreendo. Me mostre minha semente",
|
||||
|
||||
"xmr_to_error" : "Erro XMR.TO",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Tema de cor",
|
||||
"light_theme" : "Luz",
|
||||
"bright_theme" : "Brilhante",
|
||||
"dark_theme" : "Sombria"
|
||||
"dark_theme" : "Sombria",
|
||||
"enter_your_note" : "Insira sua nota ...",
|
||||
"note_optional" : "Nota (opcional)",
|
||||
"note_tap_to_change" : "Nota (toque para alterar)",
|
||||
"transaction_key" : "Chave de transação",
|
||||
"confirmations" : "Confirmações",
|
||||
"recipient_address" : "Endereço do destinatário"
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Имя",
|
||||
"send_got_it" : "Понял",
|
||||
"send_sending" : "Отправка...",
|
||||
"send_success" : "Ваш Monero был успешно отправлен",
|
||||
"send_success" : "Ваш ${crypto} был успешно отправлен",
|
||||
|
||||
|
||||
"settings_title" : "Настройки",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Дата",
|
||||
"transaction_details_height" : "Высота",
|
||||
"transaction_details_amount" : "Сумма",
|
||||
"transaction_details_fee" : "Комиссия",
|
||||
"transaction_details_copied" : "${title} скопировано в буфер обмена",
|
||||
"transaction_details_recipient_address" : "Адрес получателя",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Подождите, пока ваш кошелек синхронизируется",
|
||||
|
||||
"pre_seed_title" : "ВАЖНО",
|
||||
"pre_seed_description" : "На следующей странице вы увидите серию из 25 слов. Это ваша уникальная и личная мнемоническая фраза, и это ЕДИНСТВЕННЫЙ способ восстановить свой кошелек в случае потери или неисправности. ВАМ необходимо записать ее и хранить в надежном месте вне приложения Cake Wallet.",
|
||||
"pre_seed_description" : "На следующей странице вы увидите серию из ${words} слов. Это ваша уникальная и личная мнемоническая фраза, и это ЕДИНСТВЕННЫЙ способ восстановить свой кошелек в случае потери или неисправности. ВАМ необходимо записать ее и хранить в надежном месте вне приложения Cake Wallet.",
|
||||
"pre_seed_button_text" : "Понятно. Покажите мнемоническую фразу",
|
||||
|
||||
"xmr_to_error" : "Ошибка XMR.TO",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Цветовая тема",
|
||||
"light_theme" : "Светлая",
|
||||
"bright_theme" : "Яркая",
|
||||
"dark_theme" : "Темная"
|
||||
"dark_theme" : "Темная",
|
||||
"enter_your_note" : "Введите примечание…",
|
||||
"note_optional" : "Примечание (необязательно)",
|
||||
"note_tap_to_change" : "Примечание (нажмите для изменения)",
|
||||
"transaction_key" : "Ключ транзакции",
|
||||
"confirmations" : "Подтверждения",
|
||||
"recipient_address" : "Адрес получателя"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "Ім'я",
|
||||
"send_got_it" : "Зрозумів",
|
||||
"send_sending" : "Відправлення...",
|
||||
"send_success" : "Ваш Monero успішно надісланий",
|
||||
"send_success" : "Ваш ${crypto} успішно надісланий",
|
||||
|
||||
|
||||
"settings_title" : "Налаштування",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "Дата",
|
||||
"transaction_details_height" : "Висота",
|
||||
"transaction_details_amount" : "Сума",
|
||||
"transaction_details_fee" : "Комісія",
|
||||
"transaction_details_copied" : "${title} скопійовано в буфер обміну",
|
||||
"transaction_details_recipient_address" : "Адреса отримувача",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "Зачекайте, поки ваш гаманець не синхронізується",
|
||||
|
||||
"pre_seed_title" : "ВАЖЛИВО",
|
||||
"pre_seed_description" : "На наступній сторінці ви побачите серію з 25 слів. Це ваша унікальна та приватна мнемонічна фраза, і це ЄДИНИЙ спосіб відновити ваш гаманець на випадок втрати або несправності. ВАМ необхідно записати її та зберігати в безпечному місці поза програмою Cake Wallet.",
|
||||
"pre_seed_description" : "На наступній сторінці ви побачите серію з ${words} слів. Це ваша унікальна та приватна мнемонічна фраза, і це ЄДИНИЙ спосіб відновити ваш гаманець на випадок втрати або несправності. ВАМ необхідно записати її та зберігати в безпечному місці поза програмою Cake Wallet.",
|
||||
"pre_seed_button_text" : "Зрозуміло. Покажіть мнемонічну фразу",
|
||||
|
||||
"xmr_to_error" : "Помилка XMR.TO",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "Кольорова тема",
|
||||
"light_theme" : "Світла",
|
||||
"bright_theme" : "Яскрава",
|
||||
"dark_theme" : "Темна"
|
||||
"dark_theme" : "Темна",
|
||||
"enter_your_note" : "Введіть примітку…",
|
||||
"note_optional" : "Примітка (необов’язково)",
|
||||
"note_tap_to_change" : "Примітка (натисніть для зміни)",
|
||||
"transaction_key" : "Ключ транзакції",
|
||||
"confirmations" : "Підтвердження",
|
||||
"recipient_address" : "Адреса одержувача"
|
||||
}
|
|
@ -212,7 +212,7 @@
|
|||
"send_name" : "名稱",
|
||||
"send_got_it" : "得到它了",
|
||||
"send_sending" : "正在發送...",
|
||||
"send_success" : "你Monero已成功發送",
|
||||
"send_success" : "你${crypto}已成功發送",
|
||||
|
||||
|
||||
"settings_title" : "设定值",
|
||||
|
@ -282,6 +282,7 @@
|
|||
"transaction_details_date" : "日期",
|
||||
"transaction_details_height" : "高度",
|
||||
"transaction_details_amount" : "量",
|
||||
"transaction_details_fee" : "費用",
|
||||
"transaction_details_copied" : "${title} 复制到剪贴板",
|
||||
"transaction_details_recipient_address" : "收件人地址",
|
||||
|
||||
|
@ -415,7 +416,7 @@
|
|||
"exchange_sync_alert_content" : "請等待,直到您的錢包同步",
|
||||
|
||||
"pre_seed_title" : "重要",
|
||||
"pre_seed_description" : "在下一頁上,您將看到一系列25個單詞。 這是您獨特的私人種子,是丟失或出現故障時恢復錢包的唯一方法。 您有責任將其寫下並存儲在Cake Wallet應用程序外部的安全地方。",
|
||||
"pre_seed_description" : "在下一頁上,您將看到一系列${words}個單詞。 這是您獨特的私人種子,是丟失或出現故障時恢復錢包的唯一方法。 您有責任將其寫下並存儲在Cake Wallet應用程序外部的安全地方。",
|
||||
"pre_seed_button_text" : "我明白。 給我看我的種子",
|
||||
|
||||
"xmr_to_error" : "XMR.TO錯誤",
|
||||
|
@ -428,5 +429,11 @@
|
|||
"color_theme" : "顏色主題",
|
||||
"light_theme" : "光",
|
||||
"bright_theme" : "亮",
|
||||
"dark_theme" : "黑暗"
|
||||
"dark_theme" : "黑暗",
|
||||
"enter_your_note" : "輸入您的筆記...",
|
||||
"note_optional" : "注意(可選)",
|
||||
"note_tap_to_change" : "注意(輕按即可更改)",
|
||||
"transaction_key" : "交易密碼",
|
||||
"confirmations" : "確認書",
|
||||
"recipient_address" : "收件人地址"
|
||||
}
|
Loading…
Reference in a new issue