diff --git a/README.md b/README.md index 5e65982..ac203ba 100644 --- a/README.md +++ b/README.md @@ -1525,7 +1525,13 @@ Things I chose while building, with the reasoning: down, a male name preferred — "preferably male" was the ask), the player picks the best one automatically and offers a picker for everything in the episode's language, and the choice is remembered per language. The suite grew to 34 checks (voice ranking, the filtered picker, - persisting a pick, same-line silence, line following, manual-scroll suspension). + persisting a pick, same-line silence, line following, manual-scroll suspension). **Follow-up + 2 (0.7.5):** iOS is the special case the picker cannot fix — Safari hands web pages one voice + per language, so on an iPhone the panel now carries the settings path instead (Accessibility → + Spoken Content → Voices → language → Enhanced/Premium, set as preferred) and the speaker + button wears an amber dot while that note is waiting; the voice-less banner appends the same + guidance. Detected via the user agent (iPadOS included through `maxTouchPoints`); the suite + fakes an iPhone and pins the note, its steps and the dot (37 checks). 102. **An API key is not a login.** "When trying to use a different provider on the web app it glitches out completely" — a photo of the first-run gate with iOS's saved-password sheet laid diff --git a/components/podcast/PodcastPlayer.tsx b/components/podcast/PodcastPlayer.tsx index 8462625..53b7c51 100644 --- a/components/podcast/PodcastPlayer.tsx +++ b/components/podcast/PodcastPlayer.tsx @@ -13,6 +13,7 @@ import { savePodcastProgress } from "@/lib/podcasts"; import { bestVoice, getStoredVoice, + isAppleMobile, onlyRoboticVoices, platformVoices, setStoredVoice, @@ -103,6 +104,12 @@ export function PodcastPlayer({ episode }: { episode: Podcast }) { () => onlyRoboticVoices(voiceLocale, voiceList), [voiceLocale, voiceList], ); + /* iOS hands the page one voice per language; point at the settings that + change it (the note is the whole reason this section exists there). */ + const iosLimited = useMemo( + () => isAppleMobile() && availableVoices.length <= 1, + [availableVoices.length], + ); /** Latest position for the unmount/pause save, without re-creating callbacks. */ const latest = useRef(episode.progress ?? null); @@ -376,13 +383,19 @@ export function PodcastPlayer({ episode }: { episode: Podcast }) { aria-expanded={voiceOpen} title={voice?.name ?? t("podcast.voiceAria")} className={cn( - "grid size-10 shrink-0 place-items-center rounded-full transition", + "relative grid size-10 shrink-0 place-items-center rounded-full transition", voiceOpen ? "bg-[var(--nav-active-bg)] text-[var(--text)]" : "bg-[var(--surface-sunken)] text-[var(--text-muted)] hover:bg-[var(--hover)]", )} > + {iosLimited ? ( + + ) : null} ) : null}