feat(android,ios): read each library tile once, with its long press as an action

A poster's artwork carried the title's name and so did the text under
it, so a screen reader said the name twice. The artwork is now left out
where the text names it, and a folded franchise tile says how many more
it stands for. The long press that opens a tile's menu is offered as an
action, labelled on Android and as More on iOS, where tapAndHold also
makes the whole tile one button. On iOS the app behind a full-screen
player is hidden from VoiceOver, which walked the library behind the
picture.
This commit is contained in:
nvrl committed 2026-10-13 16:51:11 +02:00
1 parent 01eee78317
commit bf3fa19c70
4 files changed
+26 -5

No files matched your search

+4
View File
@@ -541,7 +541,9 @@ private struct ContinueCard: View {
var body: some View {
VStack(alignment: .leading, spacing: 0) {
// Named by the text under it; read as well, the name came twice.
RemoteArtwork(entry.episode.stillUrl ?? entry.title.backdropUrl, entry.title.displayName, fallback: entry.episode.thumbnailSource)
.accessibilityHidden(true)
.aspectRatio(16 / 9, contentMode: .fit)
.overlay(alignment: .bottom) {
if let progress = entry.episode.progress { AccentProgress(progress: progress) }
@@ -571,6 +573,7 @@ struct PosterTile: View {
var body: some View {
VStack(alignment: .leading, spacing: 0) {
RemoteArtwork(title.posterUrl ?? title.backdropUrl, title.displayName, fallback: title.thumbnailSource)
.accessibilityHidden(true)
.aspectRatio(2 / 3, contentMode: .fit)
.clipShape(RoundedRectangle(cornerRadius: Corner.standard))
.overlay(alignment: .topTrailing) {
@@ -581,6 +584,7 @@ struct PosterTile: View {
.padding(.horizontal, 6).padding(.vertical, 2)
.background(.black.opacity(0.7), in: RoundedRectangle(cornerRadius: Corner.standard))
.padding(6)
.accessibilityLabel("and \(folded) more")
}
}
Text(title.displayName).textStyle(.bodyMedium, semibold: true).foregroundStyle(scheme.onSurface)
+8
View File
@@ -115,6 +115,14 @@ private struct TapAndHold: ViewModifier {
.animation(.easeOut(duration: 0.1), value: pressed)
.onTapGesture(perform: onTap)
.onLongPressGesture(perform: { onHold?() }, onPressingChanged: { pressed = $0 })
// One element to VoiceOver, a button, with the long press as an
// action: a gesture is not something it can perform.
.accessibilityElement(children: .combine)
.accessibilityAddTraits(.isButton)
.accessibilityAction(.default, onTap)
.accessibilityActions {
if let onHold { Button("More", action: onHold) }
}
}
}