Address list fixes CW-883 (#1995)

* fix show/hide buttons not updating address list

* fix label not updating

* cleanup

* minor fix
This commit is contained in:
Matthew Fosse 2025-03-03 17:36:20 -08:00 committed by GitHub
parent 130f877234
commit de40b2f9aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 68 additions and 76 deletions

View file

@ -1,4 +1,3 @@
import 'dart:math';
import 'package:cake_wallet/di.dart';
@ -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({
@ -37,7 +37,6 @@ class AddressList extends StatefulWidget {
}
class _AddressListState extends State<AddressList> {
bool showHiddenAddresses = false;
void _toggleHiddenAddresses() {
@ -62,7 +61,7 @@ class _AddressListState extends State<AddressList> {
void updateItems() {
setState(() {
items = getItems(widget.addressListViewModel.items, showHiddenAddresses);
items = getItems(widget.addressListViewModel.forceRecomputeItems, showHiddenAddresses);
});
}
@ -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,
@ -149,7 +149,8 @@ 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;
@ -157,17 +158,17 @@ class _AddressListState extends State<AddressList> {
? 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) {
@ -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),
@ -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,
);
},
@ -203,5 +206,4 @@ class _AddressListState extends State<AddressList> {
await widget.addressListViewModel.toggleHideAddress(item);
updateItems();
}
}

View file

@ -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});
@ -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,
@ -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';
@ -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) {
@ -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 {
@ -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(
@ -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(
@ -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(
@ -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(
@ -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;
}
@ -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) {
@ -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);
}
@ -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!
@ -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
@ -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");