Skip to content

Commit

Permalink
add many missing accessibility labels
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaphasilor committed Sep 15, 2024
1 parent f8f8a65 commit 493e379
Show file tree
Hide file tree
Showing 19 changed files with 769 additions and 602 deletions.
72 changes: 41 additions & 31 deletions lib/components/AddToPlaylistScreen/add_to_playlist_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:finamp/services/favorite_provider.dart';
import 'package:finamp/services/feedback_helper.dart';
import 'package:finamp/services/finamp_settings_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_vibrate/flutter_vibrate.dart';
Expand Down Expand Up @@ -41,37 +42,46 @@ class _AddToPlaylistButtonState extends ConsumerState<AddToPlaylistButton> {
}

bool isFav = ref.watch(isFavoriteProvider(FavoriteRequest(widget.item)));
return GestureDetector(
onLongPress: () async {
FeedbackHelper.feedback(FeedbackType.selection);
ref
.read(isFavoriteProvider(FavoriteRequest(widget.item)).notifier)
.updateFavorite(!isFav);
},
child: IconButton(
icon: Icon(
isFav ? Icons.favorite : Icons.favorite_outline,
size: widget.size ?? 24.0,
),
color: widget.color ?? IconTheme.of(context).color,
disabledColor:
(widget.color ?? IconTheme.of(context).color)!.withOpacity(0.3),
visualDensity: widget.visualDensity ?? VisualDensity.compact,
// tooltip: AppLocalizations.of(context)!.addToPlaylistTooltip,
onPressed: () async {
if (FinampSettingsHelper.finampSettings.isOffline) {
return GlobalSnackbar.message((context) =>
AppLocalizations.of(context)!.notAvailableInOfflineMode);
}

bool inPlaylist = queueItemInPlaylist(widget.queueItem);
await showPlaylistActionsMenu(
context: context,
item: widget.item!,
parentPlaylist: inPlaylist ? widget.queueItem!.source.item : null,
usePlayerTheme: true,
);
}),
return Semantics.fromProperties(
properties: SemanticsProperties(
label: AppLocalizations.of(context)!.addToPlaylistTooltip,
hint: "Tap to add to playlist. Long press to toggle favorite.",
button: true,
),
excludeSemantics: true,
container: true,
child: GestureDetector(
onLongPress: () async {
FeedbackHelper.feedback(FeedbackType.selection);
ref
.read(isFavoriteProvider(FavoriteRequest(widget.item)).notifier)
.updateFavorite(!isFav);
},
child: IconButton(
icon: Icon(
isFav ? Icons.favorite : Icons.favorite_outline,
size: widget.size ?? 24.0,
),
color: widget.color ?? IconTheme.of(context).color,
disabledColor:
(widget.color ?? IconTheme.of(context).color)!.withOpacity(0.3),
visualDensity: widget.visualDensity ?? VisualDensity.compact,
// tooltip: AppLocalizations.of(context)!.addToPlaylistTooltip,
onPressed: () async {
if (FinampSettingsHelper.finampSettings.isOffline) {
return GlobalSnackbar.message((context) =>
AppLocalizations.of(context)!.notAvailableInOfflineMode);
}

bool inPlaylist = queueItemInPlaylist(widget.queueItem);
await showPlaylistActionsMenu(
context: context,
item: widget.item!,
parentPlaylist: inPlaylist ? widget.queueItem!.source.item : null,
usePlayerTheme: true,
);
}),
),
);
}
}
144 changes: 83 additions & 61 deletions lib/components/AlbumScreen/download_button.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:finamp/services/finamp_settings_helper.dart';
import 'package:finamp/services/finamp_user_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get_it/get_it.dart';
Expand Down Expand Up @@ -52,68 +53,89 @@ class DownloadButton extends ConsumerWidget {
viewId = finampUserHelper.currentUser!.currentViewId!;
}

var downloadButton = IconButton(
icon: status == DownloadItemStatus.notNeeded
? const Icon(Icons.file_download)
: const Icon(Icons.lock), //TODO get better icon
onPressed: () async {
if (isLibrary) {
await showDialog(
context: context,
builder: (context) => ConfirmationPromptDialog(
promptText: AppLocalizations.of(context)!
.downloadLibraryPrompt(item.name),
confirmButtonText:
AppLocalizations.of(context)!.addButtonLabel,
abortButtonText:
MaterialLocalizations.of(context).cancelButtonLabel,
onConfirmed: () =>
DownloadDialog.show(context, item, viewId),
onAborted: () {},
));
} else {
await DownloadDialog.show(context, item, viewId);
}
},
tooltip: parentTooltip,
var downloadButton = Semantics.fromProperties(
properties: SemanticsProperties(
label: AppLocalizations.of(context)!.downloadItem,
button: true,
),
container: true,
child: IconButton(
icon: status == DownloadItemStatus.notNeeded
? const Icon(Icons.file_download)
: const Icon(Icons.lock), //TODO get better icon
onPressed: () async {
if (isLibrary) {
await showDialog(
context: context,
builder: (context) => ConfirmationPromptDialog(
promptText: AppLocalizations.of(context)!
.downloadLibraryPrompt(item.name),
confirmButtonText:
AppLocalizations.of(context)!.addButtonLabel,
abortButtonText:
MaterialLocalizations.of(context).cancelButtonLabel,
onConfirmed: () =>
DownloadDialog.show(context, item, viewId),
onAborted: () {},
));
} else {
await DownloadDialog.show(context, item, viewId);
}
},
tooltip: parentTooltip,
),
);
var deleteButton = IconButton(
icon: const Icon(Icons.delete),
// If offline, we don't allow the user to delete items.
// If we did, we'd have to implement listeners for MusicScreenTabView so that the user can't delete a parent, go back, and select the same parent.
// If they did, AlbumScreen would show an error since the item no longer exists.
// Also, the user could delete the parent and immediately redownload it, which will either cause unwanted network usage or cause more errors because the user is offline.
onPressed: () {
showDialog(
context: context,
builder: (context) => ConfirmationPromptDialog(
promptText: AppLocalizations.of(context)!.deleteDownloadsPrompt(
item.baseItem?.name ?? "", item.baseItemType.name),
confirmButtonText:
AppLocalizations.of(context)!.deleteDownloadsConfirmButtonText,
abortButtonText:
AppLocalizations.of(context)!.deleteDownloadsAbortButtonText,
onConfirmed: () async {
try {
await downloadsService.deleteDownload(stub: item);
GlobalSnackbar.message((scaffold) =>
AppLocalizations.of(scaffold)!.downloadsDeleted);
} catch (error) {
GlobalSnackbar.error(error);
}
},
onAborted: () {},
),
);
// .whenComplete(() => checkIfDownloaded());
},
var deleteButton = Semantics.fromProperties(
properties: SemanticsProperties(
label: AppLocalizations.of(context)!.deleteItem,
button: true,
),
container: true,
child: IconButton(
icon: const Icon(Icons.delete),
// If offline, we don't allow the user to delete items.
// If we did, we'd have to implement listeners for MusicScreenTabView so that the user can't delete a parent, go back, and select the same parent.
// If they did, AlbumScreen would show an error since the item no longer exists.
// Also, the user could delete the parent and immediately redownload it, which will either cause unwanted network usage or cause more errors because the user is offline.
onPressed: () {
showDialog(
context: context,
builder: (context) => ConfirmationPromptDialog(
promptText: AppLocalizations.of(context)!.deleteDownloadsPrompt(
item.baseItem?.name ?? "", item.baseItemType.name),
confirmButtonText:
AppLocalizations.of(context)!.deleteDownloadsConfirmButtonText,
abortButtonText:
AppLocalizations.of(context)!.deleteDownloadsAbortButtonText,
onConfirmed: () async {
try {
await downloadsService.deleteDownload(stub: item);
GlobalSnackbar.message((scaffold) =>
AppLocalizations.of(scaffold)!.downloadsDeleted);
} catch (error) {
GlobalSnackbar.error(error);
}
},
onAborted: () {},
),
);
// .whenComplete(() => checkIfDownloaded());
},
)
);
var syncButton = IconButton(
icon: const Icon(Icons.sync),
onPressed: () {
downloadsService.resync(item, viewId);
},
color: status.outdated ? Colors.orange : null,
var syncButton = Semantics.fromProperties(
properties: SemanticsProperties(
label: AppLocalizations.of(context)!.syncDownloads,
button: true,
),
container: true,
child: IconButton(
icon: const Icon(Icons.sync),
onPressed: () {
downloadsService.resync(item, viewId);
},
color: status.outdated ? Colors.orange : null,
)
);
if (isOffline) {
if (status.isRequired) {
Expand All @@ -125,7 +147,7 @@ class DownloadButton extends ConsumerWidget {
var coreButton = status.isRequired ? deleteButton : downloadButton;
// Only show sync on album/song if there we know we are outdated due to failed downloads or the like.
// On playlists/artists/genres, always show if downloaded.
List<IconButton> buttons;
List<Widget> buttons;
if (status == DownloadItemStatus.notNeeded ||
((item.baseItemType == BaseItemDtoType.album ||
item.baseItemType == BaseItemDtoType.song) &&
Expand Down
2 changes: 1 addition & 1 deletion lib/components/AlbumScreen/song_menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ class _SongMenuState extends ConsumerState<SongMenu> {
final loopModeTooltips = {
FinampLoopMode.none:
AppLocalizations.of(context)?.loopModeNoneButtonLabel ??
"Looping off",
"Not looping",
FinampLoopMode.one:
AppLocalizations.of(context)?.loopModeOneButtonLabel ??
"Looping this song",
Expand Down
30 changes: 17 additions & 13 deletions lib/components/MusicScreen/alphabet_item_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,25 @@ class _AlphabetListState extends State<AlphabetList> {
onPointerMove: (x) => updateSelected(x.localPosition, Drag.update),
onPointerUp: (x) => updateSelected(x.localPosition, Drag.end),
behavior: HitTestBehavior.opaque,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
alphabet.length,
(x) => Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
height: _letterHeight,
child: FittedBox(
child: Text(
alphabet[x].toUpperCase(),
child: Semantics(
label: 'Alphabet list for fast scrolling',
excludeSemantics: true, // replace child semantics with custom semantics
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
alphabet.length,
(x) => Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 0),
height: _letterHeight,
child: FittedBox(
child: Text(
alphabet[x].toUpperCase(),
),
),
),
),
)),
)),
),
);
}),
);
Expand Down
51 changes: 30 additions & 21 deletions lib/components/MusicScreen/view_list_tile.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:finamp/components/AlbumScreen/download_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:get_it/get_it.dart';

Expand All @@ -20,29 +21,37 @@ class ViewListTile extends ConsumerWidget {
var currentViewId = ref.watch(FinampUserHelper.finampCurrentUserProvider
.select((value) => value.valueOrNull?.currentViewId));

return ListTile(
leading: Padding(
padding: const EdgeInsets.only(right: 16),
child: ViewIcon(
collectionType: view.collectionType,
color: currentViewId == view.id
? Theme.of(context).colorScheme.primary
: null,
),
return Semantics.fromProperties(
properties: SemanticsProperties(
label: view.name,
selected: currentViewId == view.id,
),
title: Text(
view.name ?? "Unknown Name",
style: TextStyle(
color: currentViewId == view.id
? Theme.of(context).colorScheme.primary
: null,
container: true,
child: ListTile(
leading: Padding(
padding: const EdgeInsets.only(right: 16),
child: ViewIcon(
collectionType: view.collectionType,
color: currentViewId == view.id
? Theme.of(context).colorScheme.primary
: null,
),
),
title: Text(
view.name ?? "Unknown Name",
semanticsLabel: "", // covered by SemanticsProperties
style: TextStyle(
color: currentViewId == view.id
? Theme.of(context).colorScheme.primary
: null,
),
),
onTap: () => finampUserHelper.setCurrentUserCurrentViewId(view.id),
trailing: DownloadButton(
isLibrary: true,
item: DownloadStub.fromItem(
item: view, type: DownloadItemType.collection),
),
),
onTap: () => finampUserHelper.setCurrentUserCurrentViewId(view.id),
trailing: DownloadButton(
isLibrary: true,
item: DownloadStub.fromItem(
item: view, type: DownloadItemType.collection),
),
);
}
Expand Down
Loading

0 comments on commit 493e379

Please sign in to comment.