mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 12:09:43 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-78-Ethereum
This commit is contained in:
commit
eff0369709
28 changed files with 753 additions and 627 deletions
1
.github/workflows/pr_test_build.yml
vendored
1
.github/workflows/pr_test_build.yml
vendored
|
@ -107,7 +107,6 @@ jobs:
|
||||||
echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const sideShiftApiKey = '${{ secrets.SIDE_SHIFT_API_KEY }}';" >> lib/.secrets.g.dart
|
|
||||||
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
|
Before Width: | Height: | Size: 193 B After Width: | Height: | Size: 193 B |
|
@ -40,6 +40,7 @@ import 'package:cake_wallet/utils/payment_request.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
||||||
|
@ -876,6 +877,8 @@ Future setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
|
getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||||
|
|
||||||
|
getIt.registerFactory(()=> MarketPlaceViewModel(getIt.get<IoniaService>()));
|
||||||
|
|
||||||
getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
|
getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
|
||||||
|
|
||||||
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>(
|
getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>(
|
||||||
|
@ -905,7 +908,7 @@ Future setup({
|
||||||
return IoniaVerifyIoniaOtp(getIt.get<IoniaAuthViewModel>(), email, isSignIn);
|
return IoniaVerifyIoniaOtp(getIt.get<IoniaAuthViewModel>(), email, isSignIn);
|
||||||
});
|
});
|
||||||
|
|
||||||
getIt.registerFactory(() => IoniaWelcomePage(getIt.get<IoniaGiftCardsListViewModel>()));
|
getIt.registerFactory(() => IoniaWelcomePage());
|
||||||
|
|
||||||
getIt.registerFactoryParam<IoniaBuyGiftCardPage, List, void>((List args, _) {
|
getIt.registerFactoryParam<IoniaBuyGiftCardPage, List, void>((List args, _) {
|
||||||
final merchant = args.first as IoniaMerchant;
|
final merchant = args.first as IoniaMerchant;
|
||||||
|
|
|
@ -55,11 +55,11 @@ class LanguageService {
|
||||||
'cs': 'czk',
|
'cs': 'czk',
|
||||||
'ur': 'pak',
|
'ur': 'pak',
|
||||||
'id': 'idn',
|
'id': 'idn',
|
||||||
'yo': 'yor',
|
'yo': 'nga',
|
||||||
'ha': 'hau'
|
'ha': 'hau'
|
||||||
};
|
};
|
||||||
|
|
||||||
static final list = <String, String> {};
|
static final list = <String, String>{};
|
||||||
|
|
||||||
static void loadLocaleList() {
|
static void loadLocaleList() {
|
||||||
supportedLocales.forEach((key, value) {
|
supportedLocales.forEach((key, value) {
|
||||||
|
|
|
@ -19,10 +19,10 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
|
|
||||||
static const affiliateId = secrets.sideShiftAffiliateId;
|
static const affiliateId = secrets.sideShiftAffiliateId;
|
||||||
static const apiBaseUrl = 'https://sideshift.ai/api';
|
static const apiBaseUrl = 'https://sideshift.ai/api';
|
||||||
static const rangePath = '/v1/pairs';
|
static const rangePath = '/v2/pair';
|
||||||
static const orderPath = '/v1/orders';
|
static const orderPath = '/v2/shifts';
|
||||||
static const quotePath = '/v1/quotes';
|
static const quotePath = '/v2/quotes';
|
||||||
static const permissionPath = '/v1/permissions';
|
static const permissionPath = '/v2/permissions';
|
||||||
|
|
||||||
static const List<CryptoCurrency> _notSupported = [
|
static const List<CryptoCurrency> _notSupported = [
|
||||||
CryptoCurrency.xhv,
|
CryptoCurrency.xhv,
|
||||||
|
@ -36,23 +36,22 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
CryptoCurrency.scrt,
|
CryptoCurrency.scrt,
|
||||||
CryptoCurrency.stx,
|
CryptoCurrency.stx,
|
||||||
CryptoCurrency.bttc,
|
CryptoCurrency.bttc,
|
||||||
|
CryptoCurrency.usdt,
|
||||||
|
CryptoCurrency.eos,
|
||||||
];
|
];
|
||||||
|
|
||||||
static List<ExchangePair> _supportedPairs() {
|
static List<ExchangePair> _supportedPairs() {
|
||||||
final supportedCurrencies = CryptoCurrency.all
|
final supportedCurrencies =
|
||||||
.where((element) => !_notSupported.contains(element))
|
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
return supportedCurrencies
|
return supportedCurrencies
|
||||||
.map((i) => supportedCurrencies
|
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
|
||||||
.expand((i) => i)
|
.expand((i) => i)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ExchangeProviderDescription get description =>
|
ExchangeProviderDescription get description => ExchangeProviderDescription.sideShift;
|
||||||
ExchangeProviderDescription.sideShift;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<double> fetchRate(
|
Future<double> fetchRate(
|
||||||
|
@ -65,17 +64,18 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
|
||||||
final toCurrency = _normalizeCryptoCurrency(to);
|
final fromCurrency = from.title.toLowerCase();
|
||||||
final url =
|
final toCurrency = to.title.toLowerCase();
|
||||||
apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
|
final depositNetwork = _networkFor(from);
|
||||||
|
final settleNetwork = _networkFor(to);
|
||||||
|
|
||||||
|
final url = "$apiBaseUrl$rangePath/$fromCurrency-$depositNetwork/$toCurrency-$settleNetwork";
|
||||||
|
|
||||||
final uri = Uri.parse(url);
|
final uri = Uri.parse(url);
|
||||||
final response = await get(uri);
|
final response = await get(uri);
|
||||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final rate = double.parse(responseJSON['rate'] as String);
|
final rate = double.parse(responseJSON['rate'] as String);
|
||||||
final max = double.parse(responseJSON['max'] as String);
|
|
||||||
|
|
||||||
if (amount > max) return 0.00;
|
|
||||||
|
|
||||||
return rate;
|
return rate;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
@ -101,25 +101,38 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final canCreateOrder = responseJSON['createOrder'] as bool;
|
final cancreateShift = responseJSON['createShift'] as bool;
|
||||||
final canCreateQuote = responseJSON['createQuote'] as bool;
|
return cancreateShift;
|
||||||
return canCreateOrder && canCreateQuote;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Trade> createTrade(
|
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||||
{required TradeRequest request, required bool isFixedRateMode}) async {
|
|
||||||
final _request = request as SideShiftRequest;
|
final _request = request as SideShiftRequest;
|
||||||
final quoteId = await _createQuote(_request);
|
String url = '';
|
||||||
final url = apiBaseUrl + orderPath;
|
final depositCoin = request.depositMethod.title.toLowerCase();
|
||||||
final headers = {'Content-Type': 'application/json'};
|
final settleCoin = request.settleMethod.title.toLowerCase();
|
||||||
final body = {
|
final body = {
|
||||||
'type': 'fixed',
|
|
||||||
'quoteId': quoteId,
|
|
||||||
'affiliateId': affiliateId,
|
'affiliateId': affiliateId,
|
||||||
'settleAddress': _request.settleAddress,
|
'settleAddress': _request.settleAddress,
|
||||||
'refundAddress': _request.refundAddress
|
'refundAddress': _request.refundAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isFixedRateMode) {
|
||||||
|
final quoteId = await _createQuote(_request);
|
||||||
|
body['quoteId'] = quoteId;
|
||||||
|
|
||||||
|
url = apiBaseUrl + orderPath + '/fixed';
|
||||||
|
} else {
|
||||||
|
url = apiBaseUrl + orderPath + '/variable';
|
||||||
|
final depositNetwork = _networkFor(request.depositMethod);
|
||||||
|
final settleNetwork = _networkFor(request.settleMethod);
|
||||||
|
body["depositCoin"] = depositCoin;
|
||||||
|
body["settleCoin"] = settleCoin;
|
||||||
|
body["settleNetwork"] = settleNetwork;
|
||||||
|
body["depositNetwork"] = depositNetwork;
|
||||||
|
}
|
||||||
|
final headers = {'Content-Type': 'application/json'};
|
||||||
|
|
||||||
final uri = Uri.parse(url);
|
final uri = Uri.parse(url);
|
||||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||||
|
|
||||||
|
@ -136,8 +149,9 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final id = responseJSON['id'] as String;
|
final id = responseJSON['id'] as String;
|
||||||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
final inputAddress = responseJSON['depositAddress'] as String;
|
||||||
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
final settleAddress = responseJSON['settleAddress'] as String;
|
||||||
|
final depositAmount = responseJSON['depositAmount'] as String?;
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: id,
|
id: id,
|
||||||
|
@ -147,7 +161,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
inputAddress: inputAddress,
|
inputAddress: inputAddress,
|
||||||
refundAddress: settleAddress,
|
refundAddress: settleAddress,
|
||||||
state: TradeState.created,
|
state: TradeState.created,
|
||||||
amount: _request.depositAmount,
|
amount: depositAmount ?? _request.depositAmount,
|
||||||
payoutAddress: settleAddress,
|
payoutAddress: settleAddress,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
);
|
);
|
||||||
|
@ -156,13 +170,17 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
Future<String> _createQuote(SideShiftRequest request) async {
|
Future<String> _createQuote(SideShiftRequest request) async {
|
||||||
final url = apiBaseUrl + quotePath;
|
final url = apiBaseUrl + quotePath;
|
||||||
final headers = {'Content-Type': 'application/json'};
|
final headers = {'Content-Type': 'application/json'};
|
||||||
final depositMethod = _normalizeCryptoCurrency(request.depositMethod);
|
final depositMethod = request.depositMethod.title.toLowerCase();
|
||||||
final settleMethod = _normalizeCryptoCurrency(request.settleMethod);
|
final settleMethod = request.settleMethod.title.toLowerCase();
|
||||||
|
final depositNetwork = _networkFor(request.depositMethod);
|
||||||
|
final settleNetwork = _networkFor(request.settleMethod);
|
||||||
final body = {
|
final body = {
|
||||||
'depositMethod': depositMethod,
|
'depositCoin': depositMethod,
|
||||||
'settleMethod': settleMethod,
|
'settleCoin': settleMethod,
|
||||||
'affiliateId': affiliateId,
|
'affiliateId': affiliateId,
|
||||||
'depositAmount': request.depositAmount,
|
'settleAmount': request.depositAmount,
|
||||||
|
'settleNetwork': settleNetwork,
|
||||||
|
'depositNetwork': depositNetwork,
|
||||||
};
|
};
|
||||||
final uri = Uri.parse(url);
|
final uri = Uri.parse(url);
|
||||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||||
|
@ -189,9 +207,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
{required CryptoCurrency from,
|
{required CryptoCurrency from,
|
||||||
required CryptoCurrency to,
|
required CryptoCurrency to,
|
||||||
required bool isFixedRateMode}) async {
|
required bool isFixedRateMode}) async {
|
||||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
final fromCurrency = isFixedRateMode ? to : from;
|
||||||
final toCurrency = _normalizeCryptoCurrency(to);
|
final toCurrency = isFixedRateMode ? from : to;
|
||||||
final url = apiBaseUrl + rangePath + '/' + fromCurrency + '/' + toCurrency;
|
|
||||||
|
final fromNetwork = _networkFor(fromCurrency);
|
||||||
|
final toNetwork = _networkFor(toCurrency);
|
||||||
|
|
||||||
|
final url =
|
||||||
|
"$apiBaseUrl$rangePath/${fromCurrency.title.toLowerCase()}-$fromNetwork/${toCurrency.title.toLowerCase()}-$toNetwork";
|
||||||
|
|
||||||
final uri = Uri.parse(url);
|
final uri = Uri.parse(url);
|
||||||
final response = await get(uri);
|
final response = await get(uri);
|
||||||
|
|
||||||
|
@ -210,6 +234,14 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
||||||
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
||||||
|
|
||||||
|
if (isFixedRateMode) {
|
||||||
|
final currentRate = double.parse(responseJSON['rate'] as String);
|
||||||
|
return Limits(
|
||||||
|
min: min != null ? (min * currentRate) : null,
|
||||||
|
max: max != null ? (max * currentRate) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Limits(min: min, max: max);
|
return Limits(min: min, max: max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +259,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final error = responseJSON['error']['message'] as String;
|
final error = responseJSON['error']['message'] as String;
|
||||||
|
|
||||||
throw TradeNotFoundException(id,
|
throw TradeNotFoundException(id, provider: description, description: error);
|
||||||
provider: description, description: error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
|
@ -236,36 +267,32 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final fromCurrency = responseJSON['depositMethodId'] as String;
|
final fromCurrency = responseJSON['depositCoin'] as String;
|
||||||
final from = CryptoCurrency.fromString(fromCurrency);
|
final from = CryptoCurrency.fromString(fromCurrency);
|
||||||
final toCurrency = responseJSON['settleMethodId'] as String;
|
final toCurrency = responseJSON['settleCoin'] as String;
|
||||||
final to = CryptoCurrency.fromString(toCurrency);
|
final to = CryptoCurrency.fromString(toCurrency);
|
||||||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
final inputAddress = responseJSON['depositAddress'] as String;
|
||||||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
final expectedSendAmount = responseJSON['depositAmount'] as String?;
|
||||||
final deposits = responseJSON['deposits'] as List?;
|
final status = responseJSON['status'] as String?;
|
||||||
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
final settleAddress = responseJSON['settleAddress'] as String;
|
||||||
TradeState? state;
|
TradeState? state;
|
||||||
String? status;
|
|
||||||
|
|
||||||
if (deposits?.isNotEmpty ?? false) {
|
|
||||||
status = deposits![0]['status'] as String?;
|
|
||||||
}
|
|
||||||
state = TradeState.deserialize(raw: status ?? 'created');
|
state = TradeState.deserialize(raw: status ?? 'created');
|
||||||
|
final isVariable = (responseJSON['type'] as String) == 'variable';
|
||||||
|
|
||||||
final expiredAtRaw = responseJSON['expiresAtISO'] as String;
|
final expiredAtRaw = responseJSON['expiresAt'] as String;
|
||||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: id,
|
id: id,
|
||||||
from: from,
|
from: from,
|
||||||
to: to,
|
to: to,
|
||||||
provider: description,
|
provider: description,
|
||||||
inputAddress: inputAddress,
|
inputAddress: inputAddress,
|
||||||
amount: expectedSendAmount,
|
amount: expectedSendAmount ?? '',
|
||||||
state: state,
|
state: state,
|
||||||
expiredAt: expiredAt,
|
expiredAt: expiredAt,
|
||||||
payoutAddress: settleAddress
|
payoutAddress: settleAddress);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -280,28 +307,25 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
@override
|
@override
|
||||||
String get title => 'SideShift';
|
String get title => 'SideShift';
|
||||||
|
|
||||||
static String _normalizeCryptoCurrency(CryptoCurrency currency) {
|
String _networkFor(CryptoCurrency currency) =>
|
||||||
switch (currency) {
|
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';
|
||||||
case CryptoCurrency.zaddr:
|
|
||||||
return 'zaddr';
|
String _normalizeTag(String tag) {
|
||||||
case CryptoCurrency.zec:
|
switch (tag) {
|
||||||
return 'zec';
|
case 'ETH':
|
||||||
case CryptoCurrency.bnb:
|
return 'ethereum';
|
||||||
return currency.tag!.toLowerCase();
|
case 'TRX':
|
||||||
case CryptoCurrency.usdterc20:
|
return 'tron';
|
||||||
return 'usdtErc20';
|
case 'LN':
|
||||||
case CryptoCurrency.usdttrc20:
|
return 'lightning';
|
||||||
return 'usdtTrc20';
|
case 'POLY':
|
||||||
case CryptoCurrency.usdcpoly:
|
|
||||||
return 'usdcpolygon';
|
|
||||||
case CryptoCurrency.usdcsol:
|
|
||||||
return 'usdcsol';
|
|
||||||
case CryptoCurrency.maticpoly:
|
|
||||||
return 'polygon';
|
return 'polygon';
|
||||||
case CryptoCurrency.btcln:
|
case 'ZEC':
|
||||||
return 'ln';
|
return 'zcash';
|
||||||
|
case 'AVAXC':
|
||||||
|
return 'avax';
|
||||||
default:
|
default:
|
||||||
return currency.title.toLowerCase();
|
return tag.toLowerCase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/sync_status.dart';
|
import 'package:cw_core/sync_status.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:connectivity/connectivity.dart';
|
|
||||||
|
|
||||||
Timer? _checkConnectionTimer;
|
Timer? _checkConnectionTimer;
|
||||||
|
|
||||||
void startCheckConnectionReaction(
|
void startCheckConnectionReaction(
|
||||||
|
|
|
@ -175,7 +175,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
fullscreenDialog: true);
|
fullscreenDialog: true);
|
||||||
} else if (isSingleCoin) {
|
} else if (isSingleCoin) {
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (_) => getIt.get<WalletRestorePage>(
|
builder: (_) => getIt.get<WalletRestorePage>(
|
||||||
param1: availableWalletTypes.first
|
param1: availableWalletTypes.first
|
||||||
));
|
));
|
||||||
|
@ -196,7 +195,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
|
|
||||||
case Routes.restoreWallet:
|
case Routes.restoreWallet:
|
||||||
return MaterialPageRoute<void>(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (_) => getIt.get<WalletRestorePage>(
|
builder: (_) => getIt.get<WalletRestorePage>(
|
||||||
param1: settings.arguments as WalletType));
|
param1: settings.arguments as WalletType));
|
||||||
|
|
||||||
|
@ -206,6 +204,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
|
|
||||||
case Routes.dashboard:
|
case Routes.dashboard:
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
|
settings: settings,
|
||||||
builder: (_) => getIt.get<DashboardPage>());
|
builder: (_) => getIt.get<DashboardPage>());
|
||||||
|
|
||||||
case Routes.send:
|
case Routes.send:
|
||||||
|
@ -468,7 +467,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
return CupertinoPageRoute<void>( builder: (_) => getIt.get<IoniaCreateAccountPage>());
|
return CupertinoPageRoute<void>( builder: (_) => getIt.get<IoniaCreateAccountPage>());
|
||||||
|
|
||||||
case Routes.ioniaManageCardsPage:
|
case Routes.ioniaManageCardsPage:
|
||||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaManageCardsPage>());
|
return CupertinoPageRoute<void>(
|
||||||
|
builder: (_) => getIt.get<IoniaManageCardsPage>());
|
||||||
|
|
||||||
case Routes.ioniaBuyGiftCardPage:
|
case Routes.ioniaBuyGiftCardPage:
|
||||||
final args = settings.arguments as List;
|
final args = settings.arguments as List;
|
||||||
|
@ -536,7 +536,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
case Routes.anonPayInvoicePage:
|
case Routes.anonPayInvoicePage:
|
||||||
final args = settings.arguments as List;
|
final args = settings.arguments as List;
|
||||||
return CupertinoPageRoute<void>(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
|
||||||
builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
|
builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
|
||||||
|
|
||||||
case Routes.anonPayReceivePage:
|
case Routes.anonPayReceivePage:
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:cake_wallet/entities/main_actions.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
||||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||||
|
@ -27,8 +27,6 @@ import 'package:mobx/mobx.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||||
import 'package:cake_wallet/main.dart';
|
import 'package:cake_wallet/main.dart';
|
||||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
|
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
|
||||||
|
|
||||||
class DashboardPage extends StatelessWidget {
|
class DashboardPage extends StatelessWidget {
|
||||||
|
@ -251,7 +249,12 @@ class _DashboardPageView extends BasePage {
|
||||||
if (dashboardViewModel.shouldShowMarketPlaceInDashboard) {
|
if (dashboardViewModel.shouldShowMarketPlaceInDashboard) {
|
||||||
pages.add(Semantics(
|
pages.add(Semantics(
|
||||||
label: 'Marketplace Page',
|
label: 'Marketplace Page',
|
||||||
child: MarketPlacePage(dashboardViewModel: dashboardViewModel)));
|
child: MarketPlacePage(
|
||||||
|
dashboardViewModel: dashboardViewModel,
|
||||||
|
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
pages.add(Semantics(label: 'Balance Page', child: balancePage));
|
pages.add(Semantics(label: 'Balance Page', child: balancePage));
|
||||||
pages.add(Semantics(
|
pages.add(Semantics(
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:cake_wallet/di.dart';
|
||||||
import 'package:cake_wallet/entities/main_actions.dart';
|
import 'package:cake_wallet/entities/main_actions.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
|
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
|
@ -70,7 +72,10 @@ class DesktopDashboardActions extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: MarketPlacePage(dashboardViewModel: dashboardViewModel),
|
child: MarketPlacePage(
|
||||||
|
dashboardViewModel: dashboardViewModel,
|
||||||
|
marketPlaceViewModel: getIt.get<MarketPlaceViewModel>(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -273,7 +273,7 @@ class AddressPage extends BasePage {
|
||||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case ReceivePageOption.anonPayInvoice:
|
case ReceivePageOption.anonPayInvoice:
|
||||||
Navigator.pushReplacementNamed(
|
Navigator.pushNamed(
|
||||||
context,
|
context,
|
||||||
Routes.anonPayInvoicePage,
|
Routes.anonPayInvoicePage,
|
||||||
arguments: [addressListViewModel.address.address, option],
|
arguments: [addressListViewModel.address.address, option],
|
||||||
|
@ -285,7 +285,7 @@ class AddressPage extends BasePage {
|
||||||
final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink);
|
final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink);
|
||||||
|
|
||||||
if (clearnetUrl != null && onionUrl != null) {
|
if (clearnetUrl != null && onionUrl != null) {
|
||||||
Navigator.pushReplacementNamed(
|
Navigator.pushNamed(
|
||||||
context,
|
context,
|
||||||
Routes.anonPayReceivePage,
|
Routes.anonPayReceivePage,
|
||||||
arguments: AnonpayDonationLinkInfo(
|
arguments: AnonpayDonationLinkInfo(
|
||||||
|
@ -295,7 +295,7 @@ class AddressPage extends BasePage {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
Navigator.pushReplacementNamed(
|
Navigator.pushNamed(
|
||||||
context,
|
context,
|
||||||
Routes.anonPayInvoicePage,
|
Routes.anonPayInvoicePage,
|
||||||
arguments: [addressListViewModel.address.address, option],
|
arguments: [addressListViewModel.address.address, option],
|
||||||
|
|
|
@ -3,16 +3,20 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||||
import 'package:cake_wallet/src/widgets/market_place_item.dart';
|
import 'package:cake_wallet/src/widgets/market_place_item.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class MarketPlacePage extends StatelessWidget {
|
class MarketPlacePage extends StatelessWidget {
|
||||||
|
MarketPlacePage({
|
||||||
MarketPlacePage({required this.dashboardViewModel});
|
required this.dashboardViewModel,
|
||||||
|
required this.marketPlaceViewModel,
|
||||||
|
});
|
||||||
|
|
||||||
final DashboardViewModel dashboardViewModel;
|
final DashboardViewModel dashboardViewModel;
|
||||||
|
final MarketPlaceViewModel marketPlaceViewModel;
|
||||||
final _scrollController = ScrollController();
|
final _scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -48,7 +52,7 @@ class MarketPlacePage extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
MarketPlaceItem(
|
MarketPlaceItem(
|
||||||
onTap: () =>_navigatorToGiftCardsPage(context),
|
onTap: () => _navigatorToGiftCardsPage(context),
|
||||||
title: S.of(context).cake_pay_title,
|
title: S.of(context).cake_pay_title,
|
||||||
subTitle: S.of(context).cake_pay_subtitle,
|
subTitle: S.of(context).cake_pay_subtitle,
|
||||||
),
|
),
|
||||||
|
@ -70,12 +74,13 @@ class MarketPlacePage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _navigatorToGiftCardsPage(BuildContext context) {
|
void _navigatorToGiftCardsPage(BuildContext context) {
|
||||||
final walletType = dashboardViewModel.type;
|
final walletType = dashboardViewModel.type;
|
||||||
|
|
||||||
switch (walletType) {
|
switch (walletType) {
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertWithOneAction(
|
return AlertWithOneAction(
|
||||||
|
@ -85,9 +90,14 @@ class MarketPlacePage extends StatelessWidget {
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
|
marketPlaceViewModel.isIoniaUserAuthenticated().then((value) {
|
||||||
|
if (value) {
|
||||||
|
Navigator.pushNamed(context, Routes.ioniaManageCardsPage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Navigator.of(context).pushNamed(Routes.ioniaWelcomePage);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,107 +25,126 @@ class TransactionsPage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return GestureDetector(
|
||||||
color: ResponsiveLayoutUtil.instance.isMobile(context)
|
onLongPress: () => dashboardViewModel.balanceViewModel.isReversing =
|
||||||
? null
|
!dashboardViewModel.balanceViewModel.isReversing,
|
||||||
: Theme.of(context).colorScheme.background,
|
onLongPressUp: () => dashboardViewModel.balanceViewModel.isReversing =
|
||||||
padding: EdgeInsets.only(top: 24, bottom: 24),
|
!dashboardViewModel.balanceViewModel.isReversing,
|
||||||
child: Column(
|
child: Container(
|
||||||
children: <Widget>[
|
color: ResponsiveLayoutUtil.instance.isMobile(context)
|
||||||
HeaderRow(dashboardViewModel: dashboardViewModel),
|
? null
|
||||||
Expanded(child: Observer(builder: (_) {
|
: Theme.of(context).colorScheme.background,
|
||||||
final items = dashboardViewModel.items;
|
padding: EdgeInsets.only(top: 24, bottom: 24),
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
HeaderRow(dashboardViewModel: dashboardViewModel),
|
||||||
|
Expanded(child: Observer(builder: (_) {
|
||||||
|
final items = dashboardViewModel.items;
|
||||||
|
|
||||||
return items.isNotEmpty
|
return items.isNotEmpty
|
||||||
? ListView.builder(
|
? ListView.builder(
|
||||||
itemCount: items.length,
|
itemCount: items.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = items[index];
|
final item = items[index];
|
||||||
|
|
||||||
if (item is DateSectionItem) {
|
if (item is DateSectionItem) {
|
||||||
return DateSectionRaw(date: item.date);
|
return DateSectionRaw(date: item.date);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is TransactionListItem) {
|
if (item is TransactionListItem) {
|
||||||
final transaction = item.transaction;
|
final transaction = item.transaction;
|
||||||
|
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (_) => TransactionRow(
|
builder: (_) => TransactionRow(
|
||||||
onTap: () => Navigator.of(context)
|
onTap: () => Navigator.of(context).pushNamed(
|
||||||
.pushNamed(Routes.transactionDetails, arguments: transaction),
|
Routes.transactionDetails,
|
||||||
direction: transaction.direction,
|
arguments: transaction),
|
||||||
formattedDate: DateFormat('HH:mm').format(transaction.date),
|
direction: transaction.direction,
|
||||||
formattedAmount: item.formattedCryptoAmount,
|
formattedDate: DateFormat('HH:mm')
|
||||||
formattedFiatAmount:
|
.format(transaction.date),
|
||||||
dashboardViewModel.balanceViewModel.isFiatDisabled
|
formattedAmount: item.formattedCryptoAmount,
|
||||||
? ''
|
formattedFiatAmount: dashboardViewModel
|
||||||
: item.formattedFiatAmount,
|
.balanceViewModel.isFiatDisabled
|
||||||
isPending: transaction.isPending,
|
? ''
|
||||||
title: item.formattedTitle + item.formattedStatus));
|
: item.formattedFiatAmount,
|
||||||
}
|
isPending: transaction.isPending,
|
||||||
|
title: item.formattedTitle +
|
||||||
|
item.formattedStatus));
|
||||||
|
}
|
||||||
|
|
||||||
if (item is AnonpayTransactionListItem) {
|
if (item is AnonpayTransactionListItem) {
|
||||||
final transactionInfo = item.transaction;
|
final transactionInfo = item.transaction;
|
||||||
|
|
||||||
return AnonpayTransactionRow(
|
return AnonpayTransactionRow(
|
||||||
onTap: () => Navigator.of(context)
|
onTap: () => Navigator.of(context).pushNamed(
|
||||||
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
|
Routes.anonPayDetailsPage,
|
||||||
currency: transactionInfo.fiatAmount != null
|
arguments: transactionInfo),
|
||||||
? transactionInfo.fiatEquiv ?? ''
|
currency: transactionInfo.fiatAmount != null
|
||||||
: CryptoCurrency.fromFullName(transactionInfo.coinTo)
|
? transactionInfo.fiatEquiv ?? ''
|
||||||
.name
|
: CryptoCurrency.fromFullName(
|
||||||
.toUpperCase(),
|
transactionInfo.coinTo)
|
||||||
provider: transactionInfo.provider,
|
.name
|
||||||
amount: transactionInfo.fiatAmount?.toString() ??
|
.toUpperCase(),
|
||||||
(transactionInfo.amountTo?.toString() ?? ''),
|
provider: transactionInfo.provider,
|
||||||
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
|
amount: transactionInfo.fiatAmount?.toString() ??
|
||||||
);
|
(transactionInfo.amountTo?.toString() ?? ''),
|
||||||
}
|
createdAt: DateFormat('HH:mm')
|
||||||
|
.format(transactionInfo.createdAt),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (item is TradeListItem) {
|
if (item is TradeListItem) {
|
||||||
final trade = item.trade;
|
final trade = item.trade;
|
||||||
|
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (_) => TradeRow(
|
builder: (_) => TradeRow(
|
||||||
onTap: () => Navigator.of(context)
|
onTap: () => Navigator.of(context).pushNamed(
|
||||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
Routes.tradeDetails,
|
||||||
provider: trade.provider,
|
arguments: trade),
|
||||||
from: trade.from,
|
provider: trade.provider,
|
||||||
to: trade.to,
|
from: trade.from,
|
||||||
createdAtFormattedDate: trade.createdAt != null
|
to: trade.to,
|
||||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
|
||||||
: null,
|
|
||||||
formattedAmount: item.tradeFormattedAmount));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item is OrderListItem) {
|
|
||||||
final order = item.order;
|
|
||||||
|
|
||||||
return Observer(
|
|
||||||
builder: (_) => OrderRow(
|
|
||||||
onTap: () => Navigator.of(context)
|
|
||||||
.pushNamed(Routes.orderDetails, arguments: order),
|
|
||||||
provider: order.provider,
|
|
||||||
from: order.from!,
|
|
||||||
to: order.to!,
|
|
||||||
createdAtFormattedDate:
|
createdAtFormattedDate:
|
||||||
DateFormat('HH:mm').format(order.createdAt),
|
trade.createdAt != null
|
||||||
formattedAmount: item.orderFormattedAmount,
|
? DateFormat('HH:mm')
|
||||||
));
|
.format(trade.createdAt!)
|
||||||
}
|
: null,
|
||||||
|
formattedAmount: item.tradeFormattedAmount));
|
||||||
|
}
|
||||||
|
|
||||||
return Container(color: Colors.transparent, height: 1);
|
if (item is OrderListItem) {
|
||||||
})
|
final order = item.order;
|
||||||
: Center(
|
|
||||||
child: Text(
|
return Observer(
|
||||||
S.of(context).placeholder_transactions,
|
builder: (_) => OrderRow(
|
||||||
style: TextStyle(
|
onTap: () => Navigator.of(context)
|
||||||
fontSize: 14,
|
.pushNamed(Routes.orderDetails,
|
||||||
color: Theme.of(context).primaryTextTheme!.labelSmall!.decorationColor!),
|
arguments: order),
|
||||||
),
|
provider: order.provider,
|
||||||
);
|
from: order.from!,
|
||||||
}))
|
to: order.to!,
|
||||||
],
|
createdAtFormattedDate: DateFormat('HH:mm')
|
||||||
|
.format(order.createdAt),
|
||||||
|
formattedAmount: item.orderFormattedAmount,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(color: Colors.transparent, height: 1);
|
||||||
|
})
|
||||||
|
: Center(
|
||||||
|
child: Text(
|
||||||
|
S.of(context).placeholder_transactions,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.labelSmall!
|
||||||
|
.decorationColor!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,11 @@ import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/typography.dart';
|
import 'package:cake_wallet/typography.dart';
|
||||||
import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
|
||||||
|
|
||||||
class IoniaWelcomePage extends BasePage {
|
class IoniaWelcomePage extends BasePage {
|
||||||
IoniaWelcomePage(this._cardsListViewModel);
|
IoniaWelcomePage();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) {
|
Widget middle(BuildContext context) {
|
||||||
|
@ -25,15 +22,8 @@ class IoniaWelcomePage extends BasePage {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final IoniaGiftCardsListViewModel _cardsListViewModel;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
reaction((_) => _cardsListViewModel.isLoggedIn, (bool state) {
|
|
||||||
if (state) {
|
|
||||||
Navigator.pushReplacementNamed(context, Routes.ioniaManageCardsPage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -41,7 +31,7 @@ class IoniaWelcomePage extends BasePage {
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 100),
|
SizedBox(height: 90),
|
||||||
Text(
|
Text(
|
||||||
S.of(context).about_cake_pay,
|
S.of(context).about_cake_pay,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|
|
@ -17,7 +17,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
class IoniaManageCardsPage extends BasePage {
|
class IoniaManageCardsPage extends BasePage {
|
||||||
IoniaManageCardsPage(this._cardsListViewModel) {
|
IoniaManageCardsPage(this._cardsListViewModel): searchFocusNode = FocusNode() {
|
||||||
_searchController.addListener(() {
|
_searchController.addListener(() {
|
||||||
if (_searchController.text != _cardsListViewModel.searchString) {
|
if (_searchController.text != _cardsListViewModel.searchString) {
|
||||||
_searchDebounce.run(() {
|
_searchDebounce.run(() {
|
||||||
|
@ -29,6 +29,7 @@ class IoniaManageCardsPage extends BasePage {
|
||||||
_cardsListViewModel.getMerchants();
|
_cardsListViewModel.getMerchants();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
final FocusNode searchFocusNode;
|
||||||
final IoniaGiftCardsListViewModel _cardsListViewModel;
|
final IoniaGiftCardsListViewModel _cardsListViewModel;
|
||||||
|
|
||||||
final _searchDebounce = Debounce(Duration(milliseconds: 500));
|
final _searchDebounce = Debounce(Duration(milliseconds: 500));
|
||||||
|
@ -86,7 +87,14 @@ class IoniaManageCardsPage extends BasePage {
|
||||||
//highlightColor: Colors.transparent,
|
//highlightColor: Colors.transparent,
|
||||||
//splashColor: Colors.transparent,
|
//splashColor: Colors.transparent,
|
||||||
//padding: EdgeInsets.all(0),
|
//padding: EdgeInsets.all(0),
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: (){
|
||||||
|
if (searchFocusNode.hasFocus) {
|
||||||
|
searchFocusNode.unfocus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
child: _backButton),
|
child: _backButton),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -149,6 +157,7 @@ class IoniaManageCardsPage extends BasePage {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _SearchWidget(
|
child: _SearchWidget(
|
||||||
controller: _searchController,
|
controller: _searchController,
|
||||||
|
focusNode: searchFocusNode,
|
||||||
)),
|
)),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
filterButton
|
filterButton
|
||||||
|
@ -266,9 +275,10 @@ class _SearchWidget extends StatelessWidget {
|
||||||
const _SearchWidget({
|
const _SearchWidget({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
|
required this.focusNode,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
final FocusNode focusNode;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final searchIcon = Padding(
|
final searchIcon = Padding(
|
||||||
|
@ -280,6 +290,7 @@ class _SearchWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
return TextField(
|
return TextField(
|
||||||
|
focusNode: focusNode,
|
||||||
style: TextStyle(color: Theme.of(context).accentTextTheme!.displayMedium!.backgroundColor!),
|
style: TextStyle(color: Theme.of(context).accentTextTheme!.displayMedium!.backgroundColor!),
|
||||||
controller: controller,
|
controller: controller,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
|
|
|
@ -27,8 +27,7 @@ class AnonPayInvoicePage extends BasePage {
|
||||||
AnonPayInvoicePage(
|
AnonPayInvoicePage(
|
||||||
this.anonInvoicePageViewModel,
|
this.anonInvoicePageViewModel,
|
||||||
this.receiveOptionViewModel,
|
this.receiveOptionViewModel,
|
||||||
) : _amountFocusNode = FocusNode() {
|
) : _amountFocusNode = FocusNode() {}
|
||||||
}
|
|
||||||
|
|
||||||
final _nameController = TextEditingController();
|
final _nameController = TextEditingController();
|
||||||
final _emailController = TextEditingController();
|
final _emailController = TextEditingController();
|
||||||
|
@ -53,6 +52,11 @@ class AnonPayInvoicePage extends BasePage {
|
||||||
@override
|
@override
|
||||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onClose(BuildContext context) {
|
||||||
|
Navigator.popUntil(context, ModalRoute.withName(Routes.dashboard));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) =>
|
Widget middle(BuildContext context) =>
|
||||||
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
|
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
|
||||||
|
@ -65,114 +69,125 @@ class AnonPayInvoicePage extends BasePage {
|
||||||
anonInvoicePageViewModel.reset();
|
anonInvoicePageViewModel.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||||
|
onClose(context);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||||
|
|
||||||
return KeyboardActions(
|
return WillPopScope(
|
||||||
disableScroll: true,
|
onWillPop: () => _onNavigateBack(context),
|
||||||
config: KeyboardActionsConfig(
|
child: KeyboardActions(
|
||||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
disableScroll: true,
|
||||||
keyboardBarColor: Theme.of(context)
|
config: KeyboardActionsConfig(
|
||||||
|
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||||
|
keyboardBarColor: Theme.of(context)
|
||||||
.accentTextTheme!
|
.accentTextTheme!
|
||||||
.bodyLarge!
|
.bodyLarge!
|
||||||
.backgroundColor!,
|
.backgroundColor!,
|
||||||
nextFocus: false,
|
nextFocus: false,
|
||||||
actions: [
|
actions: [
|
||||||
KeyboardActionsItem(
|
KeyboardActionsItem(
|
||||||
focusNode: _amountFocusNode,
|
focusNode: _amountFocusNode,
|
||||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||||
),
|
|
||||||
]),
|
|
||||||
child: Container(
|
|
||||||
color: Theme.of(context).colorScheme.background,
|
|
||||||
child: ScrollableWithBottomSection(
|
|
||||||
contentPadding: EdgeInsets.only(bottom: 24),
|
|
||||||
content: Container(
|
|
||||||
decoration: DeviceInfo.instance.isMobile ? BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.only(
|
|
||||||
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: [
|
|
||||||
Theme.of(context).primaryTextTheme!.titleSmall!.color!,
|
|
||||||
Theme.of(context).primaryTextTheme!.titleSmall!.decorationColor!,
|
|
||||||
],
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
),
|
),
|
||||||
) : null,
|
]),
|
||||||
child: Observer(builder: (_) {
|
child: Container(
|
||||||
return Padding(
|
color: Theme.of(context).colorScheme.background,
|
||||||
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
child: ScrollableWithBottomSection(
|
||||||
child: AnonInvoiceForm(
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
nameController: _nameController,
|
content: Container(
|
||||||
descriptionController: _descriptionController,
|
decoration: DeviceInfo.instance.isMobile
|
||||||
amountController: _amountController,
|
? BoxDecoration(
|
||||||
emailController: _emailController,
|
borderRadius: BorderRadius.only(
|
||||||
depositAmountFocus: _amountFocusNode,
|
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||||
formKey: _formKey,
|
gradient: LinearGradient(
|
||||||
isInvoice: receiveOptionViewModel.selectedReceiveOption ==
|
colors: [
|
||||||
ReceivePageOption.anonPayInvoice,
|
Theme.of(context).primaryTextTheme!.titleSmall!.color!,
|
||||||
anonInvoicePageViewModel: anonInvoicePageViewModel,
|
Theme.of(context).primaryTextTheme!.titleSmall!.decorationColor!,
|
||||||
),
|
],
|
||||||
);
|
begin: Alignment.topLeft,
|
||||||
}),
|
end: Alignment.bottomRight,
|
||||||
),
|
),
|
||||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
)
|
||||||
bottomSection: Observer(builder: (_) {
|
: null,
|
||||||
final isInvoice =
|
child: Observer(builder: (_) {
|
||||||
receiveOptionViewModel.selectedReceiveOption == ReceivePageOption.anonPayInvoice;
|
return Padding(
|
||||||
return Column(
|
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||||
children: <Widget>[
|
child: AnonInvoiceForm(
|
||||||
Padding(
|
nameController: _nameController,
|
||||||
padding: EdgeInsets.only(bottom: 15),
|
descriptionController: _descriptionController,
|
||||||
child: Center(
|
amountController: _amountController,
|
||||||
child: Text(
|
emailController: _emailController,
|
||||||
isInvoice
|
depositAmountFocus: _amountFocusNode,
|
||||||
? S.of(context).anonpay_description("an invoice", "pay")
|
formKey: _formKey,
|
||||||
: S.of(context).anonpay_description("a donation link", "donate"),
|
isInvoice: receiveOptionViewModel.selectedReceiveOption ==
|
||||||
textAlign: TextAlign.center,
|
ReceivePageOption.anonPayInvoice,
|
||||||
style: TextStyle(
|
anonInvoicePageViewModel: anonInvoicePageViewModel,
|
||||||
color: Theme.of(context)
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
|
bottomSection: Observer(builder: (_) {
|
||||||
|
final isInvoice =
|
||||||
|
receiveOptionViewModel.selectedReceiveOption == ReceivePageOption.anonPayInvoice;
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: 15),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
isInvoice
|
||||||
|
? S.of(context).anonpay_description("an invoice", "pay")
|
||||||
|
: S.of(context).anonpay_description("a donation link", "donate"),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context)
|
||||||
.primaryTextTheme!
|
.primaryTextTheme!
|
||||||
.displayLarge!
|
.displayLarge!
|
||||||
.decorationColor!,
|
.decorationColor!,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
fontSize: 12),
|
fontSize: 12),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
LoadingPrimaryButton(
|
||||||
LoadingPrimaryButton(
|
text: isInvoice
|
||||||
text:
|
? S.of(context).create_invoice
|
||||||
isInvoice ? S.of(context).create_invoice : S.of(context).create_donation_link,
|
: S.of(context).create_donation_link,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
anonInvoicePageViewModel.setRequestParams(
|
anonInvoicePageViewModel.setRequestParams(
|
||||||
inputAmount: _amountController.text,
|
inputAmount: _amountController.text,
|
||||||
inputName: _nameController.text,
|
inputName: _nameController.text,
|
||||||
inputEmail: _emailController.text,
|
inputEmail: _emailController.text,
|
||||||
inputDescription: _descriptionController.text,
|
inputDescription: _descriptionController.text,
|
||||||
);
|
);
|
||||||
if (anonInvoicePageViewModel.receipientEmail.isNotEmpty &&
|
if (anonInvoicePageViewModel.receipientEmail.isNotEmpty &&
|
||||||
_formKey.currentState != null &&
|
_formKey.currentState != null &&
|
||||||
!_formKey.currentState!.validate()) {
|
!_formKey.currentState!.validate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isInvoice) {
|
if (isInvoice) {
|
||||||
anonInvoicePageViewModel.createInvoice();
|
anonInvoicePageViewModel.createInvoice();
|
||||||
} else {
|
} else {
|
||||||
anonInvoicePageViewModel.generateDonationLink();
|
anonInvoicePageViewModel.generateDonationLink();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.accentTextTheme!
|
.accentTextTheme!
|
||||||
.bodyLarge!
|
.bodyLarge!
|
||||||
.color!,
|
.color!,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
isLoading: anonInvoicePageViewModel.state is IsExecutingState,
|
isLoading: anonInvoicePageViewModel.state is IsExecutingState,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -266,6 +266,8 @@ class WalletRestorePage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _confirmForm() {
|
void _confirmForm() {
|
||||||
|
// Dismissing all visible keyboard to provide context for navigation
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
final formContext = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
final formContext = walletRestoreViewModel.mode == WalletRestoreMode.seed
|
||||||
? walletRestoreFromSeedFormKey.currentContext
|
? walletRestoreFromSeedFormKey.currentContext
|
||||||
: walletRestoreFromKeysFormKey.currentContext;
|
: walletRestoreFromKeysFormKey.currentContext;
|
||||||
|
|
|
@ -145,216 +145,247 @@ class SendPage extends BasePage {
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
_setEffects(context);
|
_setEffects(context);
|
||||||
|
|
||||||
return Form(
|
return GestureDetector(
|
||||||
key: _formKey,
|
onLongPress: () => sendViewModel.balanceViewModel.isReversing =
|
||||||
child: ScrollableWithBottomSection(
|
!sendViewModel.balanceViewModel.isReversing,
|
||||||
contentPadding: EdgeInsets.only(bottom: 24),
|
onLongPressUp: () => sendViewModel.balanceViewModel.isReversing =
|
||||||
content: FocusTraversalGroup(
|
!sendViewModel.balanceViewModel.isReversing,
|
||||||
policy: OrderedTraversalPolicy(),
|
child: Form(
|
||||||
child: Column(
|
key: _formKey,
|
||||||
children: <Widget>[
|
child: ScrollableWithBottomSection(
|
||||||
Container(
|
contentPadding: EdgeInsets.only(bottom: 24),
|
||||||
height: _sendCardHeight(context),
|
content: FocusTraversalGroup(
|
||||||
child: Observer(
|
policy: OrderedTraversalPolicy(),
|
||||||
builder: (_) {
|
child: Column(
|
||||||
return PageView.builder(
|
children: <Widget>[
|
||||||
scrollDirection: Axis.horizontal,
|
Container(
|
||||||
controller: controller,
|
height: _sendCardHeight(context),
|
||||||
itemCount: sendViewModel.outputs.length,
|
child: Observer(
|
||||||
itemBuilder: (context, index) {
|
builder: (_) {
|
||||||
final output = sendViewModel.outputs[index];
|
return PageView.builder(
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
return SendCard(
|
controller: controller,
|
||||||
key: output.key,
|
itemCount: sendViewModel.outputs.length,
|
||||||
output: output,
|
itemBuilder: (context, index) {
|
||||||
sendViewModel: sendViewModel,
|
final output = sendViewModel.outputs[index];
|
||||||
initialPaymentRequest: initialPaymentRequest,
|
|
||||||
);
|
return SendCard(
|
||||||
});
|
key: output.key,
|
||||||
},
|
output: output,
|
||||||
)),
|
sendViewModel: sendViewModel,
|
||||||
Padding(
|
initialPaymentRequest: initialPaymentRequest,
|
||||||
padding:
|
);
|
||||||
EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10),
|
});
|
||||||
child: Container(
|
},
|
||||||
height: 10,
|
)),
|
||||||
child: Observer(
|
Padding(
|
||||||
builder: (_) {
|
padding: EdgeInsets.only(
|
||||||
final count = sendViewModel.outputs.length;
|
top: 10, left: 24, right: 24, bottom: 10),
|
||||||
|
child: Container(
|
||||||
return count > 1
|
height: 10,
|
||||||
? SmoothPageIndicator(
|
child: Observer(
|
||||||
controller: controller,
|
builder: (_) {
|
||||||
count: count,
|
final count = sendViewModel.outputs.length;
|
||||||
effect: ScrollingDotsEffect(
|
|
||||||
spacing: 6.0,
|
return count > 1
|
||||||
radius: 6.0,
|
? SmoothPageIndicator(
|
||||||
dotWidth: 6.0,
|
controller: controller,
|
||||||
dotHeight: 6.0,
|
count: count,
|
||||||
dotColor: Theme.of(context)
|
effect: ScrollingDotsEffect(
|
||||||
.primaryTextTheme!.displaySmall!
|
spacing: 6.0,
|
||||||
.backgroundColor!,
|
radius: 6.0,
|
||||||
activeDotColor: Theme.of(context)
|
dotWidth: 6.0,
|
||||||
.primaryTextTheme!.displayMedium!
|
dotHeight: 6.0,
|
||||||
.backgroundColor!),
|
dotColor: Theme.of(context)
|
||||||
)
|
.primaryTextTheme
|
||||||
: Offstage();
|
!.displaySmall!
|
||||||
},
|
.backgroundColor!,
|
||||||
|
activeDotColor: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
!.displayMedium!
|
||||||
|
.backgroundColor!),
|
||||||
|
)
|
||||||
|
: Offstage();
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (sendViewModel.hasMultiRecipient)
|
||||||
if (sendViewModel.hasMultiRecipient)
|
Container(
|
||||||
Container(
|
height: 40,
|
||||||
height: 40,
|
width: double.infinity,
|
||||||
width: double.infinity,
|
padding: EdgeInsets.only(left: 24),
|
||||||
padding: EdgeInsets.only(left: 24),
|
child: SingleChildScrollView(
|
||||||
child: SingleChildScrollView(
|
scrollDirection: Axis.horizontal,
|
||||||
scrollDirection: Axis.horizontal,
|
child: Observer(
|
||||||
child: Observer(
|
builder: (_) {
|
||||||
builder: (_) {
|
final templates = sendViewModel.templates;
|
||||||
final templates = sendViewModel.templates;
|
final itemCount = templates.length;
|
||||||
final itemCount = templates.length;
|
|
||||||
|
return Row(
|
||||||
return Row(
|
children: <Widget>[
|
||||||
children: <Widget>[
|
AddTemplateButton(
|
||||||
AddTemplateButton(
|
onTap: () => Navigator.of(context)
|
||||||
onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate),
|
.pushNamed(Routes.sendTemplate),
|
||||||
currentTemplatesLength: templates.length,
|
currentTemplatesLength: templates.length,
|
||||||
),
|
),
|
||||||
ListView.builder(
|
ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
itemCount: itemCount,
|
itemCount: itemCount,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final template = templates[index];
|
final template = templates[index];
|
||||||
return TemplateTile(
|
return TemplateTile(
|
||||||
key: UniqueKey(),
|
key: UniqueKey(),
|
||||||
to: template.name,
|
to: template.name,
|
||||||
amount: template.isCurrencySelected ? template.amount : template.amountFiat,
|
amount: template.isCurrencySelected
|
||||||
from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency,
|
? template.amount
|
||||||
onTap: () async {
|
: template.amountFiat,
|
||||||
final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency);
|
from: template.isCurrencySelected
|
||||||
final output = _defineCurrentOutput();
|
? template.cryptoCurrency
|
||||||
output.address = template.address;
|
: template.fiatCurrency,
|
||||||
if(template.isCurrencySelected){
|
onTap: () async {
|
||||||
output.setCryptoAmount(template.amount);
|
final fiatFromTemplate = FiatCurrency
|
||||||
}else{
|
.all
|
||||||
sendViewModel.setFiatCurrency(fiatFromTemplate);
|
.singleWhere((element) =>
|
||||||
output.setFiatAmount(template.amountFiat);
|
element.title ==
|
||||||
}
|
template.fiatCurrency);
|
||||||
output.resetParsedAddress();
|
final output = _defineCurrentOutput();
|
||||||
await output.fetchParsedAddress(context);
|
output.address = template.address;
|
||||||
},
|
if (template.isCurrencySelected) {
|
||||||
onRemove: () {
|
output
|
||||||
showPopUp<void>(
|
.setCryptoAmount(template.amount);
|
||||||
context: context,
|
} else {
|
||||||
builder: (dialogContext) {
|
sendViewModel.setFiatCurrency(
|
||||||
return AlertWithTwoActions(
|
fiatFromTemplate);
|
||||||
alertTitle: S.of(context).template,
|
output.setFiatAmount(
|
||||||
alertContent: S
|
template.amountFiat);
|
||||||
.of(context)
|
}
|
||||||
.confirm_delete_template,
|
output.resetParsedAddress();
|
||||||
rightButtonText: S.of(context).delete,
|
await output
|
||||||
leftButtonText: S.of(context).cancel,
|
.fetchParsedAddress(context);
|
||||||
actionRightButton: () {
|
},
|
||||||
Navigator.of(dialogContext).pop();
|
onRemove: () {
|
||||||
sendViewModel.sendTemplateViewModel
|
showPopUp<void>(
|
||||||
.removeTemplate(
|
context: context,
|
||||||
template: template);
|
builder: (dialogContext) {
|
||||||
},
|
return AlertWithTwoActions(
|
||||||
actionLeftButton: () =>
|
alertTitle:
|
||||||
Navigator.of(dialogContext)
|
S.of(context).template,
|
||||||
.pop());
|
alertContent: S
|
||||||
|
.of(context)
|
||||||
|
.confirm_delete_template,
|
||||||
|
rightButtonText:
|
||||||
|
S.of(context).delete,
|
||||||
|
leftButtonText:
|
||||||
|
S.of(context).cancel,
|
||||||
|
actionRightButton: () {
|
||||||
|
Navigator.of(dialogContext)
|
||||||
|
.pop();
|
||||||
|
sendViewModel
|
||||||
|
.sendTemplateViewModel
|
||||||
|
.removeTemplate(
|
||||||
|
template: template);
|
||||||
|
},
|
||||||
|
actionLeftButton: () =>
|
||||||
|
Navigator.of(dialogContext)
|
||||||
|
.pop());
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
},
|
],
|
||||||
),
|
);
|
||||||
],
|
},
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
bottomSectionPadding:
|
|
||||||
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
|
||||||
bottomSection: Column(
|
|
||||||
children: [
|
|
||||||
if (sendViewModel.hasCurrecyChanger)
|
|
||||||
Observer(builder: (_) =>
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(bottom: 12),
|
|
||||||
child: PrimaryButton(
|
|
||||||
onPressed: () => presentCurrencyPicker(context),
|
|
||||||
text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
|
||||||
color: Colors.transparent,
|
|
||||||
textColor: Theme.of(context)
|
|
||||||
.accentTextTheme!.displaySmall!
|
|
||||||
.decorationColor!,
|
|
||||||
)
|
)
|
||||||
)
|
],
|
||||||
),
|
),
|
||||||
if (sendViewModel.hasMultiRecipient)
|
),
|
||||||
Padding(
|
bottomSectionPadding:
|
||||||
padding: EdgeInsets.only(bottom: 12),
|
EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
child: PrimaryButton(
|
bottomSection: Column(
|
||||||
onPressed: () {
|
children: [
|
||||||
sendViewModel.addOutput();
|
if (sendViewModel.hasCurrecyChanger)
|
||||||
Future.delayed(const Duration(milliseconds: 250), () {
|
Observer(
|
||||||
controller.jumpToPage(sendViewModel.outputs.length - 1);
|
builder: (_) => Padding(
|
||||||
});
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
},
|
child: PrimaryButton(
|
||||||
text: S.of(context).add_receiver,
|
onPressed: () => presentCurrencyPicker(context),
|
||||||
color: Colors.transparent,
|
text:
|
||||||
textColor: Theme.of(context)
|
'Change your asset (${sendViewModel.selectedCryptoCurrency})',
|
||||||
.accentTextTheme!.displaySmall!
|
color: Colors.transparent,
|
||||||
.decorationColor!,
|
textColor: Theme.of(context)
|
||||||
isDottedBorder: true,
|
.accentTextTheme
|
||||||
borderColor: Theme.of(context)
|
!.displaySmall!
|
||||||
.primaryTextTheme!.displaySmall!
|
.decorationColor!,
|
||||||
.decorationColor!,
|
))),
|
||||||
)),
|
if (sendViewModel.hasMultiRecipient)
|
||||||
Observer(
|
Padding(
|
||||||
builder: (_) {
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
return LoadingPrimaryButton(
|
child: PrimaryButton(
|
||||||
onPressed: () async {
|
onPressed: () {
|
||||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
sendViewModel.addOutput();
|
||||||
if (sendViewModel.outputs.length > 1) {
|
Future.delayed(const Duration(milliseconds: 250), () {
|
||||||
showErrorValidationAlert(context);
|
controller
|
||||||
|
.jumpToPage(sendViewModel.outputs.length - 1);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
text: S.of(context).add_receiver,
|
||||||
|
color: Colors.transparent,
|
||||||
|
textColor: Theme.of(context)
|
||||||
|
.accentTextTheme
|
||||||
|
!.displaySmall!
|
||||||
|
.decorationColor!,
|
||||||
|
isDottedBorder: true,
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
!.displaySmall!
|
||||||
|
.decorationColor!,
|
||||||
|
)),
|
||||||
|
Observer(
|
||||||
|
builder: (_) {
|
||||||
|
return LoadingPrimaryButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (_formKey.currentState != null &&
|
||||||
|
!_formKey.currentState!.validate()) {
|
||||||
|
if (sendViewModel.outputs.length > 1) {
|
||||||
|
showErrorValidationAlert(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
final notValidItems = sendViewModel.outputs
|
||||||
}
|
.where((item) =>
|
||||||
|
item.address.isEmpty ||
|
||||||
|
item.cryptoAmount.isEmpty)
|
||||||
|
.toList();
|
||||||
|
|
||||||
final notValidItems = sendViewModel.outputs
|
if (notValidItems.isNotEmpty ?? false) {
|
||||||
.where((item) =>
|
showErrorValidationAlert(context);
|
||||||
item.address.isEmpty || item.cryptoAmount.isEmpty)
|
return;
|
||||||
.toList();
|
}
|
||||||
|
|
||||||
if (notValidItems.isNotEmpty ?? false) {
|
await sendViewModel.createTransaction();
|
||||||
showErrorValidationAlert(context);
|
},
|
||||||
return;
|
text: S.of(context).send,
|
||||||
}
|
color:
|
||||||
|
Theme.of(context).accentTextTheme!.bodyLarge!.color!,
|
||||||
await sendViewModel.createTransaction();
|
textColor: Colors.white,
|
||||||
|
isLoading: sendViewModel.state is IsExecutingState ||
|
||||||
},
|
sendViewModel.state is TransactionCommitting,
|
||||||
text: S.of(context).send,
|
isDisabled: !sendViewModel.isReadyForSend,
|
||||||
color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
|
);
|
||||||
textColor: Colors.white,
|
},
|
||||||
isLoading: sendViewModel.state is IsExecutingState ||
|
)
|
||||||
sendViewModel.state is TransactionCommitting,
|
],
|
||||||
isDisabled: !sendViewModel.isReadyForSend,
|
)),
|
||||||
);
|
),
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,51 +413,54 @@ class SendPage extends BasePage {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showPopUp<void>(
|
showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return ConfirmSendingAlert(
|
return ConfirmSendingAlert(
|
||||||
alertTitle: S.of(context).confirm_sending,
|
alertTitle: S.of(context).confirm_sending,
|
||||||
amount: S.of(context).send_amount,
|
amount: S.of(context).send_amount,
|
||||||
amountValue:
|
amountValue:
|
||||||
sendViewModel.pendingTransaction!.amountFormatted,
|
sendViewModel.pendingTransaction!.amountFormatted,
|
||||||
fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted,
|
fiatAmountValue:
|
||||||
fee: S.of(context).send_fee,
|
sendViewModel.pendingTransactionFiatAmountFormatted,
|
||||||
feeValue: sendViewModel.pendingTransaction!.feeFormatted,
|
fee: S.of(context).send_fee,
|
||||||
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted,
|
feeValue: sendViewModel.pendingTransaction!.feeFormatted,
|
||||||
outputs: sendViewModel.outputs,
|
feeFiatAmount: sendViewModel
|
||||||
rightButtonText: S.of(context).ok,
|
.pendingTransactionFeeFiatAmountFormatted,
|
||||||
leftButtonText: S.of(context).cancel,
|
outputs: sendViewModel.outputs,
|
||||||
actionRightButton: () {
|
rightButtonText: S.of(context).ok,
|
||||||
Navigator.of(context).pop();
|
leftButtonText: S.of(context).cancel,
|
||||||
sendViewModel.commitTransaction();
|
actionRightButton: () {
|
||||||
showPopUp<void>(
|
Navigator.of(context).pop();
|
||||||
context: context,
|
sendViewModel.commitTransaction();
|
||||||
builder: (BuildContext context) {
|
showPopUp<void>(
|
||||||
return Observer(builder: (_) {
|
context: context,
|
||||||
final state = sendViewModel.state;
|
builder: (BuildContext context) {
|
||||||
|
return Observer(builder: (_) {
|
||||||
|
final state = sendViewModel.state;
|
||||||
|
|
||||||
if (state is FailureState) {
|
if (state is FailureState) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
|
||||||
|
|
||||||
if (state is TransactionCommitted) {
|
|
||||||
return AlertWithOneAction(
|
|
||||||
alertTitle: '',
|
|
||||||
alertContent: S.of(context).send_success(
|
|
||||||
sendViewModel.selectedCryptoCurrency.toString()),
|
|
||||||
buttonText: S.of(context).ok,
|
|
||||||
buttonAction: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
RequestReviewHandler.requestReview();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Offstage();
|
if (state is TransactionCommitted) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: '',
|
||||||
|
alertContent: S.of(context).send_success(
|
||||||
|
sendViewModel.selectedCryptoCurrency
|
||||||
|
.toString()),
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
RequestReviewHandler.requestReview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Offstage();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
},
|
||||||
},
|
actionLeftButton: () => Navigator.of(context).pop());
|
||||||
actionLeftButton: () => Navigator.of(context).pop());
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -461,16 +495,18 @@ class SendPage extends BasePage {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void presentCurrencyPicker(BuildContext context) async {
|
void presentCurrencyPicker(BuildContext context) async {
|
||||||
await showPopUp<CryptoCurrency>(
|
await showPopUp<CryptoCurrency>(
|
||||||
builder: (_) => Picker(
|
builder: (_) => Picker(
|
||||||
items: sendViewModel.currencies,
|
items: sendViewModel.currencies,
|
||||||
displayItem: (Object item) => item.toString(),
|
displayItem: (Object item) => item.toString(),
|
||||||
selectedAtIndex: sendViewModel.currencies.indexOf(sendViewModel.selectedCryptoCurrency),
|
selectedAtIndex: sendViewModel.currencies
|
||||||
title: S.of(context).please_select,
|
.indexOf(sendViewModel.selectedCryptoCurrency),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
title: S.of(context).please_select,
|
||||||
onItemSelected: (CryptoCurrency cur) => sendViewModel.selectedCryptoCurrency = cur,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
),
|
onItemSelected: (CryptoCurrency cur) =>
|
||||||
|
sendViewModel.selectedCryptoCurrency = cur,
|
||||||
|
),
|
||||||
context: context);
|
context: context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,26 +43,24 @@ class TotpAuthCodePageState extends State<TotpAuthCodePage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_reaction ??= reaction((_) => widget.setup2FAViewModel.state, (ExecutionState state) {
|
if(widget.totpArguments.onTotpAuthenticationFinished != null) {
|
||||||
if (state is ExecutedSuccessfullyState) {
|
_reaction ??= reaction((_) => widget.setup2FAViewModel.state, (ExecutionState state) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
widget.totpArguments.onTotpAuthenticationFinished!(true, this);
|
if (state is ExecutedSuccessfullyState) {
|
||||||
});
|
widget.totpArguments.onTotpAuthenticationFinished!(true, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is FailureState) {
|
if (state is FailureState) {
|
||||||
print(state.error);
|
print(state.error);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
|
||||||
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state is AuthenticationBanned) {
|
if (state is AuthenticationBanned) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
|
||||||
widget.totpArguments.onTotpAuthenticationFinished!(false, this);
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,12 +150,26 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
|
|
||||||
return wallet.isCurrent
|
return wallet.isCurrent
|
||||||
? row
|
? row
|
||||||
: Slidable(
|
: Row(children: [
|
||||||
key: Key('${wallet.key}'),
|
Expanded(child: row),
|
||||||
startActionPane: _actionPane(wallet),
|
GestureDetector(
|
||||||
endActionPane: _actionPane(wallet),
|
onTap: () => _removeWallet(wallet),
|
||||||
child: row,
|
child: Container(
|
||||||
);
|
height: 40,
|
||||||
|
width: 44,
|
||||||
|
padding: EdgeInsets.only(right: 20),
|
||||||
|
child: Center(
|
||||||
|
child: Image.asset('assets/images/trash.png',
|
||||||
|
height: 16,
|
||||||
|
width: 16,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.titleLarge!
|
||||||
|
.color),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
]);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -280,18 +294,4 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
_progressBar = null;
|
_progressBar = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
|
|
||||||
motion: const ScrollMotion(),
|
|
||||||
extentRatio: 0.3,
|
|
||||||
children: [
|
|
||||||
SlidableAction(
|
|
||||||
onPressed: (_) => _removeWallet(wallet),
|
|
||||||
backgroundColor: Colors.red,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
icon: CupertinoIcons.delete,
|
|
||||||
label: S.of(context).delete,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
17
lib/view_model/dashboard/market_place_view_model.dart
Normal file
17
lib/view_model/dashboard/market_place_view_model.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:cake_wallet/ionia/ionia_service.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'market_place_view_model.g.dart';
|
||||||
|
|
||||||
|
class MarketPlaceViewModel = MarketPlaceViewModelBase with _$MarketPlaceViewModel;
|
||||||
|
|
||||||
|
abstract class MarketPlaceViewModelBase with Store {
|
||||||
|
final IoniaService _ioniaService;
|
||||||
|
|
||||||
|
MarketPlaceViewModelBase(this._ioniaService);
|
||||||
|
|
||||||
|
|
||||||
|
Future<bool> isIoniaUserAuthenticated() async {
|
||||||
|
return await _ioniaService.isLogined();
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
import 'package:cw_core/keyable.dart';
|
import 'package:cw_core/keyable.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
|
||||||
class TransactionListItem extends ActionListItem with Keyable {
|
class TransactionListItem extends ActionListItem with Keyable {
|
||||||
TransactionListItem(
|
TransactionListItem(
|
||||||
{required this.transaction,
|
{required this.transaction,
|
||||||
|
@ -28,7 +27,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
|
|
||||||
FiatCurrency get fiatCurrency => settingsStore.fiatCurrency;
|
FiatCurrency get fiatCurrency => settingsStore.fiatCurrency;
|
||||||
|
|
||||||
BalanceDisplayMode get displayMode => settingsStore.balanceDisplayMode;
|
BalanceDisplayMode get displayMode => balanceViewModel.displayMode;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
dynamic get keyIndex => transaction.id;
|
dynamic get keyIndex => transaction.id;
|
||||||
|
|
|
@ -47,7 +47,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
case ExchangeProviderDescription.simpleSwap:
|
case ExchangeProviderDescription.simpleSwap:
|
||||||
_provider = SimpleSwapExchangeProvider();
|
_provider = SimpleSwapExchangeProvider();
|
||||||
break;
|
break;
|
||||||
case ExchangeProviderDescription.trocador:
|
case ExchangeProviderDescription.trocador:
|
||||||
_provider = TrocadorExchangeProvider();
|
_provider = TrocadorExchangeProvider();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,10 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
updatedTrade.createdAt = trade.createdAt;
|
updatedTrade.createdAt = trade.createdAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updatedTrade.amount.isEmpty) {
|
||||||
|
updatedTrade.amount = trade.amount;
|
||||||
|
}
|
||||||
|
|
||||||
trade = updatedTrade;
|
trade = updatedTrade;
|
||||||
|
|
||||||
_updateItems();
|
_updateItems();
|
||||||
|
@ -123,7 +127,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateItems() {
|
void _updateItems() {
|
||||||
final tagFrom = tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : '';
|
final tagFrom =
|
||||||
|
tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : '';
|
||||||
final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : '';
|
final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : '';
|
||||||
items.clear();
|
items.clear();
|
||||||
items.add(ExchangeTradeItem(
|
items.add(ExchangeTradeItem(
|
||||||
|
|
|
@ -443,7 +443,9 @@ abstract class ExchangeViewModelBase with Store {
|
||||||
request = SideShiftRequest(
|
request = SideShiftRequest(
|
||||||
depositMethod: depositCurrency,
|
depositMethod: depositCurrency,
|
||||||
settleMethod: receiveCurrency,
|
settleMethod: receiveCurrency,
|
||||||
depositAmount: depositAmount.replaceAll(',', '.'),
|
depositAmount: isFixedRateMode
|
||||||
|
? receiveAmount.replaceAll(',', '.')
|
||||||
|
: depositAmount.replaceAll(',', '.'),
|
||||||
settleAddress: receiveAddress,
|
settleAddress: receiveAddress,
|
||||||
refundAddress: depositAddress,
|
refundAddress: depositAddress,
|
||||||
);
|
);
|
||||||
|
|
|
@ -16,12 +16,10 @@ abstract class IoniaGiftCardsListViewModelBase with Store {
|
||||||
ioniaCategories = IoniaCategory.allCategories,
|
ioniaCategories = IoniaCategory.allCategories,
|
||||||
selectedIndices = ObservableList<IoniaCategory>.of([IoniaCategory.all]),
|
selectedIndices = ObservableList<IoniaCategory>.of([IoniaCategory.all]),
|
||||||
scrollOffsetFromTop = 0.0,
|
scrollOffsetFromTop = 0.0,
|
||||||
isLoggedIn = false,
|
|
||||||
merchantState = InitialIoniaMerchantLoadingState(),
|
merchantState = InitialIoniaMerchantLoadingState(),
|
||||||
createCardState = IoniaCreateCardState(),
|
createCardState = IoniaCreateCardState(),
|
||||||
searchString = '',
|
searchString = '',
|
||||||
ioniaMerchantList = <IoniaMerchant>[] {
|
ioniaMerchantList = <IoniaMerchant>[] {
|
||||||
_getAuthStatus().then((value) => isLoggedIn = value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final IoniaService ioniaService;
|
final IoniaService ioniaService;
|
||||||
|
@ -45,24 +43,17 @@ abstract class IoniaGiftCardsListViewModelBase with Store {
|
||||||
@observable
|
@observable
|
||||||
List<IoniaMerchant> ioniaMerchants;
|
List<IoniaMerchant> ioniaMerchants;
|
||||||
|
|
||||||
@observable
|
|
||||||
bool isLoggedIn;
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
List<IoniaCategory> ioniaCategories;
|
List<IoniaCategory> ioniaCategories;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
ObservableList<IoniaCategory> selectedIndices;
|
ObservableList<IoniaCategory> selectedIndices;
|
||||||
|
|
||||||
Future<bool> _getAuthStatus() async {
|
|
||||||
return await ioniaService.isLogined();
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> createCard() async {
|
Future<void> createCard() async {
|
||||||
try {
|
try {
|
||||||
createCardState = IoniaCreateCardLoading();
|
createCardState = IoniaCreateCardLoading();
|
||||||
final card = await ioniaService.createCard();
|
await ioniaService.createCard();
|
||||||
createCardState = IoniaCreateCardSuccess();
|
createCardState = IoniaCreateCardSuccess();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
createCardState = IoniaCreateCardFailure(error: e.toString());
|
createCardState = IoniaCreateCardFailure(error: e.toString());
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import connectivity_macos
|
import connectivity_plus_macos
|
||||||
import cw_monero
|
import cw_monero
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import devicelocale
|
import devicelocale
|
||||||
|
|
|
@ -56,8 +56,8 @@ dependencies:
|
||||||
# password: ^1.0.0
|
# password: ^1.0.0
|
||||||
basic_utils: ^4.3.0
|
basic_utils: ^4.3.0
|
||||||
get_it: ^7.2.0
|
get_it: ^7.2.0
|
||||||
connectivity: ^3.0.3
|
# connectivity: ^3.0.3
|
||||||
# connectivity_plus: ^2.3.5
|
connectivity_plus: ^2.3.5
|
||||||
keyboard_actions: ^4.0.1
|
keyboard_actions: ^4.0.1
|
||||||
another_flushbar: ^1.12.29
|
another_flushbar: ^1.12.29
|
||||||
archive: ^3.3.0
|
archive: ^3.3.0
|
||||||
|
|
|
@ -685,14 +685,14 @@
|
||||||
"arrive_in_this_address" : "${currency} ${tag}arrivera à cette adresse",
|
"arrive_in_this_address" : "${currency} ${tag}arrivera à cette adresse",
|
||||||
"do_not_send": "Ne pas envoyer",
|
"do_not_send": "Ne pas envoyer",
|
||||||
"error_dialog_content": "Oups, nous avons rencontré une erreur.\n\nMerci d'envoyer le rapport d'erreur à notre équipe d'assistance afin de nous permettre d'améliorer l'application.",
|
"error_dialog_content": "Oups, nous avons rencontré une erreur.\n\nMerci d'envoyer le rapport d'erreur à notre équipe d'assistance afin de nous permettre d'améliorer l'application.",
|
||||||
"scan_qr_code": "Scannez le code QR",
|
"scan_qr_code": "Scannez le QR code",
|
||||||
"cold_or_recover_wallet": "Ajoutez un cold wallet ou récupérez un paper wallet",
|
"cold_or_recover_wallet": "Ajoutez un portefeuille froid (cold wallet) ou récupérez un portefeuille papier (paper wallet)",
|
||||||
"please_wait": "S'il vous plaît, attendez",
|
"please_wait": "Merci de patienter",
|
||||||
"sweeping_wallet": "Portefeuille de balayage",
|
"sweeping_wallet": "Portefeuille (wallet) de consolidation",
|
||||||
"sweeping_wallet_alert": "Cela ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN OU LES FONDS BALAYÉS POURRAIENT ÊTRE PERDUS",
|
"sweeping_wallet_alert": "Cette opération ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN OU LES FONDS CONSOLIDÉS POURRAIENT ÊTRE PERDUS",
|
||||||
"decimal_places_error": "Trop de décimales",
|
"decimal_places_error": "Trop de décimales",
|
||||||
"edit_node": "Modifier le nœud",
|
"edit_node": "Modifier le nœud",
|
||||||
"frozen_balance": "Équilibre gelé",
|
"frozen_balance": "Solde gelé",
|
||||||
"invoice_details": "Détails de la facture",
|
"invoice_details": "Détails de la facture",
|
||||||
"donation_link_details": "Détails du lien de don",
|
"donation_link_details": "Détails du lien de don",
|
||||||
"anonpay_description": "Générez ${type}. Le destinataire peut ${method} avec n'importe quelle crypto-monnaie prise en charge, et vous recevrez des fonds dans ce portefeuille (wallet).",
|
"anonpay_description": "Générez ${type}. Le destinataire peut ${method} avec n'importe quelle crypto-monnaie prise en charge, et vous recevrez des fonds dans ce portefeuille (wallet).",
|
||||||
|
@ -709,22 +709,22 @@
|
||||||
"error_text_input_above_maximum_limit" : "Le montant est supérieur au maximum",
|
"error_text_input_above_maximum_limit" : "Le montant est supérieur au maximum",
|
||||||
"show_market_place" :"Afficher la place de marché",
|
"show_market_place" :"Afficher la place de marché",
|
||||||
"prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran",
|
"prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran",
|
||||||
"modify_2fa": "Modifier le gâteau 2FA",
|
"modify_2fa": "Modifier les paramètres Cake 2FA",
|
||||||
"disable_cake_2fa": "Désactiver le gâteau 2FA",
|
"disable_cake_2fa": "Désactiver Cake 2FA",
|
||||||
"question_to_disable_2fa":"Êtes-vous sûr de vouloir désactiver Cake 2FA ? Un code 2FA ne sera plus nécessaire pour accéder au portefeuille et à certaines fonctions.",
|
"question_to_disable_2fa":"Êtes-vous sûr de vouloir désactiver Cake 2FA ? Un code 2FA ne sera plus nécessaire pour accéder au portefeuille (wallet) et à certaines fonctions.",
|
||||||
"disable": "Désactiver",
|
"disable": "Désactiver",
|
||||||
"setup_2fa": "Gâteau d'installation 2FA",
|
"setup_2fa": "Paramétrer Cake 2FA",
|
||||||
"verify_with_2fa": "Vérifier avec Cake 2FA",
|
"verify_with_2fa": "Vérifier avec Cake 2FA",
|
||||||
"totp_code": "Code TOTP",
|
"totp_code": "Code TOTP",
|
||||||
"please_fill_totp": "Veuillez renseigner le code à 8 chiffres présent sur votre autre appareil",
|
"please_fill_totp": "Veuillez renseigner le code à 8 chiffres affiché sur votre autre appareil",
|
||||||
"totp_2fa_success": "Succès! Cake 2FA activé pour ce portefeuille. N'oubliez pas de sauvegarder votre graine mnémonique au cas où vous perdriez l'accès au portefeuille.",
|
"totp_2fa_success": "Succès! Cake 2FA est activé pour ce portefeuille. N'oubliez pas de sauvegarder votre phrase secrète (seed) au cas où vous perdriez l'accès au portefeuille (wallet).",
|
||||||
"totp_verification_success" :"Vérification réussie !",
|
"totp_verification_success" :"Vérification réussie !",
|
||||||
"totp_2fa_failure": "Code incorrect. Veuillez essayer un code différent ou générer une nouvelle clé secrète. Utilisez une application 2FA compatible qui prend en charge les codes à 8 chiffres et SHA512.",
|
"totp_2fa_failure": "Code incorrect. Veuillez essayer un code différent ou générer un nouveau secret TOTP. Utilisez une application 2FA compatible qui prend en charge les codes à 8 chiffres et SHA512.",
|
||||||
"enter_totp_code": "Veuillez entrer le code TOTP.",
|
"enter_totp_code": "Veuillez entrer le code TOTP.",
|
||||||
"add_secret_code":"Ajouter ce code secret à un autre appareil",
|
"add_secret_code":"Configurer un autre appareil à l'aide de ce secret TOTP",
|
||||||
"totp_secret_code":"Code secret TOTP",
|
"totp_secret_code":"Secret TOTP",
|
||||||
"important_note": "Note importante",
|
"important_note": "Note importante",
|
||||||
"setup_2fa_text": "Cake 2FA n'est PAS aussi sûr que le stockage à froid. 2FA protège contre les types d'attaques de base, comme votre ami fournissant votre empreinte digitale pendant que vous dormez.\n\n Cake 2FA ne protège PAS contre un appareil compromis par un attaquant sophistiqué.\n\n Si vous perdez l'accès à vos codes 2FA , VOUS PERDREZ L'ACCÈS À CE PORTEFEUILLE. Vous devrez restaurer votre portefeuille à partir de graines mnémotechniques. VOUS DEVEZ DONC SAUVEGARDER VOS SEMENCES MNEMONIQUES ! De plus, quelqu'un ayant accès à vos graines mnémoniques pourra voler vos fonds, en contournant Cake 2FA.\n\n Le personnel d'assistance de Cake ne pourra pas vous aider si vous perdez l'accès à vos graines mnémoniques, puisque Cake est un portefeuille non dépositaire.",
|
"setup_2fa_text": "Cake 2FA (Authentification à 2 Facteurs) n'est PAS aussi sûr que le stockage à froid. Cake 2FA protège contre les attaques basiques, comme un ami fournissant votre empreinte digitale pendant que vous dormez.\n\n Cake 2FA ne protège PAS contre un appareil compromis par un attaquant sophistiqué.\n\n Si vous perdez l'accès à vos codes 2FA , VOUS PERDREZ L'ACCÈS À CE PORTEFEUILLE (WALLET). Vous devrez restaurer votre portefeuille à partir de sa phrase secrète (seed). VOUS DEVEZ DONC SAUVEGARDER VOTRE PHRASE SECRÈTE ! De plus, quelqu'un ayant accès à votre phrase secrète pourra voler vos fonds, en contournant Cake 2FA.\n\n Le personnel d'assistance de Cake ne pourra pas vous aider si vous perdez l'accès à votre phrase secrète, puisque Cake est un portefeuille non dépositaire (non custodial).",
|
||||||
"setup_totp_recommended": "Configurer TOTP (recommandé)",
|
"setup_totp_recommended": "Configurer TOTP (recommandé)",
|
||||||
"disable_buy": "Désactiver l'action d'achat",
|
"disable_buy": "Désactiver l'action d'achat",
|
||||||
"disable_sell": "Désactiver l'action de vente"
|
"disable_sell": "Désactiver l'action de vente"
|
||||||
|
|
|
@ -20,7 +20,6 @@ class SecretKey {
|
||||||
SecretKey('moonPayApiKey', () => ''),
|
SecretKey('moonPayApiKey', () => ''),
|
||||||
SecretKey('moonPaySecretKey', () => ''),
|
SecretKey('moonPaySecretKey', () => ''),
|
||||||
SecretKey('sideShiftAffiliateId', () => ''),
|
SecretKey('sideShiftAffiliateId', () => ''),
|
||||||
SecretKey('sideShiftApiKey', () => ''),
|
|
||||||
SecretKey('simpleSwapApiKey', () => ''),
|
SecretKey('simpleSwapApiKey', () => ''),
|
||||||
SecretKey('simpleSwapApiKeyDesktop', () => ''),
|
SecretKey('simpleSwapApiKeyDesktop', () => ''),
|
||||||
SecretKey('anypayToken', () => ''),
|
SecretKey('anypayToken', () => ''),
|
||||||
|
|
Loading…
Reference in a new issue