Merged 4.1.0

This commit is contained in:
M
2021-01-13 19:18:28 +02:00
149 changed files with 6461 additions and 2150 deletions
@@ -1,4 +1,7 @@
import 'dart:async';
import 'package:cake_wallet/entities/wallet_contact.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/contact_record.dart';
@@ -11,15 +14,22 @@ class ContactListViewModel = ContactListViewModelBase
with _$ContactListViewModel;
abstract class ContactListViewModelBase with Store {
ContactListViewModelBase(this.contactSource)
: contacts = ObservableList<ContactRecord>() {
ContactListViewModelBase(this.contactSource, this.walletInfoSource)
: contacts = ObservableList<ContactRecord>(),
walletContacts = walletInfoSource.values
.where((info) => info.address?.isNotEmpty ?? false)
.map((info) => WalletContact(
info.address, info.name, walletTypeToCryptoCurrency(info.type)))
.toList() {
_subscription = contactSource.bindToListWithTransform(
contacts, (Contact contact) => ContactRecord(contactSource, contact),
initialFire: true);
}
final Box<Contact> contactSource;
final Box<WalletInfo> walletInfoSource;
final ObservableList<ContactRecord> contacts;
final List<WalletContact> walletContacts;
StreamSubscription<BoxEvent> _subscription;
Future<void> delete(ContactRecord contact) async => contact.original.delete();
+117 -57
View File
@@ -1,10 +1,13 @@
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero_wallet.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/calculate_fiat_amount.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/view_model/dashboard/wallet_balance.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:flutter/cupertino.dart';
@@ -15,97 +18,154 @@ part 'balance_view_model.g.dart';
class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel;
abstract class BalanceViewModelBase with Store {
BalanceViewModelBase({
@required this.appStore,
@required this.settingsStore,
@required this.fiatConvertationStore
}) : isReversing = false;
BalanceViewModelBase(
{@required this.appStore,
@required this.settingsStore,
@required this.fiatConvertationStore}) {
isReversing = false;
wallet ??= appStore.wallet;
_reaction = reaction((_) => appStore.wallet, _onWalletChange);
final _wallet = wallet;
if (_wallet is MoneroWallet) {
balance = _wallet.balance;
}
if (_wallet is BitcoinWallet) {
balance = _wallet.balance;
}
_onCurrentWalletChangeReaction =
reaction<void>((_) => wallet.balance, (dynamic balance) {
if (balance is Balance) {
this.balance = balance;
}
});
}
final AppStore appStore;
final SettingsStore settingsStore;
final FiatConversionStore fiatConvertationStore;
bool get canReverse => false;
@observable
bool isReversing;
@observable
Balance balance;
@observable
WalletBase<Balance> wallet;
@computed
double get price => fiatConvertationStore.prices[appStore.wallet.currency];
@computed
BalanceDisplayMode get savedDisplayMode => settingsStore.balanceDisplayMode;
@computed
BalanceDisplayMode get displayMode => isReversing
? (savedDisplayMode == BalanceDisplayMode.availableBalance
? BalanceDisplayMode.fullBalance
: BalanceDisplayMode.availableBalance)
: savedDisplayMode;
? (savedDisplayMode == BalanceDisplayMode.availableBalance
? BalanceDisplayMode.fullBalance
: BalanceDisplayMode.availableBalance)
: savedDisplayMode;
@computed
double get price => fiatConvertationStore.price;
@computed
String get cryptoBalance {
final walletBalance = _walletBalance;
var balance = '---';
if (displayMode == BalanceDisplayMode.availableBalance) {
balance = walletBalance.unlockedBalance ?? '0.0';
String get availableBalanceLabel {
if (wallet.type == WalletType.monero) {
return S.current.xmr_available_balance;
}
if (displayMode == BalanceDisplayMode.fullBalance) {
balance = walletBalance.totalBalance ?? '0.0';
}
return balance;
return S.current.confirmed;
}
@computed
String get fiatBalance {
String get additionalBalanceLabel {
if (wallet.type == WalletType.monero) {
return S.current.xmr_full_balance;
}
return S.current.unconfirmed;
}
@computed
String get availableBalance {
final walletBalance = _walletBalance;
if (settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return walletBalance.formattedAvailableBalance;
}
@computed
String get additionalBalance {
final walletBalance = _walletBalance;
if (settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
return walletBalance.formattedAdditionalBalance;
}
@computed
String get availableFiatBalance {
final walletBalance = _walletBalance;
final fiatCurrency = settingsStore.fiatCurrency;
var balance = '---';
final totalBalance = _getFiatBalance(
price: price,
cryptoAmount: walletBalance.totalBalance
);
final unlockedBalance = _getFiatBalance(
price: price,
cryptoAmount: walletBalance.unlockedBalance
);
if (displayMode == BalanceDisplayMode.availableBalance) {
balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00';
if (settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
if (displayMode == BalanceDisplayMode.fullBalance) {
balance = fiatCurrency.toString() + ' ' + totalBalance ?? '0.00';
}
return balance;
return fiatCurrency.toString() +
' ' +
_getFiatBalance(
price: price,
cryptoAmount: walletBalance.formattedAvailableBalance);
}
@computed
WalletBalance get _walletBalance {
final _wallet = appStore.wallet;
String get additionalFiatBalance {
final walletBalance = _walletBalance;
final fiatCurrency = settingsStore.fiatCurrency;
if (_wallet is MoneroWallet) {
return WalletBalance(
unlockedBalance: _wallet.balance.formattedUnlockedBalance,
totalBalance: _wallet.balance.formattedFullBalance);
if (settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance) {
return '---';
}
if (_wallet is BitcoinWallet) {
return WalletBalance(
unlockedBalance: _wallet.balance.totalFormatted,
totalBalance: _wallet.balance.totalFormatted);
}
return null;
return fiatCurrency.toString() +
' ' +
_getFiatBalance(
price: price,
cryptoAmount: walletBalance.formattedAdditionalBalance);
}
@computed
Balance get _walletBalance => wallet.balance;
@computed
CryptoCurrency get currency => appStore.wallet.currency;
ReactionDisposer _onCurrentWalletChangeReaction;
ReactionDisposer _reaction;
@action
void _onWalletChange(WalletBase<Balance> wallet) {
this.wallet = wallet;
balance = wallet.balance;
_onCurrentWalletChangeReaction?.reaction?.dispose();
_onCurrentWalletChangeReaction = reaction<Balance>(
(_) => wallet.balance, (Balance balance) => this.balance = balance);
}
String _getFiatBalance({double price, String cryptoAmount}) {
if (cryptoAmount == null) {
return '0.00';
@@ -113,4 +173,4 @@ abstract class BalanceViewModelBase with Store {
return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount);
}
}
}
@@ -1,5 +1,6 @@
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/entities/transaction_history.dart';
import 'package:cake_wallet/monero/account.dart';
import 'package:cake_wallet/monero/monero_balance.dart';
@@ -184,7 +185,9 @@ abstract class DashboardViewModelBase with Store {
}
@observable
WalletBase wallet;
WalletBase<Balance> wallet;
bool get hasRescan => wallet.type == WalletType.monero;
BalanceViewModel balanceViewModel;
@@ -210,8 +213,9 @@ abstract class DashboardViewModelBase with Store {
}
@action
void _onWalletChange(WalletBase wallet) {
void _onWalletChange(WalletBase<Balance> wallet) {
this.wallet = wallet;
type = wallet.type;
name = wallet.name;
if (wallet is MoneroWallet) {
@@ -228,6 +232,8 @@ abstract class DashboardViewModelBase with Store {
_onMoneroTransactionsUpdate(wallet);
} else {
subname = null;
transactions.clear();
transactions.addAll(wallet.transactionHistory.transactions.values.map(
@@ -236,6 +242,21 @@ abstract class DashboardViewModelBase with Store {
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore)));
}
connectMapToListWithTransform(
appStore.wallet.transactionHistory.transactions,
transactions,
(TransactionInfo val) => TransactionListItem(
transaction: val,
balanceViewModel: balanceViewModel,
settingsStore: appStore.settingsStore),
filter: (TransactionInfo tx) {
if (tx is MoneroTransactionInfo && wallet is MoneroWallet) {
return tx.accountIndex == wallet.account.id;
}
return true;
});
}
@action
@@ -39,20 +39,11 @@ abstract class ExchangeTradeViewModelBase with Store {
}
items = ObservableList<ExchangeTradeItem>();
items.addAll([
ExchangeTradeItem(
title: S.current.id, data: '${trade.id}', isCopied: true),
ExchangeTradeItem(
title: S.current.amount, data: '${trade.amount}', isCopied: false),
ExchangeTradeItem(
title: S.current.status, data: '${trade.state}', isCopied: false),
ExchangeTradeItem(
title: S.current.widgets_address + ':',
data: trade.inputAddress,
isCopied: true),
]);
_updateItems();
_updateTrade();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
}
@@ -95,8 +86,27 @@ abstract class ExchangeTradeViewModelBase with Store {
}
trade = updatedTrade;
_updateItems();
} catch (e) {
print(e.toString());
}
}
void _updateItems() {
items?.clear();
items.addAll([
ExchangeTradeItem(
title: S.current.id, data: '${trade.id}', isCopied: true),
ExchangeTradeItem(
title: S.current.amount, data: '${trade.amount}', isCopied: false),
ExchangeTradeItem(
title: S.current.status, data: '${trade.state}', isCopied: false),
ExchangeTradeItem(
title: S.current.widgets_address + ':',
data: trade.inputAddress,
isCopied: true),
]);
}
}
@@ -1,3 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:cake_wallet/entities/sync_status.dart';
@@ -7,6 +9,7 @@ import 'package:cake_wallet/exchange/limits.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/limits_state.dart';
import 'package:cake_wallet/store/dashboard/trades_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
@@ -27,8 +30,8 @@ part 'exchange_view_model.g.dart';
class ExchangeViewModel = ExchangeViewModelBase with _$ExchangeViewModel;
abstract class ExchangeViewModelBase with Store {
ExchangeViewModelBase(
this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore) {
ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore,
this.tradesStore, this._settingsStore) {
providerList = [
XMRTOExchangeProvider(),
ChangeNowExchangeProvider(),
@@ -104,10 +107,6 @@ abstract class ExchangeViewModelBase with Store {
@observable
bool isReceiveAmountEntered;
Limits limits;
NumberFormat _cryptoNumberFormat;
@computed
SyncStatus get status => wallet.syncStatus;
@@ -115,6 +114,15 @@ abstract class ExchangeViewModelBase with Store {
ObservableList<ExchangeTemplate> get templates =>
_exchangeTemplateStore.templates;
bool get hasAllAmount =>
wallet.type == WalletType.bitcoin && depositCurrency == wallet.currency;
Limits limits;
NumberFormat _cryptoNumberFormat;
SettingsStore _settingsStore;
@action
void changeProvider({ExchangeProvider provider}) {
this.provider = provider;
@@ -264,9 +272,8 @@ abstract class ExchangeViewModelBase with Store {
await trades.add(trade);
tradeState = TradeIsCreatedSuccessfully(trade: trade);
} catch (e) {
tradeState = TradeIsCreatedFailure(
title: provider.title,
error: e.toString());
tradeState =
TradeIsCreatedFailure(title: provider.title, error: e.toString());
}
}
} else {
@@ -291,6 +298,22 @@ abstract class ExchangeViewModelBase with Store {
_onPairChange();
}
@action
void calculateDepositAllAmount() {
if (wallet is BitcoinWallet) {
final availableBalance = wallet.balance.available;
final fee = BitcoinWalletBase.feeAmountForPriority(
_settingsStore.transactionPriority);
if (availableBalance < fee || availableBalance == 0) {
return;
}
final amount = availableBalance - fee;
changeDepositAmount(amount: bitcoinAmountToString(amount: amount));
}
}
void updateTemplate() => _exchangeTemplateStore.update();
void addTemplate(
@@ -13,16 +13,18 @@ part 'node_list_view_model.g.dart';
class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
abstract class NodeListViewModelBase with Store {
NodeListViewModelBase(this._nodeSource, this._wallet, this.settingsStore)
NodeListViewModelBase(this._nodeSource, this.wallet, this.settingsStore)
: nodes = ObservableList<Node>() {
_nodeSource.bindToList(nodes,
filter: (Node val) => val?.type == _wallet.type, initialFire: true);
filter: (Node val) => val?.type == wallet.type, initialFire: true);
}
@computed
Node get currentNode => settingsStore.nodes[wallet.type];
final ObservableList<Node> nodes;
final SettingsStore settingsStore;
final WalletBase _wallet;
final WalletBase wallet;
final Box<Node> _nodeSource;
Future<void> reset() async {
@@ -30,14 +32,12 @@ abstract class NodeListViewModelBase with Store {
Node node;
switch (_wallet.type) {
switch (wallet.type) {
case WalletType.bitcoin:
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource);
break;
case WalletType.monero:
node = getMoneroDefaultNode(
nodes: _nodeSource,
);
node = getMoneroDefaultNode(nodes: _nodeSource);
break;
default:
break;
@@ -50,5 +50,5 @@ abstract class NodeListViewModelBase with Store {
Future<void> delete(Node node) async => node.delete();
Future<void> setAsCurrent(Node node) async =>
settingsStore.currentNode = node;
settingsStore.nodes[wallet.type] = node;
}
+71 -20
View File
@@ -1,3 +1,5 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:hive/hive.dart';
import 'package:intl/intl.dart';
@@ -36,7 +38,15 @@ abstract class SendViewModelBase with Store {
this._fiatConversationStore, this.transactionDescriptionBox)
: state = InitialExecutionState(),
_cryptoNumberFormat = NumberFormat(),
note = '',
sendAll = false {
final _priority = _settingsStore.transactionPriority;
if (!TransactionPriority.forWalletType(walletType).contains(_priority)) {
_settingsStore.transactionPriority =
TransactionPriority.forWalletType(walletType).first;
}
_setCryptoNumMaximumFractionDigits();
}
@@ -52,6 +62,9 @@ abstract class SendViewModelBase with Store {
@observable
String address;
@observable
String note;
@observable
bool sendAll;
@@ -59,6 +72,50 @@ abstract class SendViewModelBase with Store {
double get estimatedFee =>
_wallet.calculateEstimatedFee(_settingsStore.transactionPriority);
@computed
String get estimatedFeeFiatAmount {
try {
final fiat = calculateFiatAmountRaw(
price: _fiatConversationStore.prices[_wallet.currency],
cryptoAmount: estimatedFee);
return fiat;
} catch (_) {
return '0.00';
}
}
@computed
String get pendingTransactionFiatAmount {
try {
if (pendingTransaction != null) {
final fiat = calculateFiatAmount(
price: _fiatConversationStore.prices[_wallet.currency],
cryptoAmount: pendingTransaction.amountFormatted);
return fiat;
} else {
return '0.00';
}
} catch (_) {
return '0.00';
}
}
@computed
String get pendingTransactionFeeFiatAmount {
try {
if (pendingTransaction != null) {
final fiat = calculateFiatAmount(
price: _fiatConversationStore.prices[_wallet.currency],
cryptoAmount: pendingTransaction.feeFormatted);
return fiat;
} else {
return '0.00';
}
} catch (_) {
return '0.00';
}
}
FiatCurrency get fiat => _settingsStore.fiatCurrency;
TransactionPriority get transactionPriority =>
@@ -77,19 +134,7 @@ abstract class SendViewModelBase with Store {
PendingTransaction pendingTransaction;
@computed
String get balance {
String balance = '0.0';
if (_wallet is MoneroWallet) {
balance = _wallet.balance.formattedUnlockedBalance as String ?? '';
}
if (_wallet is BitcoinWallet) {
balance = _wallet.balance.confirmedFormatted as String ?? '';
}
return balance;
}
String get balance => _wallet.balance.formattedAvailableBalance ?? '0.0';
@computed
bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
@@ -97,6 +142,7 @@ abstract class SendViewModelBase with Store {
@computed
ObservableList<Template> get templates => _sendTemplateStore.templates;
WalletType get walletType => _wallet.type;
final WalletBase _wallet;
final SettingsStore _settingsStore;
final SendTemplateStore _sendTemplateStore;
@@ -113,6 +159,7 @@ abstract class SendViewModelBase with Store {
cryptoAmount = '';
fiatAmount = '';
address = '';
note = '';
}
@action
@@ -132,10 +179,14 @@ abstract class SendViewModelBase with Store {
state = TransactionCommitting();
await pendingTransaction.commit();
if (_settingsStore.shouldSaveRecipientAddress &&
(pendingTransaction.id?.isNotEmpty ?? false)) {
await transactionDescriptionBox.add(TransactionDescription(
id: pendingTransaction.id, recipientAddress: address));
if (pendingTransaction.id?.isNotEmpty ?? false) {
_settingsStore.shouldSaveRecipientAddress
? await transactionDescriptionBox.add(TransactionDescription(
id: pendingTransaction.id,
recipientAddress: address,
transactionNote: note))
: await transactionDescriptionBox.add(TransactionDescription(
id: pendingTransaction.id, transactionNote: note));
}
state = TransactionCommitted();
@@ -175,7 +226,7 @@ abstract class SendViewModelBase with Store {
void _updateFiatAmount() {
try {
final fiat = calculateFiatAmount(
price: _fiatConversationStore.price,
price: _fiatConversationStore.prices[_wallet.currency],
cryptoAmount: cryptoAmount.replaceAll(',', '.'));
if (fiatAmount != fiat) {
fiatAmount = fiat;
@@ -189,7 +240,7 @@ abstract class SendViewModelBase with Store {
void _updateCryptoAmount() {
try {
final crypto = double.parse(fiatAmount.replaceAll(',', '.')) /
_fiatConversationStore.price;
_fiatConversationStore.prices[_wallet.currency];
final cryptoAmountTmp = _cryptoNumberFormat.format(crypto);
if (cryptoAmount != cryptoAmountTmp) {
@@ -205,7 +256,7 @@ abstract class SendViewModelBase with Store {
switch (_wallet.type) {
case WalletType.bitcoin:
final amount = !sendAll ? double.parse(_amount) : null;
final amount = !sendAll ? _amount : null;
return BitcoinTransactionCredentials(
address, amount, _settingsStore.transactionPriority);
@@ -6,15 +6,13 @@ class PickerListItem<ItemType> extends SettingsListItem {
{@required String title,
@required this.selectedItem,
@required this.items,
void Function(ItemType item) onItemSelected,
this.isAlwaysShowScrollThumb = false})
void Function(ItemType item) onItemSelected})
: _onItemSelected = onItemSelected,
super(title);
final ItemType Function() selectedItem;
final List<ItemType> items;
final void Function(ItemType item) _onItemSelected;
final bool isAlwaysShowScrollThumb;
void onItemSelected(dynamic item) {
if (item is ItemType) {
@@ -1,3 +1,6 @@
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/themes/theme_list.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:flutter/cupertino.dart';
import 'package:mobx/mobx.dart';
@@ -26,13 +29,21 @@ part 'settings_view_model.g.dart';
class SettingsViewModel = SettingsViewModelBase with _$SettingsViewModel;
abstract class SettingsViewModelBase with Store {
SettingsViewModelBase(this._settingsStore, WalletBase wallet)
SettingsViewModelBase(this._settingsStore, WalletBase<Balance> wallet)
: itemHeaders = {},
_walletType = wallet.type,
_biometricAuth = BiometricAuth() {
currentVersion = '';
PackageInfo.fromPlatform().then(
(PackageInfo packageInfo) => currentVersion = packageInfo.version);
final _priority = _settingsStore.transactionPriority;
if (!TransactionPriority.forWalletType(_walletType).contains(_priority)) {
_settingsStore.transactionPriority =
TransactionPriority.forWalletType(_walletType).first;
}
sections = [
[
PickerListItem(
@@ -44,15 +55,13 @@ abstract class SettingsViewModelBase with Store {
PickerListItem(
title: S.current.settings_currency,
items: FiatCurrency.all,
isAlwaysShowScrollThumb: true,
selectedItem: () => fiatCurrency,
onItemSelected: (FiatCurrency currency) =>
setFiatCurrency(currency)),
PickerListItem(
title: S.current.settings_fee_priority,
items: _transactionPriorities(wallet.type),
items: TransactionPriority.forWalletType(wallet.type),
selectedItem: () => transactionPriority,
isAlwaysShowScrollThumb: true,
onItemSelected: (TransactionPriority priority) =>
_settingsStore.transactionPriority = priority),
SwitcherListItem(
@@ -106,11 +115,12 @@ abstract class SettingsViewModelBase with Store {
setAllowBiometricalAuthentication(value);
}
}),
SwitcherListItem(
title: S.current.settings_dark_mode,
value: () => _settingsStore.isDarkTheme,
onValueChange: (_, bool value) =>
_settingsStore.isDarkTheme = value)
PickerListItem(
title: S.current.color_theme,
items: ThemeList.all,
selectedItem: () => theme,
onItemSelected: (ThemeBase theme) =>
_settingsStore.currentTheme = theme)
],
[
LinkListItem(
@@ -186,6 +196,9 @@ abstract class SettingsViewModelBase with Store {
bool get allowBiometricalAuthentication =>
_settingsStore.allowBiometricalAuthentication;
@computed
ThemeBase get theme => _settingsStore.currentTheme;
final Map<String, String> itemHeaders;
List<List<SettingsListItem>> sections;
final SettingsStore _settingsStore;
@@ -234,19 +247,4 @@ abstract class SettingsViewModelBase with Store {
@action
void _showTrades() => actionlistDisplayMode.add(ActionListDisplayMode.trades);
static List<TransactionPriority> _transactionPriorities(WalletType type) {
switch (type) {
case WalletType.monero:
return TransactionPriority.all;
case WalletType.bitcoin:
return [
TransactionPriority.slow,
TransactionPriority.regular,
TransactionPriority.fast
];
default:
return [];
}
}
}
@@ -0,0 +1,105 @@
import 'dart:async';
import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dart';
import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
part 'trade_details_view_model.g.dart';
class TradeDetailsViewModel = TradeDetailsViewModelBase
with _$TradeDetailsViewModel;
abstract class TradeDetailsViewModelBase with Store {
TradeDetailsViewModelBase({Trade tradeForDetails, this.trades}) {
trade = tradeForDetails;
switch (trade.provider) {
case ExchangeProviderDescription.xmrto:
_provider = XMRTOExchangeProvider();
break;
case ExchangeProviderDescription.changeNow:
_provider = ChangeNowExchangeProvider();
break;
case ExchangeProviderDescription.morphToken:
_provider = MorphTokenExchangeProvider(trades: trades);
break;
}
items = ObservableList<StandartListItem>();
_updateItems();
_updateTrade();
_timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
}
final Box<Trade> trades;
@observable
Trade trade;
@observable
ObservableList<StandartListItem> items;
ExchangeProvider _provider;
Timer _timer;
@action
Future<void> _updateTrade() async {
try {
final updatedTrade = await _provider.findTradeById(id: trade.id);
if (updatedTrade.createdAt == null && trade.createdAt != null) {
updatedTrade.createdAt = trade.createdAt;
}
trade = updatedTrade;
_updateItems();
} catch (e) {
print(e.toString());
}
}
void _updateItems() {
final dateFormat = DateFormatter.withCurrentLocal();
items?.clear();
items.addAll([
StandartListItem(title: S.current.trade_details_id, value: trade.id),
StandartListItem(
title: S.current.trade_details_state,
value: trade.state != null
? trade.state.toString()
: S.current.trade_details_fetching)
]);
if (trade.provider != null) {
items.add(StandartListItem(
title: S.current.trade_details_provider,
value: trade.provider.toString()));
}
if (trade.createdAt != null) {
items.add(StandartListItem(
title: S.current.trade_details_created_at,
value: dateFormat.format(trade.createdAt).toString()));
}
if (trade.from != null && trade.to != null) {
items.add(StandartListItem(
title: S.current.trade_details_pair,
value: '${trade.from.toString()} → ${trade.to.toString()}'));
}
}
}
@@ -0,0 +1,114 @@
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/monero/monero_transaction_info.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/generated/i18n.dart';
part 'transaction_details_view_model.g.dart';
class TransactionDetailsViewModel = TransactionDetailsViewModelBase
with _$TransactionDetailsViewModel;
abstract class TransactionDetailsViewModelBase with Store {
TransactionDetailsViewModelBase(
{this.transactionInfo,
this.transactionDescriptionBox,
this.settingsStore})
: items = [] {
showRecipientAddress = settingsStore?.shouldSaveRecipientAddress ?? false;
final dateFormat = DateFormatter.withCurrentLocal();
final tx = transactionInfo;
if (tx is MoneroTransactionInfo) {
final _items = [
StandartListItem(
title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(
title: S.current.transaction_details_amount,
value: tx.amountFormatted()),
StandartListItem(
title: S.current.transaction_details_fee, value: tx.feeFormatted()),
];
if (tx.key?.isNotEmpty ?? null) {
_items.add(
StandartListItem(title: S.current.transaction_key, value: tx.key));
}
items.addAll(_items);
}
if (tx is BitcoinTransactionInfo) {
final _items = [
StandartListItem(
title: S.current.transaction_details_transaction_id, value: tx.id),
StandartListItem(
title: S.current.transaction_details_date,
value: dateFormat.format(tx.date)),
StandartListItem(
title: S.current.confirmations,
value: tx.confirmations?.toString()),
StandartListItem(
title: S.current.transaction_details_height, value: '${tx.height}'),
StandartListItem(
title: S.current.transaction_details_amount,
value: tx.amountFormatted()),
if (tx.feeFormatted()?.isNotEmpty)
StandartListItem(
title: S.current.transaction_details_fee,
value: tx.feeFormatted())
];
items.addAll(_items);
}
if (showRecipientAddress) {
final recipientAddress = transactionDescriptionBox.values
.firstWhere((val) => val.id == transactionInfo.id, orElse: () => null)
?.recipientAddress;
if (recipientAddress?.isNotEmpty ?? false) {
items.add(StandartListItem(
title: S.current.transaction_details_recipient_address,
value: recipientAddress));
}
}
final description = transactionDescriptionBox.values.firstWhere(
(val) => val.id == transactionInfo.id,
orElse: () => TransactionDescription(id: transactionInfo.id));
items.add(TextFieldListItem(
title: S.current.note_tap_to_change,
value: description.note,
onSubmitted: (value) {
description.transactionNote = value;
if (description.isInBox) {
description.save();
} else {
transactionDescriptionBox.add(description);
}
}));
}
final TransactionInfo transactionInfo;
final Box<TransactionDescription> transactionDescriptionBox;
final SettingsStore settingsStore;
final List<TransactionDetailsListItem> items;
bool showRecipientAddress;
}
@@ -63,7 +63,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
final wallet = _wallet;
if (wallet is BitcoinWallet) {
await wallet.generateNewAddress(label: label);
await wallet.generateNewAddress();
}
if (wallet is MoneroWallet) {
@@ -77,7 +77,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
final wallet = _wallet;
if (wallet is BitcoinWallet) {
await wallet.updateAddress(_item.address as String, label: label);
await wallet.updateAddress(_item.address as String);
}
if (wallet is MoneroWallet) {
@@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
@@ -31,7 +32,7 @@ class MoneroURI extends PaymentURI {
var base = 'monero:' + address;
if (amount?.isNotEmpty ?? false) {
base += '?tx_amount=$amount';
base += '?tx_amount=${amount.replaceAll(',', '.')}';
}
return base;
@@ -47,7 +48,7 @@ class BitcoinURI extends PaymentURI {
var base = 'bitcoin:' + address;
if (amount?.isNotEmpty ?? false) {
base += '?amount=$amount';
base += '?amount=${amount.replaceAll(',', '.')}';
}
return base;
@@ -57,10 +58,13 @@ class BitcoinURI extends PaymentURI {
abstract class WalletAddressListViewModelBase with Store {
WalletAddressListViewModelBase(
{@required AppStore appStore}) {
hasAccounts = _wallet is MoneroWallet;
_appStore = appStore;
_wallet = _appStore.wallet;
_onWalletChangeReaction = reaction((_) => _appStore.wallet, (WalletBase wallet) => _wallet = wallet);
hasAccounts = _wallet?.type == WalletType.monero;
_onWalletChangeReaction = reaction((_) => _appStore.wallet, (WalletBase<Balance> wallet) {
_wallet = wallet;
hasAccounts = _wallet.type == WalletType.monero;
});
_init();
}
@@ -116,7 +120,7 @@ abstract class WalletAddressListViewModelBase with Store {
return WalletAddressListItem(
isPrimary: isPrimary,
name: addr.label,
name: null,
address: addr.address);
});
addressList.addAll(bitcoinAddresses);
@@ -125,16 +129,8 @@ abstract class WalletAddressListViewModelBase with Store {
return addressList;
}
bool hasAccounts;
@observable
WalletBase _wallet;
List<ListItem> _baseItems;
AppStore _appStore;
ReactionDisposer _onWalletChangeReaction;
bool hasAccounts;
@computed
String get accountLabel {
@@ -147,6 +143,19 @@ abstract class WalletAddressListViewModelBase with Store {
return null;
}
@computed
bool get hasAddressList => _wallet.type == WalletType.monero;
@observable
WalletBase<Balance> _wallet;
List<ListItem> _baseItems;
AppStore _appStore;
ReactionDisposer _onWalletChangeReaction;
@action
void setAddress(WalletAddressListItem address) =>
_wallet.address = address.address;
@@ -160,4 +169,13 @@ abstract class WalletAddressListViewModelBase with Store {
_baseItems.add(WalletAddressListHeader());
}
@action
void nextAddress() {
final wallet = _wallet;
if (wallet is BitcoinWallet) {
wallet.nextAddress();
}
}
}
+3 -2
View File
@@ -27,7 +27,7 @@ abstract class WalletCreationVMBase with Store {
@observable
ExecutionState state;
final WalletType type;
WalletType type;
final bool isRecovery;
final Box<WalletInfo> _walletInfoSource;
final AppStore _appStore;
@@ -50,8 +50,9 @@ abstract class WalletCreationVMBase with Store {
dirPath: dirPath);
credentials.walletInfo = walletInfo;
final wallet = await process(credentials);
walletInfo.address = wallet.address;
await _walletInfoSource.add(walletInfo);
_appStore.wallet = wallet;
_appStore.changeCurrentWallet(wallet);
_appStore.authenticationStore.allowed();
state = ExecutedSuccessfullyState();
} catch (e) {
@@ -32,7 +32,8 @@ abstract class WalletListViewModelBase with Store {
final password =
await _keyService.getWalletPassword(walletName: wallet.name);
final walletService = getIt.get<WalletService>(param1: wallet.type);
_appStore.wallet = await walletService.openWallet(wallet.name, password);
final loadedWallet = await walletService.openWallet(wallet.name, password);
_appStore.changeCurrentWallet(loadedWallet);
_updateList();
}
+4 -2
View File
@@ -43,6 +43,8 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
}
@override
Future<WalletBase> process(WalletCredentials credentials) async =>
_walletCreationService.create(credentials);
Future<WalletBase> process(WalletCredentials credentials) async {
_walletCreationService.changeWalletType(type: type);
return _walletCreationService.create(credentials);
}
}
+24 -5
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/bitcoin/bitcoin_wallet_creation_credentials.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
@@ -22,10 +23,16 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
WalletRestoreViewModelBase(AppStore appStore, this._walletCreationService,
Box<WalletInfo> walletInfoSource,
{@required WalletType type})
: super(appStore, walletInfoSource, type: type, isRecovery: true) {
isButtonEnabled = false;
: availableModes = type == WalletType.monero
? WalletRestoreMode.values
: [WalletRestoreMode.seed],
hasSeedLanguageSelector = type == WalletType.monero,
hasBlockchainHeightLanguageSelector = type == WalletType.monero,
super(appStore, walletInfoSource, type: type, isRecovery: true) {
isButtonEnabled =
!hasSeedLanguageSelector && !hasBlockchainHeightLanguageSelector;
mode = WalletRestoreMode.seed;
_walletCreationService.changeWalletType(type: WalletType.monero);
_walletCreationService.changeWalletType(type: type);
}
@observable
@@ -34,6 +41,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
@observable
bool isButtonEnabled;
final List<WalletRestoreMode> availableModes;
final bool hasSeedLanguageSelector;
final bool hasBlockchainHeightLanguageSelector;
final WalletCreationService _walletCreationService;
@override
@@ -44,8 +55,16 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
if (mode == WalletRestoreMode.seed) {
final seed = options['seed'] as String;
return MoneroRestoreWalletFromSeedCredentials(
name: name, height: height, mnemonic: seed, password: password);
switch (type) {
case WalletType.monero:
return MoneroRestoreWalletFromSeedCredentials(
name: name, height: height, mnemonic: seed, password: password);
case WalletType.bitcoin:
return BitcoinRestoreWalletFromSeedCredentials(
name: name, mnemonic: seed, password: password);
default:
break;
}
}
if (mode == WalletRestoreMode.keys) {