Skip to content

Commit 8df91d2

Browse files
authored
feat(desktop): improve audio tile accessibility (#1434)
* feat(desktop): improve audio tile accessibility Fixes #1425 * refactor(desktop): simplify audio tile tap handling and remove unused state * fix(desktop): prevent title tap on mobile devices
1 parent cae2cd8 commit 8df91d2

File tree

2 files changed

+87
-67
lines changed

2 files changed

+87
-67
lines changed

lib/common/view/audio_tile.dart

Lines changed: 80 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ class _AudioTileState extends State<AudioTile> {
6565
final theme = context.theme;
6666
final l10n = context.l10n;
6767
final playerModel = di<PlayerModel>();
68-
final slimTile =
69-
widget.audioPageType == AudioPageType.allTitlesView ||
70-
widget.audioPageType == AudioPageType.album;
7168

7269
final selectedColor = widget.selectedColor ?? theme.contrastyPrimary;
7370
final color = widget.selected && widget.isPlayerPlaying
@@ -80,35 +77,39 @@ class _AudioTileState extends State<AudioTile> {
8077
_ => widget.audio.artist ?? l10n.unknown,
8178
};
8279

83-
const dimension = kAudioTrackWidth;
80+
const dimension = kAudioTrackWidth - 10;
8481

85-
final leading = switch (widget.audioPageType) {
86-
AudioPageType.album => _AlbumTileLead(
87-
trackNumber: widget.audio.trackNumber,
88-
color: color,
89-
dimension: dimension / 2,
90-
),
91-
_ =>
92-
widget.allowLeadingImage
93-
? AudioTileImage(
94-
key: switch (widget.audio.audioType) {
95-
AudioType.radio => ValueKey(widget.audio.uuid),
96-
_ => null,
97-
},
98-
size: dimension,
99-
audio: widget.audio,
100-
)
101-
: null,
102-
};
82+
final leading = _AudioTileLeading(
83+
audioPageType: widget.audioPageType,
84+
audio: widget.audio,
85+
dimension: dimension,
86+
color: color,
87+
onTap: widget.onTap,
88+
selected: widget.selected,
89+
isPlayerPlaying: widget.isPlayerPlaying,
90+
);
10391

10492
const titleOverflow = TextOverflow.ellipsis;
10593
const titleMaxLines = 1;
10694

95+
final onTileTap = () {
96+
if (widget.selected) {
97+
if (widget.isPlayerPlaying) {
98+
playerModel.pause();
99+
} else {
100+
playerModel.resume();
101+
}
102+
} else {
103+
widget.onTap?.call();
104+
}
105+
};
106+
107107
final title = Padding(
108108
padding: const EdgeInsets.only(right: kLargestSpace),
109109
child: widget.onTitleTap == null
110-
? Text(
111-
widget.audio.title ?? l10n.unknown,
110+
? TapAbleText(
111+
onTap: isMobile ? null : onTileTap,
112+
text: widget.audio.title ?? l10n.unknown,
112113
overflow: titleOverflow,
113114
maxLines: titleMaxLines,
114115
)
@@ -129,7 +130,7 @@ class _AudioTileState extends State<AudioTile> {
129130
? Text('${l10n.disc} ${widget.audio.discNumber}', maxLines: 1)
130131
: TapAbleText(
131132
maxLines: 1,
132-
wrapInFlexible: slimTile,
133+
wrapInFlexible: true,
133134
text: subTitle,
134135
onTap: widget.onSubTitleTap == null
135136
? null
@@ -145,51 +146,25 @@ class _AudioTileState extends State<AudioTile> {
145146
selectedColor: widget.isPlayerPlaying
146147
? selectedColor
147148
: theme.colorScheme.onSurface,
148-
selectedTileColor: theme.colorScheme.onSurface.withValues(alpha: 0.05),
149+
selectedTileColor: isMobile
150+
? theme.colorScheme.onSurface.withValues(alpha: 0.05)
151+
: Colors.transparent,
149152
contentPadding: audioTilePadding.copyWith(
150153
left: widget.audioPageType == AudioPageType.album ? 10 : null,
151-
right: slimTile ? 0 : null,
154+
right: 0,
152155
),
153-
onTap: () {
154-
if (widget.selected) {
155-
if (widget.isPlayerPlaying) {
156-
playerModel.pause();
157-
} else {
158-
playerModel.resume();
159-
}
160-
} else {
161-
widget.onTap?.call();
162-
}
163-
},
164-
title: slimTile
165-
? Row(
166-
spacing: kMediumSpace,
167-
children: [
168-
Expanded(flex: 4, child: title),
169-
if (widget.showSlimTileSubtitle)
170-
Expanded(flex: 3, child: subtitle),
171-
if (widget.showDuration)
172-
Expanded(
173-
child: _AudioTileDuration(
174-
splitter: '',
175-
audio: widget.audio,
176-
),
177-
),
178-
],
179-
)
180-
: title,
181-
subtitle: slimTile
182-
? widget.showSecondLineSubTitle
183-
? subtitle
184-
: null
185-
: Row(
186-
mainAxisSize: MainAxisSize.min,
187-
children: [
188-
Flexible(child: subtitle),
189-
if (widget.showDuration)
190-
Flexible(child: _AudioTileDuration(audio: widget.audio)),
191-
],
156+
onTap: isMobile ? onTileTap : null,
157+
title: Row(
158+
spacing: kMediumSpace,
159+
children: [
160+
Expanded(flex: 4, child: title),
161+
if (widget.showSlimTileSubtitle) Expanded(flex: 3, child: subtitle),
162+
if (widget.showDuration)
163+
Expanded(
164+
child: _AudioTileDuration(splitter: '', audio: widget.audio),
192165
),
166+
],
167+
),
193168
trailing: AudioTileTrail(
194169
hovered: _hovered,
195170
audio: widget.audio,
@@ -320,3 +295,42 @@ class _AlbumTileLead extends StatelessWidget {
320295
);
321296
}
322297
}
298+
299+
class _AudioTileLeading extends StatelessWidget {
300+
const _AudioTileLeading({
301+
required this.audio,
302+
required this.audioPageType,
303+
required this.selected,
304+
required this.isPlayerPlaying,
305+
this.onTap,
306+
this.color,
307+
required this.dimension,
308+
});
309+
310+
final Audio audio;
311+
final AudioPageType audioPageType;
312+
final bool selected;
313+
314+
final bool isPlayerPlaying;
315+
final void Function()? onTap;
316+
317+
final Color? color;
318+
final double dimension;
319+
320+
@override
321+
Widget build(BuildContext context) => switch (audioPageType) {
322+
AudioPageType.album => _AlbumTileLead(
323+
trackNumber: audio.trackNumber,
324+
color: color,
325+
dimension: dimension,
326+
),
327+
_ => AudioTileImage(
328+
key: switch (audio.audioType) {
329+
AudioType.radio => ValueKey(audio.uuid),
330+
_ => null,
331+
},
332+
size: dimension,
333+
audio: audio,
334+
),
335+
};
336+
}

lib/common/view/sliver_audio_tile_list.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_it/flutter_it.dart';
33

44
import '../../extensions/build_context_x.dart';
55
import '../../player/player_model.dart';
6+
import '../../settings/settings_model.dart';
67
import '../data/audio.dart';
78
import 'audio_page_type.dart';
89
import 'audio_tile.dart';
@@ -30,7 +31,12 @@ class SliverAudioTileList extends StatelessWidget with WatchItMixin {
3031
Widget build(BuildContext context) {
3132
final mqSize = constraints?.maxWidth ?? context.mediaQuerySize.width;
3233
final playerToTheRight = mqSize > kSideBarThreshHold;
33-
final width = playerToTheRight ? mqSize - kSideBarPlayerWidth : mqSize;
34+
final autoMovePlayer = watchPropertyValue(
35+
(SettingsModel m) => m.autoMovePlayer,
36+
);
37+
final width = autoMovePlayer && playerToTheRight
38+
? mqSize - kSideBarPlayerWidth
39+
: mqSize;
3440

3541
final playerModel = di<PlayerModel>();
3642
final isPlaying = watchPropertyValue((PlayerModel m) => m.isPlaying);

0 commit comments

Comments
 (0)