ShelfPlayer icon indicating copy to clipboard operation
ShelfPlayer copied to clipboard

[Accessibility] Expose and announce download progress (% complete) for VoiceOver

Open math65 opened this issue 3 months ago • 4 comments

On iOS, when I download a book in ShelfPlayer, I can’t tell—using VoiceOver—whether the item is still downloading or finished. VoiceOver doesn’t expose any progress information (e.g., percentage), and there’s no clear completion announcement.

Summary

  • Problem: Download progress is not conveyed to VoiceOver users.
  • Impact: I can’t know if a book is downloading, how far along it is, or when it completes—without sighted assistance.
  • Request: Provide an accessible progress indicator with a percentage (and/or transferred size) and a completion announcement.

Steps to Reproduce

  1. On iOS, enable VoiceOver.
  2. In ShelfPlayer, start downloading any book.
  3. Navigate to the item (library, book detail, and explore with VoiceOver.
  4. Notice that VoiceOver does not read a changing progress value (e.g., “Downloading — 42%”).

Actual Behavior

  • VoiceOver announces something like “Downloading” or a static label, but no numeric progress is exposed.
  • There’s no clear auditory announcement when the download completes.

Expected Behavior

  • While downloading, VoiceOver should announce a progress value that updates (e.g., “Downloading — 42%”).

Why this matters (Accessibility impact)

For blind users, downloads without progress feedback are guesswork. A simple percentage and a completion announcement make the experience predictable and independent.

Environment

  • App: ShelfPlayer — V3.0.4
  • OS: iOS — V18.6.2
  • Device: iPhone 15 pro (VoiceOver enabled)

Additional Context

I’m a VoiceOver user. If you need me to test a TestFlight build or share logs, I’m happy to help. I’m not sure whether a visual progress indicator is normally shown, but with VoiceOver enabled I don’t get any progress feedback, and I also couldn’t find a dedicated “Downloads” view to monitor all active downloads.

math65 avatar Aug 31 '25 00:08 math65

Hey, there are some VoiceOver / SwiftUI limitations I discovered while implementing VoiceOver: The accessibility value would not update properly, even if the underlying value changes. But I will look into it. How would you expect the announce functionality to work, I couldn't find a similar feature in Apple Music / Podcasts?

You can enable the offline mode from the menu in the top right hand corner on the home panel, there all downloads, including in progress ones, are shown.

rasmuslos avatar Sep 04 '25 19:09 rasmuslos

Hi,

Thanks a lot for your reply!

I didn’t know that the “switch library” button actually enabled an offline mode — that’s very useful 🙂 And regarding the announce functionality, yes, in Apple Music or the App Store, VoiceOver announces the progress while downloading (like “Downloading 20%, 30%…”), so I was expecting something similar here.

Le 4 sept. 2025 à 21:30, Rasmus Krämer @.***> a écrit :

Hey, there are some VoiceOver / SwiftUI limitations I discovered while implementing VoiceOver: The accessibility value would not update properly, even if the underlying value changes. But I will look into it. How would you expect the announce functionality to work, I couldn't find a similar feature in Apple Music / Podcasts?

You can enable the offline mode from the menu in the top right hand corner on the home panel, there all downloads, including in progress ones, are shown.

math65 avatar Sep 04 '25 20:09 math65

Hi, Following this issue and maybe adding some insights.

Accessibility Value

ProgressView(value: progress, total: 1.0)
    .accessibilityValue("\(Int(progress * 100))%")

Progress Labels

ProgressView("Loading", value: progress, total: 1.0)
    .accessibilityLabel("Loading progress")
    .accessibilityValue("\(Int(progress * 100))% complete")

Auto-announcing Updates

struct AccessibleProgressView: View {
    @State private var progress: Double = 0.0
    
    var body: some View {
        ProgressView(value: progress, total: 1.0)
            .accessibilityValue("\(Int(progress * 100))%")
            .onChange(of: progress) { _, newValue in
                let percentage = Int(newValue * 100)
                // Announce every 10% or at completion
                if percentage % 10 == 0 || percentage == 100 {
                    UIAccessibility.post(
                        notification: .announcement,
                        argument: "\(percentage)% complete"
                    )
                }
            }
    }
}

Additional Tips

  • Use .accessibilityHint() for context about what's loading
  • Consider .accessibilityRemoveTraits(.updatesFrequently) if progress updates are too frequent
  • For indeterminate progress: .accessibilityLabel("Loading in progress")

yplassiard avatar Sep 05 '25 09:09 yplassiard

I didn't know about UIAccessibility.post, I will look into adding it!

rasmuslos avatar Oct 05 '25 15:10 rasmuslos