diff --git a/lib/src/screens/auth/auth_page.dart b/lib/src/screens/auth/auth_page.dart index 0483af63d..9faa52ea7 100644 --- a/lib/src/screens/auth/auth_page.dart +++ b/lib/src/screens/auth/auth_page.dart @@ -8,6 +8,8 @@ import 'package:cake_wallet/src/stores/auth/auth_store.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code.dart'; import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:cake_wallet/src/domain/common/biometric_auth.dart'; +import 'package:cake_wallet/themes.dart'; +import 'package:cake_wallet/theme_changer.dart'; typedef OnAuthenticationFinished = void Function(bool, AuthPageState); @@ -26,6 +28,7 @@ class AuthPageState extends State { final _pinCodeKey = GlobalKey(); final _backArrowImageDarkTheme = Image.asset('assets/images/back_arrow_dark_theme.png'); + final _backArrowImage = Image.asset('assets/images/back_arrow.png'); void changeProcessText(String text) { _key.currentState.showSnackBar( @@ -39,6 +42,10 @@ class AuthPageState extends State { final authStore = Provider.of(context); final settingsStore = Provider.of(context); + final _themeChanger = Provider.of(context); + final _backButton = _themeChanger.getTheme() == Themes.darkTheme + ? _backArrowImageDarkTheme : _backArrowImage; + if (settingsStore.allowBiometricalAuthentication) { WidgetsBinding.instance.addPostFrameCallback((_) { final biometricAuth = BiometricAuth(); @@ -134,7 +141,7 @@ class AuthPageState extends State { splashColor: Colors.transparent, padding: EdgeInsets.all(0), onPressed: () => Navigator.of(context).pop(), - child: _backArrowImageDarkTheme), + child: _backButton), ), ) : Container(), @@ -146,6 +153,7 @@ class AuthPageState extends State { (pin, _) => authStore.auth( password: pin.fold('', (ac, val) => ac + '$val')), false, - _pinCodeKey)); + _pinCodeKey, + authStore: authStore,)); } } diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 86cff5392..91ff1a1c9 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -28,6 +28,7 @@ class DashboardPageBodyState extends State { return SafeArea( child: Scaffold( + endDrawer: MenuWidget(), body: Container( decoration: BoxDecoration( gradient: LinearGradient( @@ -49,17 +50,16 @@ class DashboardPageBodyState extends State { width: 44, child: ButtonTheme( minWidth: double.minPositive, - child: FlatButton( - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - padding: EdgeInsets.all(0), - onPressed: () async { - await showDialog( - builder: (_) => MenuWidget(), - context: context - ); - }, - child: menuButton), + child: Builder( + builder: (context) { + return FlatButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + padding: EdgeInsets.all(0), + onPressed: () => Scaffold.of(context).openEndDrawer(), + child: menuButton); + } + ), ), ), ), diff --git a/lib/src/screens/dashboard/widgets/menu_widget.dart b/lib/src/screens/dashboard/widgets/menu_widget.dart index 24bf9cd46..8d1974f94 100644 --- a/lib/src/screens/dashboard/widgets/menu_widget.dart +++ b/lib/src/screens/dashboard/widgets/menu_widget.dart @@ -1,7 +1,5 @@ -import 'dart:async'; import 'dart:ui'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/palette.dart'; import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart'; import 'package:cake_wallet/src/stores/wallet/wallet_store.dart'; import 'package:provider/provider.dart'; @@ -19,7 +17,6 @@ class MenuWidgetState extends State { double screenWidth; double screenHeight; double opacity; - bool isDraw; double headerHeight; double tileHeight; @@ -32,7 +29,6 @@ class MenuWidgetState extends State { screenWidth = 0; screenHeight = 0; opacity = 0; - isDraw = false; headerHeight = 120; tileHeight = 75; @@ -59,10 +55,6 @@ class MenuWidgetState extends State { fromBottomEdge *= scale; } }); - - Timer(Duration(milliseconds: 350), () => - setState(() => isDraw = true) - ); } @override @@ -71,194 +63,174 @@ class MenuWidgetState extends State { final walletStore = Provider.of(context); final itemCount = walletMenu.items.length; - return GestureDetector( - onTap: () => Navigator.of(context).pop(), - child: Container( - color: Colors.transparent, - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0), + return Row( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(left: 24), child: Container( - decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)), - child: Row( - mainAxisSize: MainAxisSize.max, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: EdgeInsets.only(left: 24), - child: isDraw - ? Container( - height: 60, - width: 4, - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(2)), - color: Theme.of(context).hintColor // - ), - ) - : Container( - height: 60, - width: 4, - ) - ), - SizedBox(width: 12), - Expanded( - child: GestureDetector( - onTap: () => null, - child: Container( - width: double.infinity, - height: double.infinity, - alignment: Alignment.centerRight, - child: AnimatedContainer( - alignment: Alignment.centerLeft, - width: menuWidth, - height: double.infinity, - duration: Duration(milliseconds: 500), - curve: Curves.fastOutSlowIn, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)), - color: Theme.of(context).primaryTextTheme.display1.color.withOpacity(opacity) - ), - child: isDraw - ? ListView.separated( - itemBuilder: (_, index) { - - if (index == 0) { - return Container( - height: headerHeight, - padding: EdgeInsets.only( - left: 24, - top: fromTopEdge, - right: 24, - bottom: fromBottomEdge), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(topLeft: Radius.circular(24)), - color: Theme.of(context).primaryTextTheme.display2.color - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - moneroIcon, - SizedBox(width: 16), - Expanded( - child: Container( - height: 40, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - walletStore.name, - style: TextStyle( - color: Theme.of(context).primaryTextTheme.title.color, - decoration: TextDecoration.none, - fontFamily: 'Lato', - fontSize: 20, - fontWeight: FontWeight.bold - ), - ), - Text( - walletStore.account.label, - style: TextStyle( - color: Theme.of(context).primaryTextTheme.caption.color, - decoration: TextDecoration.none, - fontFamily: 'Lato', - fontSize: 12 - ), - ) - ], - ), - ) - ) - ], - ), - ); - } - - index -= 1; - final item = walletMenu.items[index]; - final image = walletMenu.images[index] ?? Offstage(); - - return GestureDetector( - onTap: () { - Navigator.of(context).pop(); - walletMenu.action(index); - }, - child: index == itemCount - 1 - ? Container( - height: headerHeight, - padding: EdgeInsets.only( - left: 24, - right: 24, - top: fromBottomEdge, - bottom: fromTopEdge), - alignment: Alignment.topLeft, - decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)), - color: Theme.of(context).primaryTextTheme.display1.color, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 16), - Expanded( - child: Text( - item, - style: TextStyle( - decoration: TextDecoration.none, - color: Theme.of(context).primaryTextTheme.title.color, - fontFamily: 'Lato', - fontSize: 20, - fontWeight: FontWeight.bold - ), - ) - ) - ], - ), - ) - : Container( - height: tileHeight, - padding: EdgeInsets.only(left: 24, right: 24), - color: Theme.of(context).primaryTextTheme.display1.color, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image, - SizedBox(width: 16), - Expanded( - child: Text( - item, - style: TextStyle( - decoration: TextDecoration.none, - color: Theme.of(context).primaryTextTheme.title.color, - fontFamily: 'Lato', - fontSize: 20, - fontWeight: FontWeight.bold - ), - ) - ) - ], - ), - ), - ); - }, - separatorBuilder: (_, index) => - Container( - height: 1, - color: Theme.of(context).dividerColor, - ), - itemCount: itemCount + 1) - : Offstage() - ), - ), - ) - ) - ], - ) - ), + height: 60, + width: 4, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(2)), + color: Theme.of(context).hintColor + ), + ) ), - ), + SizedBox(width: 12), + Expanded( + child: GestureDetector( + onTap: () => null, + child: Container( + width: menuWidth, + height: double.infinity, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24), + bottomLeft: Radius.circular(24)), + color: Theme.of(context).primaryTextTheme.display1.color + ), + child: ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24), + bottomLeft: Radius.circular(24)), + child: ListView.separated( + itemBuilder: (_, index) { + + if (index == 0) { + return Container( + height: headerHeight, + padding: EdgeInsets.only( + left: 24, + top: fromTopEdge, + right: 24, + bottom: fromBottomEdge), + decoration: BoxDecoration( + borderRadius: BorderRadius.only(topLeft: Radius.circular(24)), + color: Theme.of(context).primaryTextTheme.display2.color + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + moneroIcon, + SizedBox(width: 16), + Expanded( + child: Container( + height: 40, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + walletStore.name, + style: TextStyle( + color: Theme.of(context).primaryTextTheme.title.color, + decoration: TextDecoration.none, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ), + Text( + walletStore.account.label, + style: TextStyle( + color: Theme.of(context).primaryTextTheme.caption.color, + decoration: TextDecoration.none, + fontFamily: 'Lato', + fontSize: 12 + ), + ) + ], + ), + ) + ) + ], + ), + ); + } + + index -= 1; + final item = walletMenu.items[index]; + final image = walletMenu.images[index] ?? Offstage(); + + return GestureDetector( + onTap: () { + Navigator.of(context).pop(); + walletMenu.action(index); + }, + child: index == itemCount - 1 + ? Container( + height: headerHeight, + padding: EdgeInsets.only( + left: 24, + right: 24, + top: fromBottomEdge, + bottom: fromTopEdge), + alignment: Alignment.topLeft, + decoration: BoxDecoration( + borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)), + color: Theme.of(context).primaryTextTheme.display1.color, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + decoration: TextDecoration.none, + color: Theme.of(context).primaryTextTheme.title.color, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ) + ) + ], + ), + ) + : Container( + height: tileHeight, + padding: EdgeInsets.only(left: 24, right: 24), + color: Theme.of(context).primaryTextTheme.display1.color, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image, + SizedBox(width: 16), + Expanded( + child: Text( + item, + style: TextStyle( + decoration: TextDecoration.none, + color: Theme.of(context).primaryTextTheme.title.color, + fontFamily: 'Lato', + fontSize: 20, + fontWeight: FontWeight.bold + ), + ) + ) + ], + ), + ), + ); + }, + separatorBuilder: (_, index) => + Container( + height: 1, + color: Theme.of(context).dividerColor, + ), + itemCount: itemCount + 1), + ), + ), + ) + ) + ], ); } } \ No newline at end of file diff --git a/lib/src/screens/nodes/nodes_list_page.dart b/lib/src/screens/nodes/nodes_list_page.dart index 8c0a04be6..0a9a910ab 100644 --- a/lib/src/screens/nodes/nodes_list_page.dart +++ b/lib/src/screens/nodes/nodes_list_page.dart @@ -77,8 +77,6 @@ class NodeListPageBodyState extends State { final nodeList = Provider.of(context); final settings = Provider.of(context); - final trashImage = Image.asset('assets/images/trash.png', height: 32, width: 32, color: Colors.white); - final currentColor = Theme.of(context).accentTextTheme.subtitle.decorationColor; final notCurrentColor = Theme.of(context).accentTextTheme.title.backgroundColor; @@ -194,12 +192,16 @@ class NodeListPageBodyState extends State { await nodeList.remove(node: node), direction: DismissDirection.endToStart, background: Container( - padding: EdgeInsets.only(right: 10.0, top: 2), + padding: EdgeInsets.only(right: 10.0), alignment: AlignmentDirectional.centerEnd, color: Palette.red, child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - trashImage, + const Icon( + CupertinoIcons.delete, + color: Colors.white, + ), Text( S.of(context).delete, style: TextStyle(color: Colors.white), diff --git a/lib/src/screens/pin_code/pin_code.dart b/lib/src/screens/pin_code/pin_code.dart index 111355b2d..6d67cf925 100644 --- a/lib/src/screens/pin_code/pin_code.dart +++ b/lib/src/screens/pin_code/pin_code.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/src/stores/settings/settings_store.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/stores/auth/auth_store.dart'; +import 'package:cake_wallet/src/domain/common/biometric_auth.dart'; abstract class PinCodeWidget extends StatefulWidget { PinCodeWidget({Key key, this.onPinCodeEntered, this.hasLengthSwitcher}) @@ -14,21 +16,26 @@ abstract class PinCodeWidget extends StatefulWidget { class PinCode extends PinCodeWidget { PinCode(Function(List pin, PinCodeState state) onPinCodeEntered, - bool hasLengthSwitcher, Key key) + bool hasLengthSwitcher, Key key, {this.authStore}) : super( key: key, onPinCodeEntered: onPinCodeEntered, hasLengthSwitcher: hasLengthSwitcher); + final AuthStore authStore; + @override - PinCodeState createState() => PinCodeState(); + PinCodeState createState() => PinCodeState(authStore: authStore); } class PinCodeState extends State { + PinCodeState({this.authStore}); static const defaultPinLength = 4; static const sixPinLength = 6; static const fourPinLength = 4; final _gridViewKey = GlobalKey(); + final AuthStore authStore; + final _key = GlobalKey(); int pinLength = defaultPinLength; List pin = List.filled(defaultPinLength, null); @@ -83,9 +90,11 @@ class PinCodeState extends State { } @override - Widget build(BuildContext context) => Scaffold(body: body(context)); + Widget build(BuildContext context) => Scaffold(key: _key, body: body(context)); Widget body(BuildContext context) { + final settingsStore = Provider.of(context); + final deleteIconImage = Image.asset( 'assets/images/delete_icon.png', color: Theme.of(context).primaryTextTheme.title.color, @@ -161,10 +170,35 @@ class PinCodeState extends State { margin: EdgeInsets.only( left: marginLeft, right: marginRight), child: FlatButton( - onPressed: () {}, + onPressed: (widget.hasLengthSwitcher || + !settingsStore.allowBiometricalAuthentication) + ? null + : () { + if (authStore != null) { + WidgetsBinding.instance.addPostFrameCallback((_) { + final biometricAuth = BiometricAuth(); + biometricAuth.isAuthenticated().then( + (isAuth) { + if (isAuth) { + authStore.biometricAuth(); + _key.currentState.showSnackBar( + SnackBar( + content: Text(S.of(context).authenticated), + backgroundColor: Colors.green, + ), + ); + } + } + ); + }); + } + }, color: Theme.of(context).backgroundColor, shape: CircleBorder(), - child: faceImage, + child: (widget.hasLengthSwitcher || + !settingsStore.allowBiometricalAuthentication) + ? Offstage() + : faceImage, ), ); } else if (index == 10) { diff --git a/lib/src/screens/receive/receive_page.dart b/lib/src/screens/receive/receive_page.dart index 2479404e1..58260bdbd 100644 --- a/lib/src/screens/receive/receive_page.dart +++ b/lib/src/screens/receive/receive_page.dart @@ -245,110 +245,130 @@ class ReceivePageState extends State { ), ), Observer( - builder: (_) => ListView.separated( - separatorBuilder: (context, index) => Divider( - height: 1, - color: Theme.of(context).dividerColor, - ), - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: subaddressListStore.subaddresses.length + 2, - itemBuilder: (context, index) { + builder: (_) { + subaddressListStore.updateShortAddressShow(); - if (index == 0) { - return ClipRRect( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(24), - topRight: Radius.circular(24) - ), - child: HeaderTile( - onTap: () async { - await showDialog( - context: context, - builder: (BuildContext context) { - return AccountListPage(accountListStore: accountListStore); - } - ); - }, - title: walletStore.account.label, + return ListView.separated( + separatorBuilder: (context, index) => Divider( + height: 1, + color: Theme.of(context).dividerColor, + ), + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: subaddressListStore.subaddresses.length + 2, + itemBuilder: (context, index) { + + if (index == 0) { + return ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(24), + topRight: Radius.circular(24) + ), + child: HeaderTile( + onTap: () async { + await showDialog( + context: context, + builder: (BuildContext context) { + return AccountListPage(accountListStore: accountListStore); + } + ); + }, + title: walletStore.account.label, + icon: Icon( + Icons.arrow_forward_ios, + size: 14, + color: Theme.of(context).primaryTextTheme.title.color, + ) + ), + ); + } + + if (index == 1) { + return HeaderTile( + onTap: () => Navigator.of(context) + .pushNamed(Routes.newSubaddress), + title: S.of(context).subaddresses, icon: Icon( - Icons.arrow_forward_ios, - size: 14, + Icons.add, + size: 20, color: Theme.of(context).primaryTextTheme.title.color, ) - ), + ); + } + + index -= 2; + + return Observer( + builder: (_) { + final subaddress = subaddressListStore.subaddresses[index]; + final isCurrent = + walletStore.subaddress.address == subaddress.address; + + String shortAddress = subaddress.address; + shortAddress = shortAddress.replaceRange(8, shortAddress.length - 8, '...'); + + final content = Observer( + builder: (_) { + final isShortAddressShow = subaddressListStore.isShortAddressShow[index]; + + final label = index == 0 + ? 'Primary subaddress' + : subaddress.label.isNotEmpty + ? subaddress.label + : isShortAddressShow ? shortAddress : subaddress.address; + + return InkWell( + onTap: () => walletStore.setSubaddress(subaddress), + onLongPress: () { + if (subaddress.label.isNotEmpty) { + return; + } + subaddressListStore.setShortAddressShow(index, !isShortAddressShow); + }, + child: Container( + color: isCurrent ? currentColor : notCurrentColor, + padding: EdgeInsets.only( + left: 24, + right: 24, + top: 28, + bottom: 28 + ), + child: Text( + label, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: isCurrent + ? currentTextColor + : notCurrentTextColor, + ), + ), + ), + ); + } + ); + + return isCurrent || index == 0 + ? content + : Slidable( + key: Key(subaddress.address), + actionPane: SlidableDrawerActionPane(), + child: content, + secondaryActions: [ + IconSlideAction( + caption: S.of(context).edit, + color: Theme.of(context).primaryTextTheme.overline.color, + icon: Icons.edit, + onTap: () => Navigator.of(context) + .pushNamed(Routes.newSubaddress, arguments: subaddress), + ) + ] + ); + } ); } - - if (index == 1) { - return HeaderTile( - onTap: () => Navigator.of(context) - .pushNamed(Routes.newSubaddress), - title: S.of(context).subaddresses, - icon: Icon( - Icons.add, - size: 20, - color: Theme.of(context).primaryTextTheme.title.color, - ) - ); - } - - index -= 2; - - return Observer( - builder: (_) { - final subaddress = subaddressListStore.subaddresses[index]; - final isCurrent = - walletStore.subaddress.address == subaddress.address; - - final label = subaddress.label.isNotEmpty - ? subaddress.label - : subaddress.address; - - final content = InkWell( - onTap: () => walletStore.setSubaddress(subaddress), - child: Container( - color: isCurrent ? currentColor : notCurrentColor, - padding: EdgeInsets.only( - left: 24, - right: 24, - top: 28, - bottom: 28 - ), - child: Text( - label, - style: TextStyle( - fontSize: subaddress.label.isNotEmpty - ? 18 : 10, - fontWeight: FontWeight.bold, - color: isCurrent - ? currentTextColor - : notCurrentTextColor, - ), - ), - ), - ); - - return isCurrent - ? content - : Slidable( - key: Key(subaddress.address), - actionPane: SlidableDrawerActionPane(), - child: content, - secondaryActions: [ - IconSlideAction( - caption: S.of(context).edit, - color: Theme.of(context).primaryTextTheme.overline.color, - icon: Icons.edit, - onTap: () => Navigator.of(context) - .pushNamed(Routes.newSubaddress, arguments: subaddress), - ) - ] - ); - } - ); - } - ) + ); + } ), ], ), diff --git a/lib/src/stores/subaddress_list/subaddress_list_store.dart b/lib/src/stores/subaddress_list/subaddress_list_store.dart index b9e6dbe59..e242fba7e 100644 --- a/lib/src/stores/subaddress_list/subaddress_list_store.dart +++ b/lib/src/stores/subaddress_list/subaddress_list_store.dart @@ -15,6 +15,7 @@ class SubaddressListStore = SubaddressListStoreBase with _$SubaddressListStore; abstract class SubaddressListStoreBase with Store { SubaddressListStoreBase({@required WalletService walletService}) { subaddresses = ObservableList(); + isShortAddressShow = ObservableList(); if (walletService.currentWallet != null) { _onWalletChanged(walletService.currentWallet); @@ -27,12 +28,20 @@ abstract class SubaddressListStoreBase with Store { @observable ObservableList subaddresses; + @observable + ObservableList isShortAddressShow; + SubaddressList _subaddressList; StreamSubscription _onWalletChangeSubscription; StreamSubscription> _onSubaddressesChangeSubscription; StreamSubscription _onAccountChangeSubscription; Account _account; + @action + void setShortAddressShow(int index, bool isShow) { + isShortAddressShow[index] = isShow; + } + @override void dispose() { if (_onSubaddressesChangeSubscription != null) { @@ -47,6 +56,10 @@ abstract class SubaddressListStoreBase with Store { super.dispose(); } + void updateShortAddressShow() { + isShortAddressShow = ObservableList.of(List.generate(subaddresses.length, (i) => true)); + } + Future _updateSubaddressList({int accountIndex}) async { await _subaddressList.refresh(accountIndex: accountIndex); subaddresses = ObservableList.of(_subaddressList.getAll());