This repository was archived by the owner on Jul 7, 2026. It is now read-only.
[2.3.11] — 2026-04-27
Polish round 4 — performance, race fixes, accessibility hints from a final pre-release audit.
Fixed — LibraryView performance on heavy listeners
@Querywas fetching every Episode in the database, on every render. The two derived arrays (inProgressEpisodes,freshEpisodes) filtered in Swift after a fetch-all. With 30 subscriptions and a 2k-episode back catalog (typical OPML import from a long-time listener), every Library render hydrated 2,000 model objects into memory just to drop most of them.- Now uses two predicate-filtered
@Querydeclarations that push theisSubscribed && !isPlayed [&& playedPosition > 0]check down to SQLite. Only the matching rows hydrate. - Per-podcast counts pre-bucketed once instead of recomputed inside the
ForEachover subscribed shows. The prior loop was O(N×M) — for each podcast row, it filteredfreshEpisodesto count that podcast's unplayed episodes. With 30 podcasts and 2k episodes that's 60k iterations per scroll frame. Now O(N+M) total: build aDictionary<UUID, Int>once, look up by podcast id.
Fixed — race between unsubscribe and currently-playing episode
PodcastUnsubscribeServicedeleting downloaded files for an unsubscribed podcast could fire whileAVPlayerwas mid-read on the local file URL — the file got removed from under the player. Now checks whether the currently-playing episode belongs to the podcast being unsubscribed and pauses playback first via the newPlaybackController.pause()public method. Without this the symptom was either silent corruption or a crash on some iOS versions.
Added — accessibility hints
- PlayerView SPEED Menu —
accessibilityLabel("Playback speed") / accessibilityHint("Pick a speed for this podcast"). VoiceOver previously announced just the visual label with no context about the Menu's purpose. - PlayerView SLEEP Menu — same treatment, with hint that adapts to whether a timer is currently active.