mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
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
This commit is contained in:
parent
9e7009f339
commit
5ad67b62a5
8 changed files with 230 additions and 226 deletions
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -139,32 +139,35 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
.decorationColor!,
|
||||
width: 1.0),
|
||||
),
|
||||
suffixIcon: IconButton(
|
||||
onPressed: () async {
|
||||
final rName = await generateName();
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
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!,
|
||||
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!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -208,58 +208,29 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
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 {
|
||||
|
|
|
@ -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
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<void>(
|
||||
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<void>(
|
||||
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(
|
||||
|
|
|
@ -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,
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue