fix(accessibility): label icon controls and semantic tap targets

This commit is contained in:
Storm Dragon 2026-02-27 15:41:57 -05:00
parent e30e84ded1
commit b552e9843c
15 changed files with 118 additions and 66 deletions

View file

@ -163,6 +163,7 @@ class AudiobookPlayerPlayPauseButton extends HookConsumerWidget {
child: CircularProgressIndicator(),
),
ProcessingState.completed => IconButton(
tooltip: 'Replay',
onPressed: () async {
await player.seek(const Duration(seconds: 0));
await player.play();
@ -170,6 +171,7 @@ class AudiobookPlayerPlayPauseButton extends HookConsumerWidget {
icon: const Icon(Icons.replay),
),
ProcessingState.ready => IconButton(
tooltip: player.playing ? 'Pause' : 'Play',
onPressed: () async {
await player.togglePlayPause();
},

View file

@ -64,6 +64,7 @@ class PlayerWhenExpanded extends HookConsumerWidget {
IconButton(
iconSize: 30,
icon: const Icon(Icons.keyboard_arrow_down),
tooltip: 'Minimize player',
onPressed: () {
// minimize the player
audioBookMiniplayerController.animateToHeight(
@ -75,6 +76,7 @@ class PlayerWhenExpanded extends HookConsumerWidget {
// the cast button
IconButton(
icon: const Icon(Icons.cast),
tooltip: 'Cast',
onPressed: () {
showNotImplementedToast(context);
},
@ -108,14 +110,11 @@ class PlayerWhenExpanded extends HookConsumerWidget {
),
child: SizedBox(
height: imageSize,
child: InkWell(
onTap: () {},
child: ClipRRect(
borderRadius: BorderRadius.circular(
AppElementSizes.borderRadiusRegular * earlyPercentage,
),
child: img,
child: ClipRRect(
borderRadius: BorderRadius.circular(
AppElementSizes.borderRadiusRegular * earlyPercentage,
),
child: img,
),
),
),

View file

@ -51,20 +51,24 @@ class PlayerWhenMinimized extends HookConsumerWidget {
horizontal:
((availWidth - maxImgSize) / 2) * percentageMiniplayer,
),
child: InkWell(
onTap: () {
// navigate to item page
context.pushNamed(
Routes.libraryItem.name,
pathParameters: {
Routes.libraryItem.pathParamName!:
player.book!.libraryItemId,
},
);
},
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxImgSize),
child: imgWidget,
child: Semantics(
button: true,
label: 'Open current book details',
child: InkWell(
onTap: () {
// navigate to item page
context.pushNamed(
Routes.libraryItem.name,
pathParameters: {
Routes.libraryItem.pathParamName!:
player.book!.libraryItemId,
},
);
},
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: maxImgSize),
child: imgWidget,
),
),
),
),
@ -112,11 +116,16 @@ class PlayerWhenMinimized extends HookConsumerWidget {
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: IconButton(
tooltip: 'Rewind 30 seconds',
icon: const Icon(
Icons.replay_30,
size: AppElementSizes.iconSizeSmall,
),
onPressed: () {},
onPressed: () {
player.seek(
player.positionInBook - const Duration(seconds: 30),
);
},
),
),
),

View file

@ -13,6 +13,9 @@ class AudiobookPlayerSeekButton extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final player = ref.watch(audiobookPlayerProvider);
return IconButton(
tooltip: isForward
? 'Seek forward 30 seconds'
: 'Seek backward 30 seconds',
icon: Icon(
isForward ? Icons.forward_30 : Icons.replay_30,
size: AppElementSizes.iconSizeSmall,

View file

@ -49,6 +49,7 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
}
return IconButton(
tooltip: isForward ? 'Next chapter' : 'Previous chapter',
icon: Icon(
isForward ? Icons.skip_next : Icons.skip_previous,
size: AppElementSizes.iconSizeSmall,

View file

@ -162,6 +162,7 @@ class SpeedWheel extends StatelessWidget {
// a minus button to decrease the speed
if (showIncrementButtons)
IconButton.filledTonal(
tooltip: 'Decrease speed',
icon: const Icon(Icons.remove),
onPressed: () {
// animate to index - 1
@ -198,6 +199,7 @@ class SpeedWheel extends StatelessWidget {
if (showIncrementButtons)
// a plus button to increase the speed
IconButton.filledTonal(
tooltip: 'Increase speed',
icon: const Icon(Icons.add),
onPressed: () {
// animate to index + 1