Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address list fixes CW-883 #1995

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 21 additions & 19 deletions lib/src/screens/receive/widgets/address_list.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

import 'dart:math';

import 'package:cake_wallet/di.dart';
Expand All @@ -21,6 +20,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';

class AddressList extends StatefulWidget {
const AddressList({
Expand All @@ -37,7 +37,6 @@ class AddressList extends StatefulWidget {
}

class _AddressListState extends State<AddressList> {

bool showHiddenAddresses = false;

void _toggleHiddenAddresses() {
Expand All @@ -62,7 +61,7 @@ class _AddressListState extends State<AddressList> {

void updateItems() {
setState(() {
items = getItems(widget.addressListViewModel.items, showHiddenAddresses);
items = getItems(widget.addressListViewModel.forceRecomputeItems, showHiddenAddresses);
});
}

Expand Down Expand Up @@ -132,9 +131,10 @@ class _AddressListState extends State<AddressList> {
showTrailingButton: widget.addressListViewModel.showAddManualAddresses,
showSearchButton: true,
onSearchCallback: updateItems,
trailingButtonTap: () => Navigator.of(context).pushNamed(Routes.newSubaddress).then((value) {
updateItems(); // refresh the new address
}),
trailingButtonTap: () =>
Navigator.of(context).pushNamed(Routes.newSubaddress).then((value) {
updateItems(); // refresh the new address
}),
trailingIcon: Icon(
Icons.add,
size: 20,
Expand All @@ -149,25 +149,26 @@ class _AddressListState extends State<AddressList> {
cell = Container();
} else {
cell = Observer(builder: (_) {
final isCurrent = item.address == widget.addressListViewModel.address.address && editable;
final isCurrent =
item.address == widget.addressListViewModel.address.address && editable;
final backgroundColor = isCurrent
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileBackgroundColor
: Theme.of(context).extension<ReceivePageTheme>()!.tilesBackgroundColor;
final textColor = isCurrent
? Theme.of(context).extension<ReceivePageTheme>()!.currentTileTextColor
: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor;


return AddressCell.fromItem(
item,
isCurrent: isCurrent,
hasBalance: widget.addressListViewModel.isBalanceAvailable,
hasReceived: widget.addressListViewModel.isReceivedAvailable,
// hasReceived:
backgroundColor: (kDebugMode && item.isHidden) ?
Theme.of(context).colorScheme.error :
(kDebugMode && item.isManual) ? Theme.of(context).colorScheme.error.withBlue(255) :
backgroundColor,
// hasReceived:
backgroundColor: (kDebugMode && item.isHidden)
? Theme.of(context).colorScheme.error
: (kDebugMode && item.isManual)
? Theme.of(context).colorScheme.error.withBlue(255)
: backgroundColor,
textColor: textColor,
onTap: (_) {
if (widget.onSelect != null) {
Expand All @@ -177,9 +178,11 @@ class _AddressListState extends State<AddressList> {
widget.addressListViewModel.setAddress(item);
},
onEdit: editable
? () => Navigator.of(context).pushNamed(Routes.newSubaddress, arguments: item).then((value) {
updateItems(); // refresh the new address
})
? () => Navigator.of(context)
.pushNamed(Routes.newSubaddress, arguments: item)
.then((value) {
updateItems(); // refresh the new address
})
: null,
isHidden: item.isHidden,
onHide: () => _hideAddress(item),
Expand All @@ -191,8 +194,8 @@ class _AddressListState extends State<AddressList> {
return index != 0
? cell
: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30), topRight: Radius.circular(30)),
borderRadius:
BorderRadius.only(topLeft: Radius.circular(30), topRight: Radius.circular(30)),
child: cell,
);
},
Expand All @@ -203,5 +206,4 @@ class _AddressListState extends State<AddressList> {
await widget.addressListViewModel.toggleHideAddress(item);
updateItems();
}

}
104 changes: 47 additions & 57 deletions lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/amount_converter.dart';
import 'package:cw_core/currency.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:intl/intl.dart';
import 'package:mobx/mobx.dart';

part 'wallet_address_list_view_model.g.dart';

class WalletAddressListViewModel = WalletAddressListViewModelBase
with _$WalletAddressListViewModel;
class WalletAddressListViewModel = WalletAddressListViewModelBase with _$WalletAddressListViewModel;

abstract class PaymentURI {
PaymentURI({required this.amount, required this.address});
Expand Down Expand Up @@ -222,9 +222,7 @@ class ZanoURI extends PaymentURI {
}
}


abstract class WalletAddressListViewModelBase
extends WalletChangeListenerViewModel with Store {
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
WalletAddressListViewModelBase({
required AppStore appStore,
required this.yatStore,
Expand All @@ -245,8 +243,7 @@ abstract class WalletAddressListViewModelBase
_init();

selectedCurrency = walletTypeToCryptoCurrency(wallet.type);
hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven]
.contains(wallet.type);
hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven].contains(wallet.type);
}

static const String _cryptoNumberPattern = '0.00000000';
Expand All @@ -259,8 +256,7 @@ abstract class WalletAddressListViewModelBase
double? _fiatRate;
String _rawAmount = '';

List<Currency> get currencies =>
[walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];
List<Currency> get currencies => [walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all];

String get buttonTitle {
if (isElectrumWallet) {
Expand All @@ -286,8 +282,8 @@ abstract class WalletAddressListViewModelBase
WalletType get type => wallet.type;

@computed
WalletAddressListItem get address => WalletAddressListItem(
address: wallet.walletAddresses.address, isPrimary: false);
WalletAddressListItem get address =>
WalletAddressListItem(address: wallet.walletAddresses.address, isPrimary: false);

@computed
PaymentURI get uri {
Expand Down Expand Up @@ -317,25 +313,23 @@ abstract class WalletAddressListViewModelBase
case WalletType.wownero:
return WowneroURI(amount: amount, address: address.address);
case WalletType.zano:
return ZanoURI(amount: amount, address: address.address);
return ZanoURI(amount: amount, address: address.address);
case WalletType.none:
throw Exception('Unexpected type: ${type.toString()}');
}
}

@computed
ObservableList<ListItem> get items => ObservableList<ListItem>()
..addAll(_baseItems)
..addAll(addressList);

@computed
ObservableList<ListItem> get addressList {
ObservableList<ListItem> _computeAddressList() {
final addressList = ObservableList<ListItem>();

if (wallet.type == WalletType.monero) {
final primaryAddress =
monero!.getSubaddressList(wallet).subaddresses.first;
final addressItems =
monero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final primaryAddress = monero!.getSubaddressList(wallet).subaddresses.first;
final addressItems = monero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final isPrimary = subaddress == primaryAddress;

return WalletAddressListItem(
Expand All @@ -351,10 +345,8 @@ abstract class WalletAddressListViewModelBase
}

if (wallet.type == WalletType.wownero) {
final primaryAddress =
wownero!.getSubaddressList(wallet).subaddresses.first;
final addressItems =
wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final isPrimary = subaddress == primaryAddress;

return WalletAddressListItem(
Expand All @@ -367,10 +359,8 @@ abstract class WalletAddressListViewModelBase
}

if (wallet.type == WalletType.haven) {
final primaryAddress =
haven!.getSubaddressList(wallet).subaddresses.first;
final addressItems =
haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final primaryAddress = haven!.getSubaddressList(wallet).subaddresses.first;
final addressItems = haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
final isPrimary = subaddress == primaryAddress;

return WalletAddressListItem(
Expand All @@ -384,8 +374,7 @@ abstract class WalletAddressListViewModelBase

if (isElectrumWallet) {
if (bitcoin!.hasSelectedSilentPayments(wallet)) {
final addressItems =
bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
final addressItems = bitcoin!.getSilentPaymentAddresses(wallet).map((address) {
final isPrimary = address.id == 0;

return WalletAddressListItem(
Expand Down Expand Up @@ -436,8 +425,7 @@ abstract class WalletAddressListViewModelBase
if (wallet.type == WalletType.litecoin && addressItems.length >= 1000) {
// find the index of the last item with a txCount > 0
final addressItemsList = addressItems.toList();
int index = addressItemsList
.lastIndexWhere((item) => (item.txCount ?? 0) > 0);
int index = addressItemsList.lastIndexWhere((item) => (item.txCount ?? 0) > 0);
if (index == -1) {
index = 0;
}
Expand All @@ -451,22 +439,19 @@ abstract class WalletAddressListViewModelBase
if (wallet.type == WalletType.ethereum) {
final primaryAddress = ethereum!.getAddress(wallet);

addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
}

if (wallet.type == WalletType.polygon) {
final primaryAddress = polygon!.getAddress(wallet);

addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
}

if (wallet.type == WalletType.solana) {
final primaryAddress = solana!.getAddress(wallet);

addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
}

if (wallet.type == WalletType.nano) {
Expand All @@ -480,21 +465,18 @@ abstract class WalletAddressListViewModelBase
if (wallet.type == WalletType.tron) {
final primaryAddress = tron!.getAddress(wallet);

addressList.add(WalletAddressListItem(
isPrimary: true, name: null, address: primaryAddress));
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
}

for (var i = 0; i < addressList.length; i++) {
if (!(addressList[i] is WalletAddressListItem)) continue;
(addressList[i] as WalletAddressListItem).isHidden = wallet
.walletAddresses.hiddenAddresses
(addressList[i] as WalletAddressListItem).isHidden = wallet.walletAddresses.hiddenAddresses
.contains((addressList[i] as WalletAddressListItem).address);
}

for (var i = 0; i < addressList.length; i++) {
if (!(addressList[i] is WalletAddressListItem)) continue;
(addressList[i] as WalletAddressListItem).isManual = wallet
.walletAddresses.manualAddresses
(addressList[i] as WalletAddressListItem).isManual = wallet.walletAddresses.manualAddresses
.contains((addressList[i] as WalletAddressListItem).address);
}

Expand All @@ -516,13 +498,28 @@ abstract class WalletAddressListViewModelBase
return addressList;
}

@computed
ObservableList<ListItem> get addressList {
return _computeAddressList();
}

List<ListItem> get forceRecomputeItems {
// necessary because the addressList contains non-observable items
List<ListItem> recomputed = [];
recomputed.addAll(_baseItems);
recomputed.addAll(_computeAddressList());
return recomputed;
}

Future<void> toggleHideAddress(WalletAddressListItem item) async {
if (item.isHidden) {
wallet.walletAddresses.hiddenAddresses
.removeWhere((element) => element == item.address);
item.isHidden = false;
wallet.walletAddresses.hiddenAddresses.removeWhere((element) => element == item.address);
} else {
item.isHidden = true;
wallet.walletAddresses.hiddenAddresses.add(item.address);
}
// update the address list:
await wallet.walletAddresses.saveAddressesInBox();
if (wallet.type == WalletType.monero) {
monero!
Expand Down Expand Up @@ -568,28 +565,22 @@ abstract class WalletAddressListViewModelBase
].contains(wallet.type);

@computed
bool get isElectrumWallet => [
WalletType.bitcoin,
WalletType.litecoin,
WalletType.bitcoinCash
].contains(wallet.type);
bool get isElectrumWallet =>
[WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash].contains(wallet.type);

@computed
bool get isBalanceAvailable => isElectrumWallet;

@computed
bool get isReceivedAvailable =>
[WalletType.monero, WalletType.wownero].contains(wallet.type);
bool get isReceivedAvailable => [WalletType.monero, WalletType.wownero].contains(wallet.type);

@computed
bool get isSilentPayments =>
wallet.type == WalletType.bitcoin &&
bitcoin!.hasSelectedSilentPayments(wallet);
wallet.type == WalletType.bitcoin && bitcoin!.hasSelectedSilentPayments(wallet);

@computed
bool get isAutoGenerateSubaddressEnabled =>
_settingsStore.autoGenerateSubaddressStatus !=
AutoGenerateSubaddressStatus.disabled &&
_settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled &&
!isSilentPayments;

@computed
Expand Down Expand Up @@ -672,8 +663,7 @@ abstract class WalletAddressListViewModelBase
@action
void _convertAmountToCrypto() {
final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type);
final fiatRate =
_fiatRate ?? (fiatConversionStore.prices[cryptoCurrency] ?? 0.0);
final fiatRate = _fiatRate ?? (fiatConversionStore.prices[cryptoCurrency] ?? 0.0);

if (fiatRate <= 0.0) {
dev.log("Invalid Fiat Rate $fiatRate");
Expand Down
Loading