Skip to content

Commit 6ecdb9d

Browse files
committed
add proper translatable strings for accessibility labels
1 parent d9db25a commit 6ecdb9d

14 files changed

+479
-406
lines changed

lib/components/AddToPlaylistScreen/add_to_playlist_button.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class _AddToPlaylistButtonState extends ConsumerState<AddToPlaylistButton> {
4545
return Semantics.fromProperties(
4646
properties: SemanticsProperties(
4747
label: AppLocalizations.of(context)!.addToPlaylistTooltip,
48-
hint: "Tap to add to playlist. Long press to toggle favorite.",
48+
hint: AppLocalizations.of(context)!.playlistActionsMenuButtonTooltip,
4949
button: true,
5050
),
5151
excludeSemantics: true,

lib/components/AlbumScreen/download_button.dart

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,37 +53,30 @@ class DownloadButton extends ConsumerWidget {
5353
viewId = finampUserHelper.currentUser!.currentViewId!;
5454
}
5555

56-
var downloadButton = Semantics.fromProperties(
57-
properties: SemanticsProperties(
58-
label: AppLocalizations.of(context)!.downloadItem,
59-
button: true,
60-
),
61-
container: true,
62-
child: IconButton(
63-
icon: status == DownloadItemStatus.notNeeded
64-
? const Icon(Icons.file_download)
65-
: const Icon(Icons.lock), //TODO get better icon
66-
onPressed: () async {
67-
if (isLibrary) {
68-
await showDialog(
69-
context: context,
70-
builder: (context) => ConfirmationPromptDialog(
71-
promptText: AppLocalizations.of(context)!
72-
.downloadLibraryPrompt(item.name),
73-
confirmButtonText:
74-
AppLocalizations.of(context)!.addButtonLabel,
75-
abortButtonText:
76-
MaterialLocalizations.of(context).cancelButtonLabel,
77-
onConfirmed: () =>
78-
DownloadDialog.show(context, item, viewId),
79-
onAborted: () {},
80-
));
81-
} else {
82-
await DownloadDialog.show(context, item, viewId);
83-
}
84-
},
85-
tooltip: parentTooltip,
86-
),
56+
var downloadButton = IconButton(
57+
icon: status == DownloadItemStatus.notNeeded
58+
? const Icon(Icons.file_download)
59+
: const Icon(Icons.lock), //TODO get better icon
60+
onPressed: () async {
61+
if (isLibrary) {
62+
await showDialog(
63+
context: context,
64+
builder: (context) => ConfirmationPromptDialog(
65+
promptText: AppLocalizations.of(context)!
66+
.downloadLibraryPrompt(item.name),
67+
confirmButtonText:
68+
AppLocalizations.of(context)!.addButtonLabel,
69+
abortButtonText:
70+
MaterialLocalizations.of(context).cancelButtonLabel,
71+
onConfirmed: () =>
72+
DownloadDialog.show(context, item, viewId),
73+
onAborted: () {},
74+
));
75+
} else {
76+
await DownloadDialog.show(context, item, viewId);
77+
}
78+
},
79+
tooltip: parentTooltip,
8780
);
8881
var deleteButton = IconButton(
8982
icon: const Icon(Icons.delete),

lib/components/PlayerScreen/album_chip.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class _AlbumChipContent extends StatelessWidget {
7373

7474
return Semantics.fromProperties(
7575
properties: SemanticsProperties(
76-
label: "$albumName (Album)",
76+
label: "$albumName (${AppLocalizations.of(context)!.album})",
7777
button: true,
7878
),
7979
excludeSemantics: true,

lib/components/PlayerScreen/artist_chip.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ class _ArtistChipContent extends StatelessWidget {
141141

142142
return Semantics.fromProperties(
143143
properties: SemanticsProperties(
144-
label: "$name (Artist)",
144+
label: "$name (${AppLocalizations.of(context)!.artist})",
145145
button: true,
146146
),
147147
container: true,

lib/components/PlayerScreen/player_buttons.dart

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter/semantics.dart';
77
import 'package:flutter_tabler_icons/flutter_tabler_icons.dart';
88
import 'package:flutter_vibrate/flutter_vibrate.dart';
99
import 'package:get_it/get_it.dart';
10+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1011

1112
import '../../services/media_state_stream.dart';
1213
import '../../services/music_player_background_task.dart';
@@ -34,8 +35,8 @@ class PlayerButtons extends StatelessWidget {
3435
if (controller.shouldShow(PlayerHideable.loopShuffleButtons))
3536
PlayerButtonsRepeating(),
3637
Semantics.fromProperties(
37-
properties: const SemanticsProperties(
38-
label: "Skip to beginning or previous track",
38+
properties: SemanticsProperties(
39+
label: AppLocalizations.of(context)!.skipToPreviousTrackButtonTooltip,
3940
button: true,
4041
),
4142
container: true,
@@ -51,8 +52,8 @@ class PlayerButtons extends StatelessWidget {
5152
),
5253
),
5354
Semantics.fromProperties(
54-
properties: const SemanticsProperties(
55-
label: "Toggle playback",
55+
properties: SemanticsProperties(
56+
label: AppLocalizations.of(context)!.togglePlaybackButtonTooltip,
5657
button: true,
5758
),
5859
container: true,
@@ -86,8 +87,8 @@ class PlayerButtons extends StatelessWidget {
8687
),
8788
),
8889
Semantics.fromProperties(
89-
properties: const SemanticsProperties(
90-
label: "Skip to next track",
90+
properties: SemanticsProperties(
91+
label: AppLocalizations.of(context)!.skipToNextTrackButtonTooltip,
9192
button: true,
9293
),
9394
container: true,

lib/components/PlayerScreen/player_buttons_more.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
66
import 'package:flutter_riverpod/flutter_riverpod.dart';
77
import 'package:flutter_tabler_icons/flutter_tabler_icons.dart';
88
import 'package:get_it/get_it.dart';
9+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
910

1011
import '../../models/finamp_models.dart';
1112

@@ -21,7 +22,7 @@ class PlayerButtonsMore extends ConsumerWidget {
2122
@override
2223
Widget build(BuildContext context, WidgetRef ref) {
2324
return Semantics(
24-
label: "Track menu",
25+
label: AppLocalizations.of(context)!.trackMenuButtonTooltip,
2526
excludeSemantics: true, // replace child semantics with custom semantics
2627
container: true,
2728
child: IconTheme(

lib/components/PlayerScreen/player_buttons_repeating.dart

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,16 @@ class PlayerButtonsRepeating extends StatelessWidget {
2323
return StreamBuilder(
2424
stream: mediaStateStream,
2525
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
26-
return Semantics.fromProperties(
27-
properties: SemanticsProperties(
28-
label: "${getLocalizedLoopMode(context, queueService.loopMode)}. Tap to toggle.",
29-
button: true,
30-
),
31-
excludeSemantics: true,
32-
container: true,
33-
child: IconButton(
34-
onPressed: () async {
35-
FeedbackHelper.feedback(FeedbackType.light);
36-
queueService.toggleLoopMode();
37-
},
38-
icon: _getRepeatingIcon(
39-
queueService.loopMode,
40-
Theme.of(context).colorScheme.secondary,
41-
)),
42-
);
26+
return IconButton(
27+
tooltip: "${getLocalizedLoopMode(context, queueService.loopMode)}. ${AppLocalizations.of(context)!.genericToggleButtonTooltip}",
28+
onPressed: () async {
29+
FeedbackHelper.feedback(FeedbackType.light);
30+
queueService.toggleLoopMode();
31+
},
32+
icon: _getRepeatingIcon(
33+
queueService.loopMode,
34+
Theme.of(context).colorScheme.secondary,
35+
));
4336
});
4437
}
4538

lib/components/PlayerScreen/player_buttons_shuffle.dart

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:flutter/rendering.dart';
99
import 'package:flutter_tabler_icons/flutter_tabler_icons.dart';
1010
import 'package:flutter_vibrate/flutter_vibrate.dart';
1111
import 'package:get_it/get_it.dart';
12+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1213

1314
class PlayerButtonsShuffle extends StatelessWidget {
1415
final audioHandler = GetIt.instance<MusicPlayerBackgroundTask>();
@@ -21,26 +22,29 @@ class PlayerButtonsShuffle extends StatelessWidget {
2122
return StreamBuilder(
2223
stream: mediaStateStream,
2324
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
24-
return Semantics.fromProperties(
25-
properties: SemanticsProperties(
26-
label: "Playing ${_queueService.playbackOrder == FinampPlaybackOrder.shuffled ? "shuffled" : "in order"}. Tap to toggle.",
27-
button: true,
28-
),
29-
excludeSemantics: true,
30-
container: true,
31-
child: IconButton(
32-
onPressed: () async {
33-
FeedbackHelper.feedback(FeedbackType.light);
34-
_queueService.togglePlaybackOrder();
35-
},
36-
icon: Icon(
37-
(_queueService.playbackOrder == FinampPlaybackOrder.shuffled
38-
? TablerIcons.arrows_shuffle
39-
: TablerIcons.arrows_right),
40-
),
25+
return IconButton(
26+
tooltip: getLocalizedPlaybackOrder(context, _queueService.playbackOrder),
27+
onPressed: () async {
28+
FeedbackHelper.feedback(FeedbackType.light);
29+
_queueService.togglePlaybackOrder();
30+
},
31+
icon: Icon(
32+
(_queueService.playbackOrder == FinampPlaybackOrder.shuffled
33+
? TablerIcons.arrows_shuffle
34+
: TablerIcons.arrows_right),
4135
),
4236
);
4337
},
4438
);
4539
}
40+
41+
String getLocalizedPlaybackOrder(BuildContext context, FinampPlaybackOrder playbackOrder) {
42+
switch (playbackOrder) {
43+
case FinampPlaybackOrder.linear:
44+
return AppLocalizations.of(context)!.playbackOrderLinearButtonTooltip;
45+
case FinampPlaybackOrder.shuffled:
46+
return AppLocalizations.of(context)!.playbackOrderShuffledButtonTooltip;
47+
}
48+
}
49+
4650
}

lib/components/PlayerScreen/player_screen_album_image.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
99
import 'package:flutter_vibrate/flutter_vibrate.dart';
1010
import 'package:get_it/get_it.dart';
1111
import 'package:simple_gesture_detector/simple_gesture_detector.dart';
12+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1213

1314
import '../../services/current_album_image_provider.dart';
1415
import '../../services/favorite_provider.dart';
@@ -35,7 +36,7 @@ class PlayerScreenAlbumImage extends ConsumerWidget {
3536
final currentTrack = snapshot.data!.currentTrack;
3637

3738
return Semantics(
38-
label: "Artwork for ${currentTrack?.item.title}. Tap to toggle playback. Swipe left or right to switch tracks.",
39+
label: AppLocalizations.of(context)!.playerAlbumArtworkTooltip(currentTrack?.item.title ?? AppLocalizations.of(context)!.unknownName),
3940
excludeSemantics: true, // replace child semantics with custom semantics
4041
container: true,
4142
child: GestureDetector(

lib/components/PlayerScreen/progress_slider.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
77
import 'package:flutter/semantics.dart';
88
import 'package:flutter_riverpod/flutter_riverpod.dart';
99
import 'package:get_it/get_it.dart';
10+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1011

1112
import '../../services/music_player_background_task.dart';
1213

@@ -235,7 +236,9 @@ class __PlaybackProgressSliderState
235236
final durationFullHours = (widget.mediaItem?.duration?.inHours ?? 0);
236237
final durationFullMinutes = (widget.mediaItem?.duration?.inMinutes ?? 0) % 60;
237238
final durationSeconds = (widget.mediaItem?.duration?.inSeconds ?? 0) % 60;
238-
return "${positionFullHours > 0 ? "$positionFullHours hours " : ""}${positionFullMinutes > 0 ? "$positionFullMinutes minutes " : ""}$positionSeconds seconds of ${durationFullHours > 0 ? "$durationFullHours hours " : ""}${durationFullMinutes > 0 ? "$durationFullMinutes minutes " : ""}$durationSeconds seconds";
239+
final positionString = "${positionFullHours > 0 ? "$positionFullHours ${AppLocalizations.of(context)!.hours} " : ""}${positionFullMinutes > 0 ? "$positionFullMinutes ${AppLocalizations.of(context)!.minutes} " : ""}$positionSeconds ${AppLocalizations.of(context)!.seconds}";
240+
final durationString = "${durationFullHours > 0 ? "$durationFullHours ${AppLocalizations.of(context)!.hours} " : ""}${durationFullMinutes > 0 ? "$durationFullMinutes ${AppLocalizations.of(context)!.minutes} " : ""}$durationSeconds ${AppLocalizations.of(context)!.seconds}";
241+
return AppLocalizations.of(context)!.timeFractionTooltip(positionString, durationString);
239242
},
240243
secondaryTrackValue:
241244
widget.mediaItem?.extras?["downloadedSongPath"] == null

lib/components/PlayerScreen/song_name_content.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:finamp/screens/player_screen.dart';
77
import 'package:flutter/material.dart';
88
import 'package:flutter/semantics.dart';
99
import 'package:get_it/get_it.dart';
10+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1011

1112
import '../../services/queue_service.dart';
1213
import 'album_chip.dart';
@@ -58,7 +59,7 @@ class SongNameContent extends StatelessWidget {
5859
),
5960
child: Semantics.fromProperties(
6061
properties: SemanticsProperties(
61-
label: "${currentTrack.item.title} (Title)",
62+
label: "${currentTrack.item.title} (${AppLocalizations.of(context)!.title})",
6263
),
6364
excludeSemantics: true,
6465
container: true,

lib/components/album_image.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
88
import 'package:flutter_blurhash/flutter_blurhash.dart';
99
import 'package:flutter_riverpod/flutter_riverpod.dart';
1010
import 'package:octo_image/octo_image.dart';
11+
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
1112

1213
import '../models/jellyfin_models.dart';
1314
import '../services/album_image_provider.dart';
@@ -75,7 +76,8 @@ class AlbumImage extends ConsumerWidget {
7576
}
7677

7778
return Semantics(
78-
label: "Artwork${item?.name != null ? "for ${item?.name}" : ""}",
79+
// label: item?.name != null ? AppLocalizations.of(context)!.artworkTooltip(item!.name!) : AppLocalizations.of(context)!.artwork, // removed to reduce screen reader verbosity
80+
excludeSemantics: true,
7981
child: AspectRatio(
8082
aspectRatio: 1.0,
8183
child: Align(

0 commit comments

Comments
 (0)