From 5ad67b62a5ebc97be70e91727ab9801be61d8a3f Mon Sep 17 00:00:00 2001 From: Rafael Saes <76502841+saltrafael@users.noreply.github.com> Date: Tue, 18 Apr 2023 17:36:56 +0000 Subject: [PATCH] Cw 304 enhance talkback (#887) * fix(#536): add talkback support to missing main and common elements * fix(#564): add talkback support for slidable node items & addresses page * fix: add missing delete button from add pin widget --- lib/src/screens/base_page.dart | 29 +++--- lib/src/screens/dashboard/dashboard_page.dart | 91 +++++++++++-------- .../screens/new_wallet/new_wallet_page.dart | 55 +++++------ lib/src/screens/pin_code/pin_code_widget.dart | 61 ++++--------- lib/src/screens/receive/receive_page.dart | 50 ++++------ .../screens/receive/widgets/address_cell.dart | 15 ++- .../settings/connection_sync_page.dart | 66 ++++++++------ lib/src/widgets/introducing_card.dart | 91 ++++++++++--------- 8 files changed, 231 insertions(+), 227 deletions(-) diff --git a/lib/src/screens/base_page.dart b/lib/src/screens/base_page.dart index 123eef65..28327ad3 100644 --- a/lib/src/screens/base_page.dart +++ b/lib/src/screens/base_page.dart @@ -58,19 +58,24 @@ abstract class BasePage extends StatelessWidget { bool isMobileView = ResponsiveLayoutUtil.instance.isMobile(context); - return SizedBox( - height: isMobileView ? 37 : 45, - width: isMobileView ? 37 : 45, - child: ButtonTheme( - minWidth: double.minPositive, - child: TextButton( - style: ButtonStyle( - overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent), + return MergeSemantics( + child: SizedBox( + height: isMobileView ? 37 : 45, + width: isMobileView ? 37 : 45, + child: ButtonTheme( + minWidth: double.minPositive, + child: Semantics( + label: canUseCloseIcon && !isMobileView ? 'Close' : 'Back', + child: TextButton( + style: ButtonStyle( + overlayColor: MaterialStateColor.resolveWith( + (states) => Colors.transparent), + ), + onPressed: () => onClose(context), + child: + canUseCloseIcon && !isMobileView ? _closeButton : _backButton, ), - onPressed: () => onClose(context), - child: canUseCloseIcon && !isMobileView - ? _closeButton - : _backButton, + ), ), ), ); diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 032ddf9d..fbd976aa 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -104,7 +104,7 @@ class _DashboardPageView extends BasePage { //splashColor: Colors.transparent, //padding: EdgeInsets.all(0), onPressed: () => onOpenEndDrawer(), - child: menuButton)); + child: Semantics(label: 'Menu', child: menuButton))); } final DashboardViewModel dashboardViewModel; @@ -149,17 +149,21 @@ class _DashboardPageView extends BasePage { Padding( padding: EdgeInsets.only(bottom: 24, top: 10), child: Observer(builder: (context) { - return SmoothPageIndicator( - controller: controller, - count: pages.length, - effect: ColorTransitionEffect( - spacing: 6.0, - radius: 6.0, - dotWidth: 6.0, - dotHeight: 6.0, - dotColor: Theme.of(context).indicatorColor, - activeDotColor: - Theme.of(context).accentTextTheme!.headline4!.backgroundColor!), + return ExcludeSemantics( + child: SmoothPageIndicator( + controller: controller, + count: pages.length, + effect: ColorTransitionEffect( + spacing: 6.0, + radius: 6.0, + dotWidth: 6.0, + dotHeight: 6.0, + dotColor: Theme.of(context).indicatorColor, + activeDotColor: Theme.of(context) + .accentTextTheme! + .headline4! + .backgroundColor!), + ), ); } )), @@ -184,27 +188,38 @@ class _DashboardPageView extends BasePage { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: MainActions.all .where((element) => element.canShow?.call(dashboardViewModel) ?? true) - .map((action) => ActionButton( - image: Image.asset(action.image, - height: 24, - width: 24, - color: action.isEnabled?.call(dashboardViewModel) ?? true - ? Theme.of(context) - .accentTextTheme - .headline2! - .backgroundColor! - : Theme.of(context) - .accentTextTheme - .headline3! - .backgroundColor!), - title: action.name(context), - onClick: () async => await action.onTap(context, dashboardViewModel), - textColor: action.isEnabled?.call(dashboardViewModel) ?? true - ? null - : Theme.of(context) - .accentTextTheme - .headline3! - .backgroundColor!, + .map((action) => Semantics( + button: true, + enabled: (action.isEnabled + ?.call(dashboardViewModel) ?? + true), + child: ActionButton( + image: Image.asset(action.image, + height: 24, + width: 24, + color: action.isEnabled?.call( + dashboardViewModel) ?? + true + ? Theme.of(context) + .accentTextTheme + .headline2! + .backgroundColor! + : Theme.of(context) + .accentTextTheme + .headline3! + .backgroundColor!), + title: action.name(context), + onClick: () async => await action.onTap( + context, dashboardViewModel), + textColor: action.isEnabled + ?.call(dashboardViewModel) ?? + true + ? null + : Theme.of(context) + .accentTextTheme + .headline3! + .backgroundColor!, + ), )) .toList(), ), @@ -222,10 +237,14 @@ class _DashboardPageView extends BasePage { return; } if (dashboardViewModel.shouldShowMarketPlaceInDashboard) { - pages.add(MarketPlacePage(dashboardViewModel: dashboardViewModel)); + pages.add(Semantics( + label: 'Marketplace Page', + child: MarketPlacePage(dashboardViewModel: dashboardViewModel))); } - pages.add(balancePage); - pages.add(TransactionsPage(dashboardViewModel: dashboardViewModel)); + pages.add(Semantics(label: 'Balance Page', child: balancePage)); + pages.add(Semantics( + label: 'Transactions Page', + child: TransactionsPage(dashboardViewModel: dashboardViewModel))); _isEffectsInstalled = true; autorun((_) async { diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 0f15e23c..5fe7522b 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -139,32 +139,35 @@ class _WalletNameFormState extends State { .decorationColor!, width: 1.0), ), - suffixIcon: IconButton( - onPressed: () async { - final rName = await generateName(); - FocusManager.instance.primaryFocus?.unfocus(); - - setState(() { - _controller.text = rName; - _walletNewVM.name = rName; - _controller.selection = TextSelection.fromPosition( - TextPosition(offset: _controller.text.length)); - }); - }, - icon: Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.0), - color: Theme.of(context).hintColor, - ), - width: 34, - height: 34, - child: Image.asset( - 'assets/images/refresh_icon.png', - color: Theme.of(context) - .primaryTextTheme! - .headline4! - .decorationColor!, + suffixIcon: Semantics( + label: 'Generate Name', + child: IconButton( + onPressed: () async { + final rName = await generateName(); + FocusManager.instance.primaryFocus?.unfocus(); + + setState(() { + _controller.text = rName; + _walletNewVM.name = rName; + _controller.selection = TextSelection.fromPosition( + TextPosition(offset: _controller.text.length)); + }); + }, + icon: Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.0), + color: Theme.of(context).hintColor, + ), + width: 34, + height: 34, + child: Image.asset( + 'assets/images/refresh_icon.png', + color: Theme.of(context) + .primaryTextTheme! + .headline4! + .decorationColor!, + ), ), ), ), diff --git a/lib/src/screens/pin_code/pin_code_widget.dart b/lib/src/screens/pin_code/pin_code_widget.dart index 8f30136d..0ce4ab33 100644 --- a/lib/src/screens/pin_code/pin_code_widget.dart +++ b/lib/src/screens/pin_code/pin_code_widget.dart @@ -208,58 +208,29 @@ class PinCodeState extends State { const double marginLeft = 15; if (index == 9) { + // Empty container return Container( margin: EdgeInsets.only(left: marginLeft, right: marginRight), - child: TextButton( - onPressed: () => null, - // (widget.hasLengthSwitcher || - // !settingsStore - // .allowBiometricalAuthentication) - // ? null - // : () { - // FIXME - // 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, - // ), - // ); - // } - // } - // ); - // }); - // } - // }, - // FIX-ME: Style - //color: Theme.of(context).backgroundColor, - //shape: CircleBorder(), - child: Container() - // (widget.hasLengthSwitcher || - // !settingsStore - // .allowBiometricalAuthentication) - // ? Offstage() - // : faceImage, - ), ); } else if (index == 10) { index = 0; } else if (index == 11) { - return Container( - margin: EdgeInsets.only(left: marginLeft, right: marginRight), - child: TextButton( - onPressed: () => _pop(), - style: TextButton.styleFrom( - backgroundColor: Theme.of(context).backgroundColor, - shape: CircleBorder(), + return MergeSemantics( + child: Container( + margin: EdgeInsets.only(left: marginLeft, right: marginRight), + child: Semantics( + label: 'Delete', + button: true, + onTap: () => _pop(), + child: TextButton( + onPressed: () => _pop(), + style: TextButton.styleFrom( + backgroundColor: Theme.of(context).backgroundColor, + shape: CircleBorder(), + ), + child: deleteIconImage, + ), ), - child: deleteIconImage, ), ); } else { diff --git a/lib/src/screens/receive/receive_page.dart b/lib/src/screens/receive/receive_page.dart index 4a573b2e..53bda35d 100644 --- a/lib/src/screens/receive/receive_page.dart +++ b/lib/src/screens/receive/receive_page.dart @@ -41,26 +41,7 @@ class ReceivePage extends BasePage { final FocusNode _cryptoAmountFocus; @override - Widget leading(BuildContext context) { - final _backButton = Icon(Icons.arrow_back_ios, - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!, - size: 16,); - - return SizedBox( - height: 37, - width: 37, - child: ButtonTheme( - minWidth: double.minPositive, - child: TextButton( - // FIX-ME: Style - //highlightColor: Colors.transparent, - //splashColor: Colors.transparent, - //padding: EdgeInsets.all(0), - onPressed: () => onClose(context), - child: _backButton), - ), - ); - } + Color get titleColor => Colors.white; @override Widget middle(BuildContext context) { @@ -93,19 +74,22 @@ class ReceivePage extends BasePage { return Material( color: Colors.transparent, - child: IconButton( - padding: EdgeInsets.zero, - constraints: BoxConstraints(), - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - iconSize: 25, - onPressed: () { - ShareUtil.share( - text: addressListViewModel.address.address, - context: context, - ); - }, - icon: shareImage + child: Semantics( + label: 'Share', + child: IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + iconSize: 25, + onPressed: () { + ShareUtil.share( + text: addressListViewModel.address.address, + context: context, + ); + }, + icon: shareImage + ), ) ); } diff --git a/lib/src/screens/receive/widgets/address_cell.dart b/lib/src/screens/receive/widgets/address_cell.dart index 137db108..e1fe77e7 100644 --- a/lib/src/screens/receive/widgets/address_cell.dart +++ b/lib/src/screens/receive/widgets/address_cell.dart @@ -70,11 +70,16 @@ class AddressCell extends StatelessWidget { ), ), )); - return Slidable( - key: Key(address), - startActionPane: _actionPane(context), - endActionPane: _actionPane(context), - child: cell, + return Semantics( + label: 'Slidable', + selected: isCurrent, + enabled: !isCurrent, + child: Slidable( + key: Key(address), + startActionPane: _actionPane(context), + endActionPane: _actionPane(context), + child: cell, + ), ); } diff --git a/lib/src/screens/settings/connection_sync_page.dart b/lib/src/screens/settings/connection_sync_page.dart index 264cae0d..edcb5794 100644 --- a/lib/src/screens/settings/connection_sync_page.dart +++ b/lib/src/screens/settings/connection_sync_page.dart @@ -41,9 +41,13 @@ class ConnectionSyncPage extends BasePage { handler: (context) => Navigator.of(context).pushNamed(Routes.rescan), ), StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), - NodeHeaderListRow( - title: S.of(context).add_new_node, - onTap: (_) async => await Navigator.of(context).pushNamed(Routes.newNode), + Semantics( + button: true, + child: NodeHeaderListRow( + title: S.of(context).add_new_node, + onTap: (_) async => + await Navigator.of(context).pushNamed(Routes.newNode), + ), ), StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)), SizedBox(height: 100), @@ -60,31 +64,39 @@ class ConnectionSyncPage extends BasePage { itemBuilder: (_, sectionIndex, index) { final node = nodeListViewModel.nodes[index]; final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex; - final nodeListRow = NodeListRow( - title: node.uriRaw, - isSelected: isSelected, - isAlive: node.requestNode(), - onTap: (_) async { - if (isSelected) { - return; - } + final nodeListRow = Semantics( + label: 'Slidable', + selected: isSelected, + enabled: !isSelected, + child: NodeListRow( + title: node.uriRaw, + isSelected: isSelected, + isAlive: node.requestNode(), + onTap: (_) async { + if (isSelected) { + return; + } - await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context).change_current_node_title, - alertContent: nodeListViewModel.getAlertContent(node.uriRaw), - leftButtonText: S.of(context).cancel, - rightButtonText: S.of(context).change, - actionLeftButton: () => Navigator.of(context).pop(), - actionRightButton: () async { - await nodeListViewModel.setAsCurrent(node); - Navigator.of(context).pop(); - }, - ); - }); - }, + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: + S.of(context).change_current_node_title, + alertContent: nodeListViewModel + .getAlertContent(node.uriRaw), + leftButtonText: S.of(context).cancel, + rightButtonText: S.of(context).change, + actionLeftButton: () => + Navigator.of(context).pop(), + actionRightButton: () async { + await nodeListViewModel.setAsCurrent(node); + Navigator.of(context).pop(); + }, + ); + }); + }, + ), ); final dismissibleRow = Slidable( diff --git a/lib/src/widgets/introducing_card.dart b/lib/src/widgets/introducing_card.dart index 52b81fd6..59885d44 100644 --- a/lib/src/widgets/introducing_card.dart +++ b/lib/src/widgets/introducing_card.dart @@ -33,54 +33,59 @@ class IntroducingCard extends StatelessWidget { children: [ Expanded( flex: 1, - child: Padding( - padding: const EdgeInsets.all(24), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AutoSizeText(title ?? '', - style: TextStyle( - fontSize: 24, - fontFamily: 'Lato', - fontWeight: FontWeight.bold, - color: Theme.of(context) - .accentTextTheme! - .headline2! - .backgroundColor!, - height: 1), - maxLines: 1, - textAlign: TextAlign.center), - SizedBox(height: 14), - Text(subTitle ?? '', - textAlign: TextAlign.left, - style: TextStyle( - fontSize: 12, - fontFamily: 'Lato', - color: Theme.of(context) - .accentTextTheme! - .headline2! - .backgroundColor!, - height: 1)), - ], + child: MergeSemantics( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AutoSizeText(title ?? '', + style: TextStyle( + fontSize: 24, + fontFamily: 'Lato', + fontWeight: FontWeight.bold, + color: Theme.of(context) + .accentTextTheme! + .headline2! + .backgroundColor!, + height: 1), + maxLines: 1, + textAlign: TextAlign.center), + SizedBox(height: 14), + Text(subTitle ?? '', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 12, + fontFamily: 'Lato', + color: Theme.of(context) + .accentTextTheme! + .headline2! + .backgroundColor!, + height: 1)), + ], + ), ), ), ), Padding( padding: const EdgeInsets.fromLTRB(0,16,16,0), - child: GestureDetector( - onTap: closeCard, - child: Container( - height: 23, - width: 23, - decoration: BoxDecoration( - color: Colors.white, shape: BoxShape.circle), - child: Center( - child: Image.asset( - 'assets/images/x.png', - color: Palette.darkBlueCraiola, - height: 15, - width: 15, - )), + child: Semantics( + label: 'Close', + child: GestureDetector( + onTap: closeCard, + child: Container( + height: 23, + width: 23, + decoration: BoxDecoration( + color: Colors.white, shape: BoxShape.circle), + child: Center( + child: Image.asset( + 'assets/images/x.png', + color: Palette.darkBlueCraiola, + height: 15, + width: 15, + )), + ), ), ), )