Merge redesign part 1.

This commit is contained in:
M
2020-09-01 14:18:07 +03:00
126 changed files with 4852 additions and 2871 deletions
@@ -8,6 +8,7 @@ import 'package:cake_wallet/src/domain/common/transaction_info.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
@@ -22,7 +23,6 @@ import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:cake_wallet/store/dashboard/trade_filter_store.dart';
import 'package:cake_wallet/store/dashboard/transaction_filter_store.dart';
import 'package:cake_wallet/view_model/dashboard/formatted_item_list.dart';
import 'package:cake_wallet/store/dashboard/page_view_store.dart';
part 'dashboard_view_model.g.dart';
@@ -34,8 +34,41 @@ abstract class DashboardViewModelBase with Store {
this.appStore,
this.tradesStore,
this.tradeFilterStore,
this.transactionFilterStore,
this.pageViewStore}) {
this.transactionFilterStore}) {
filterItems = {
S.current.transactions: [
FilterItem(
value: transactionFilterStore.displayIncoming,
caption: S.current.incoming,
onChanged: (value) => transactionFilterStore.toggleIncoming()),
FilterItem(
value: transactionFilterStore.displayOutgoing,
caption: S.current.outgoing,
onChanged: (value) => transactionFilterStore.toggleOutgoing()),
FilterItem(
value: false,
caption: S.current.transactions_by_date,
onChanged: null),
],
S.current.trades: [
FilterItem(
value: tradeFilterStore.displayXMRTO,
caption: 'XMR.TO',
onChanged: (value) => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.xmrto)),
FilterItem(
value: tradeFilterStore.displayChangeNow,
caption: 'Change.NOW',
onChanged: (value) => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.changeNow)),
FilterItem(
value: tradeFilterStore.displayMorphToken,
caption: 'MorphToken',
onChanged: (value) => tradeFilterStore
.toggleDisplayExchange(ExchangeProviderDescription.morphToken)),
]
};
name = appStore.wallet?.name;
wallet ??= appStore.wallet;
type = wallet.type;
@@ -69,9 +102,6 @@ abstract class DashboardViewModelBase with Store {
@observable
String subname;
@computed
double get currentPage => pageViewStore.currentPage;
@computed
String get address => wallet.address;
@@ -108,7 +138,7 @@ abstract class DashboardViewModelBase with Store {
final _items = <ActionListItem>[];
_items.addAll(transactionFilterStore.filtered(transactions: transactions));
_items.addAll(tradeFilterStore.filtered(trades: trades));
_items.addAll(tradeFilterStore.filtered(trades: trades, wallet: wallet));
return formattedItemsList(_items);
}
@@ -125,7 +155,7 @@ abstract class DashboardViewModelBase with Store {
TransactionFilterStore transactionFilterStore;
PageViewStore pageViewStore;
Map<String, List<FilterItem>> filterItems;
ReactionDisposer _reaction;
@@ -0,0 +1,7 @@
class FilterItem {
FilterItem({this.value, this.caption, this.onChanged});
bool value;
String caption;
Function(bool) onChanged;
}
@@ -0,0 +1,93 @@
import 'dart:async';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/src/domain/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/src/domain/exchange/morphtoken/morphtoken_exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_item.dart';
import 'package:cake_wallet/generated/i18n.dart';
part 'exchange_trade_view_model.g.dart';
class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeViewModel;
abstract class ExchangeTradeViewModelBase with Store {
ExchangeTradeViewModelBase({this.wallet, this.trades, this.tradesStore}) {
trade = tradesStore.trade;
isSendable = trade.from == wallet.currency ||
trade.provider == ExchangeProviderDescription.xmrto;
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<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),
]);
_updateTrade();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
}
final WalletBase wallet;
final Box<Trade> trades;
final TradesStore tradesStore;
@observable
Trade trade;
@observable
bool isSendable;
@observable
ObservableList<ExchangeTradeItem> 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;
} catch (e) {
print(e.toString());
}
}
}
@@ -0,0 +1,298 @@
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/limits.dart';
import 'package:cake_wallet/src/domain/exchange/trade.dart';
import 'package:cake_wallet/src/stores/exchange/limits_state.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart';
import 'package:cake_wallet/src/domain/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/changenow/changenow_request.dart';
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_trade_request.dart';
import 'package:cake_wallet/src/domain/exchange/morphtoken/morphtoken_exchange_provider.dart';
import 'package:cake_wallet/src/domain/exchange/morphtoken/morphtoken_request.dart';
import 'package:cake_wallet/store/templates/exchange_template_store.dart';
import 'package:cake_wallet/src/domain/exchange/exchange_template.dart';
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}) {
providerList = [
XMRTOExchangeProvider(),
ChangeNowExchangeProvider(),
MorphTokenExchangeProvider(trades: trades)
];
provider = providerList[ 0 ];
depositCurrency = CryptoCurrency.xmr;
receiveCurrency = CryptoCurrency.btc;
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
depositAmount = '';
receiveAmount = '';
depositAddress = '';
receiveAddress = '';
limitsState = LimitsInitialState();
tradeState = ExchangeTradeStateInitial();
_cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
loadLimits();
}
final WalletBase wallet;
final Box<Trade> trades;
final ExchangeTemplateStore exchangeTemplateStore;
final TradesStore tradesStore;
@observable
ExchangeProvider provider;
@observable
List<ExchangeProvider> providerList;
@observable
CryptoCurrency depositCurrency;
@observable
CryptoCurrency receiveCurrency;
@observable
LimitsState limitsState;
@observable
ExchangeTradeState tradeState;
@observable
String depositAmount;
@observable
String receiveAmount;
@observable
String depositAddress;
@observable
String receiveAddress;
@observable
bool isDepositAddressEnabled;
@observable
bool isReceiveAddressEnabled;
Limits limits;
NumberFormat _cryptoNumberFormat;
@computed
ObservableList<ExchangeTemplate> get templates =>
exchangeTemplateStore.templates;
@action
void changeProvider({ExchangeProvider provider}) {
this.provider = provider;
depositAmount = '';
receiveAmount = '';
loadLimits();
}
@action
void changeDepositCurrency({CryptoCurrency currency}) {
depositCurrency = currency;
_onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
}
@action
void changeReceiveCurrency({CryptoCurrency currency}) {
receiveCurrency = currency;
_onPairChange();
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
}
@action
void changeReceiveAmount({String amount}) {
receiveAmount = amount;
if (amount == null || amount.isEmpty) {
depositAmount = '';
receiveAmount = '';
return;
}
final _amount = double.parse(amount) ?? 0;
provider
.calculateAmount(
from: depositCurrency, to: receiveCurrency, amount: _amount)
.then((amount) => _cryptoNumberFormat.format(amount).toString().replaceAll(RegExp("\\,"), ""))
.then((amount) => depositAmount = amount);
}
@action
void changeDepositAmount({String amount}) {
depositAmount = amount;
if (amount == null || amount.isEmpty) {
depositAmount = '';
receiveAmount = '';
return;
}
final _amount = double.parse(amount);
provider
.calculateAmount(
from: depositCurrency, to: receiveCurrency, amount: _amount)
.then((amount) => _cryptoNumberFormat.format(amount).toString().replaceAll(RegExp("\\,"), ""))
.then((amount) => receiveAmount = amount);
}
@action
Future loadLimits() async {
limitsState = LimitsIsLoading();
try {
limits = await provider.fetchLimits(
from: depositCurrency, to: receiveCurrency);
limitsState = LimitsLoadedSuccessfully(limits: limits);
} catch (e) {
limitsState = LimitsLoadedFailure(error: e.toString());
}
}
@action
Future createTrade() async {
TradeRequest request;
String amount;
CryptoCurrency currency;
if (provider is XMRTOExchangeProvider) {
request = XMRTOTradeRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount,
address: receiveAddress,
refundAddress: depositAddress);
amount = depositAmount;
currency = depositCurrency;
}
if (provider is ChangeNowExchangeProvider) {
request = ChangeNowRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount,
refundAddress: depositAddress,
address: receiveAddress);
amount = depositAmount;
currency = depositCurrency;
}
if (provider is MorphTokenExchangeProvider) {
request = MorphTokenRequest(
from: depositCurrency,
to: receiveCurrency,
amount: depositAmount,
refundAddress: depositAddress,
address: receiveAddress);
amount = depositAmount;
currency = depositCurrency;
}
if (limitsState is LimitsLoadedSuccessfully && amount != null) {
if (double.parse(amount) < limits.min) {
tradeState = TradeIsCreatedFailure(error: S.current.error_text_minimal_limit('${provider.description}',
'${limits.min}', currency.toString()));
} else if (limits.max != null && double.parse(amount) > limits.max) {
tradeState = TradeIsCreatedFailure(error: S.current.error_text_maximum_limit('${provider.description}',
'${limits.max}', currency.toString()));
} else {
try {
tradeState = TradeIsCreating();
final trade = await provider.createTrade(request: request);
trade.walletId = wallet.id;
tradesStore.setTrade(trade);
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
} catch (e) {
tradeState = TradeIsCreatedFailure(error: e.toString());
}
}
} else {
tradeState = TradeIsCreatedFailure(error: S.current.error_text_limits_loading_failed('${provider.description}'));
}
}
@action
void reset() {
depositAmount = '';
receiveAmount = '';
depositCurrency = CryptoCurrency.xmr;
receiveCurrency = CryptoCurrency.btc;
depositAddress = depositCurrency == wallet.currency ? wallet.address : '';
receiveAddress = receiveCurrency == wallet.currency ? wallet.address : '';
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
_onPairChange();
}
List<ExchangeProvider> providersForCurrentPair() {
return _providersForPair(from: depositCurrency, to: receiveCurrency);
}
List<ExchangeProvider> _providersForPair(
{CryptoCurrency from, CryptoCurrency to}) {
final providers = providerList
.where((provider) => provider.pairList
.where((pair) =>
pair.from == depositCurrency && pair.to == receiveCurrency)
.isNotEmpty)
.toList();
return providers;
}
void _onPairChange() {
final isPairExist = provider.pairList
.where((pair) =>
pair.from == depositCurrency && pair.to == receiveCurrency)
.isNotEmpty;
if (!isPairExist) {
final provider =
_providerForPair(from: depositCurrency, to: receiveCurrency);
if (provider != null) {
changeProvider(provider: provider);
}
}
depositAmount = '';
receiveAmount = '';
loadLimits();
}
ExchangeProvider _providerForPair({CryptoCurrency from, CryptoCurrency to}) {
final providers = _providersForPair(from: from, to: to);
return providers.isNotEmpty ? providers[0] : null;
}
}
+221
View File
@@ -0,0 +1,221 @@
import 'package:cake_wallet/core/address_validator.dart';
import 'package:cake_wallet/core/amount_validator.dart';
import 'package:cake_wallet/core/template_validator.dart';
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/monero/monero_wallet.dart';
import 'package:cake_wallet/src/domain/common/balance.dart';
import 'package:cake_wallet/src/domain/common/balance_display_mode.dart';
import 'package:cake_wallet/src/domain/common/calculate_estimated_fee.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
import 'package:cake_wallet/src/domain/common/sync_status.dart';
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/templates/send_template_store.dart';
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/monero/monero_wallet_service.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet_creation_credentials.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/core/wallet_credentials.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/domain/common/openalias_record.dart';
import 'package:cake_wallet/store/dashboard/fiat_convertation_store.dart';
import 'package:cake_wallet/src/domain/common/template.dart';
part 'send_view_model.g.dart';
abstract class SendViewModelState {}
class InitialSendViewModelState extends SendViewModelState {}
class TransactionIsCreating extends SendViewModelState {}
class TransactionCreatedSuccessfully extends SendViewModelState {}
class TransactionCommitting extends SendViewModelState {}
class TransactionCommitted extends SendViewModelState {}
class SendingFailed extends SendViewModelState {
SendingFailed({@required this.error});
String error;
}
class SendViewModel = SendViewModelBase with _$SendViewModel;
abstract class SendViewModelBase with Store {
SendViewModelBase(
this._wallet,
this._settingsStore,
this._fiatConvertationStore,
this.sendTemplateStore) {
state = InitialSendViewModelState();
_cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
_fiatNumberFormat = NumberFormat()..maximumFractionDigits = 2;
}
NumberFormat _cryptoNumberFormat;
NumberFormat _fiatNumberFormat;
@observable
SendViewModelState state;
@observable
String fiatAmount;
@observable
String cryptoAmount;
@observable
String address;
String get cryptoCurrencyTitle {
var _currencyTitle = '';
if (_wallet is MoneroWallet) {
_currencyTitle = 'Monero';
}
if (_wallet is BitcoinWallet) {
_currencyTitle = 'Bitcoin';
}
return _currencyTitle;
}
String get pageTitle => S.current.send_title + ' ' + cryptoCurrencyTitle;
FiatCurrency get fiat => _settingsStore.fiatCurrency;
TransactionPriority get transactionPriority =>
_settingsStore.transactionPriority;
double get estimatedFee =>
calculateEstimatedFee(priority: transactionPriority);
String get name => _wallet.name;
CryptoCurrency get currency => _wallet.currency;
Validator get amountValidator => AmountValidator(type: _wallet.type);
Validator get addressValidator => AddressValidator(type: _wallet.currency);
Validator get templateValidator => TemplateValidator();
@computed
double get price => _fiatConvertationStore.price;
@computed
ObservableList<Template> get templates => ObservableList.of(
sendTemplateStore.templates.where((item)
=> item.cryptoCurrency == _wallet.currency.title).toList());
@computed
String get balance {
var _balance = '0.0';
if (_wallet is MoneroWallet) {
_balance = _wallet.balance.formattedUnlockedBalance.toString();
}
if (_wallet is BitcoinWallet) {
_balance = _wallet.balance.confirmedFormatted.toString();
}
return _settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance
? '---'
: _balance;
}
@computed
SyncStatus get status => _wallet.syncStatus;
@action
void changeCryptoAmount(String amount) {
cryptoAmount = amount;
if (cryptoAmount != null && cryptoAmount.isNotEmpty) {
_calculateFiatAmount();
} else {
fiatAmount = '';
}
}
@action
void changeFiatAmount(String amount) {
fiatAmount = amount;
if (fiatAmount != null && fiatAmount.isNotEmpty) {
_calculateCryptoAmount();
} else {
cryptoAmount = '';
}
}
@action
Future _calculateFiatAmount() async {
try {
final amount = double.parse(cryptoAmount) * price;
fiatAmount = _fiatNumberFormat.format(amount);
} catch (e) {
fiatAmount = '0.00';
}
}
@action
Future _calculateCryptoAmount() async {
try {
final amount = double.parse(fiatAmount) / price;
cryptoAmount = _cryptoNumberFormat.format(amount);
} catch (e) {
cryptoAmount = '0.00';
}
}
@action
void changeAddress(String address) {
this.address = address;
}
@action
void setSendAll() {
cryptoAmount = 'ALL';
fiatAmount = '';
}
final WalletBase _wallet;
final SettingsStore _settingsStore;
final FiatConvertationStore _fiatConvertationStore;
final SendTemplateStore sendTemplateStore;
String recordName;
String recordAddress;
Future<bool> isOpenaliasRecord(String name) async {
final _openaliasRecord = await OpenaliasRecord
.fetchAddressAndName(OpenaliasRecord.formatDomainName(name));
recordAddress = _openaliasRecord.address;
recordName = _openaliasRecord.name;
return recordAddress != name;
}
Future<void> createTransaction() async {}
Future<void> commitTransaction() async {}
}
@@ -1,5 +1,8 @@
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/theme_changer_store.dart';
import 'package:cake_wallet/themes.dart';
import 'package:flutter/cupertino.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/routes.dart';
@@ -75,7 +78,11 @@ abstract class SettingsViewModelBase with Store {
title: S.current.settings_dark_mode,
value: () => _settingsStore.isDarkTheme,
onValueChange: (bool value) {
// FIXME: Implement me
_settingsStore.isDarkTheme = value;
getIt
.get<ThemeChangerStore>()
.themeChanger
.setTheme(value ? Themes.darkTheme : Themes.lightTheme);
})
],
[