[v2.2.0] — 2026-11-08
Ephyra gets its own look, a real tablet layout and a lot more speed. The app now wears the
Bioluminescence identity: deep navy chrome, cyan only for what is alive (playback, downloads,
focus), violet for what is yours (favourites, watched, ratings), the Outfit typeface and round
pill buttons; Material You dynamic colours are now an opt-in instead of the default. On a tablet,
an unfolded foldable or a split-screen window the same app lays itself out for the width: a
navigation rail, movie and show pages with the poster beside the text over a full-width backdrop,
seasons as a list with the selected episode next to it, and a player that keeps the orientation
you hold it in, with an episode panel, keyboard and mouse support and tabletop posture on
foldables. Under the hood a performance pass across the whole app makes cold start, page loads,
scrolling and playback start noticeably quicker, on TV as much as on the phone.
Added
- Tablet and wide-window layouts: navigation rail, hero item pages for movies, shows and
episodes, seasons as list and detail side by side, wider cards and grids, Downloads in two
columns, readable text widths everywhere (#288, #290, #291, #297). - Player on wide windows: free orientation, volume and brightness swipes only near the edges,
roomier controls, an episode panel to switch episodes without leaving playback (#289, #301,
#314). - Player keyboard and mouse: Space, arrows, M (mute), L (lock), Esc, media keys; the mouse shows
the controls and the wheel seeks; Ctrl+F opens search (#310). - Foldables: in tabletop posture the video sits above the fold and the controls below it; the
controls resize when the window does (#313). - Profiles: user faces in the chrome, one-tap switching between users, default avatars (#248).
- Media segments (intro, outro, recap, preview, commercial): one action per type, skip, ask or
ignore; the skip button follows the segment window on phone and hides after its window on TV
(#283). - HDR10+ and Dolby Atmos badges on movie and episode pages (#282).
- Home: a switch for the remembered Home rows and a Clear cache row (#270).
- About screens for phone and TV with install, server and device info (#223).
- A swimming jellyfish on the welcome screen, specks on empty states and the TV screensaver
(#227, #235).
Changed
- The Bioluminescence identity: the Ephyra palette is the default and dynamic colours are an
opt-in (#225); colour tokens (#224); Outfit for display, headline and title text (#228);
round shape roles and pill actions (#226); violet for favourite, watched and rating (#229);
a glow and a cyan focus ring on TV (#233, #242); buoyant motion and transitions (#234); TV item
pages fade to the surface colour (#237); the storage summary's Other segment is neutral (#246);
player dialogs tint the selected option with the accent (#244). - Performance: codec probe, database and sync jobs off the cold-start path (#260, #261); show,
season, person, movie and episode pages load their parts concurrently (#262, #274); fewer
recompositions in the TV player, Season and Main (#263); the Downloads screen loads in one
batch and polls less (#264, #277, #279, #293); batched database lookups, bigger library pages
and a lazier letter index (#265); Compose stability config and a carousel that pauses while
you scroll (#266); playback starts sooner (#267); screens reload on resume only when stale,
overlapping loads are cancelled and Home rows are cached (#268, #273, #275); a baseline
profile ships with the app (#269, #285); artwork loads at display size (#294); TV backdrops
are capped at 1280 px (#278). - The no-op "lazy trickplay" developer toggle is gone (#276).
Fixed
- mpv reaches the ready state on the first restart when no seek is pending (#312).
- Each player gets its own media session id (#231).
- The "still watching?" prompt shows on TV (#243).
- Status-bar icons stay readable over backdrops on item pages (#291, #297).
- The HDR10+ wordmark is drawn at 16 dp so "10+" stays legible (#282).
Maintenance
- Dependencies: Android Gradle plugin 9.5.1, Gradle 9.9.0, KSP 2.3.13, Navigation 3 1.2.1,
fragment-ktx 1.9.1, ZXing 3.5.4, GitHub Actions majors; Renovate configured and JDK pinned to
21 (#198–#207, #247). - Repository: Google Play metadata and screenshots, LF line endings enforced, the website and
README redone with new screenshots and a tablet section (#208, #311, #315).
What's Changed
- chore(deps): update android.plugin to v9.5.1 by @renovate[bot] in #198
- chore(deps): update dependency com.google.devtools.ksp to v2.3.13 by @renovate[bot] in #199
- chore(deps): update dependency ruby to v4.0.9 by @renovate[bot] in #200
- fix(deps): update androidx.navigation3 to v1.2.1 by @renovate[bot] in #201
- fix(deps): update dependency androidx.fragment:fragment-ktx to v1.9.1 by @renovate[bot] in #203
- chore(renovate): ignore java-jdk updates to preserve JDK 21 LTS by @midasvo in #205
- chore(deps): update gradle to v9.9.0 by @renovate[bot] in #206
- feat(play): prepare the repo for Google Play by @midasvo in #208
- docs: link the privacy policy on midasvo.nl over https by @midasvo in #209
- docs(identity): land the Bioluminescence vision by @midasvo in #222
- chore(deps): update github-actions (major) by @renovate[bot] in #207
- feat(identity): Bioluminescence colour tokens by @midasvo in #224
- feat(theme): Ephyra palette by default; dynamic colours are now opt-in by @midasvo in #225
- feat: About screens for TV and phone by @midasvo in #223
- feat(identity): round shape roles and pill actions by @midasvo in #226
- feat(phone): the swimming jellyfish on the welcome screen by @midasvo in #227
- feat(identity): Outfit for display, headline and title roles by @midasvo in #228
- feat(identity): violet for favourite, watched and rating by @midasvo in #229
- docs: rewrite the README by @midasvo in #230
- fix(player): unique media session id per player by @midasvo in #231
- feat(identity): glow modifier and cyan TV focus ring by @midasvo in #233
- feat(identity): buoyant motion tokens and transitions (#219) by @midasvo in #234
- feat(identity): welcome halo, empty-state and screensaver specks by @midasvo in #235
- fix(identity): TV item pages fade to surface, not black by @midasvo in #237
- docs(screenshots): retake README screenshots for the Bioluminescence identity by @midasvo in #239
- feat(site): landing page in the Bioluminescence identity by @midasvo in #241
- feat(identity): TV drawer items get the focus ring by @midasvo in #242
- fix(player): show the still-watching prompt on TV by @midasvo in #243
- fix(identity): View player dialogs tint the selected radio with primary by @midasvo in #244
- feat(identity): storage summary's Other segment is a neutral by @midasvo in #246
- fix(deps): update dependency com.google.zxing:core to v3.5.4 by @renovate[bot] in #247
- Profile switching: faces in the chrome, one-tap switch, default avatars by @midasvo in #248
- perf(phone): keep the AndroidX startup provider so baseline profiles install by @midasvo in #260
- perf(build): baseline profile module, startup benchmark, narrower R8 keep rule by @midasvo in #269
- perf(startup): take the codec probe, Room and the sync jobs off cold start by @midasvo in #261
- perf(tv): player, Season and Main recompositions, hero backdrop without an offscreen layer by @midasvo in #263
- perf(downloads): batched load, cheaper queue consumers, settings storage off Main by @midasvo in #264
- perf(compose): stability config, carousel pauses during scroll, one click modifier per card by @midasvo in #266
- perf(player): start playback sooner by @midasvo in #267
- perf(detail): load Show, Season and Person pages concurrently by @midasvo in #262
- perf(data): batch Room lookups, bigger library pages, lazier letter index by @midasvo in #265
- perf(reload): reload on resume only when stale, cancel overlapping loads, cache Home rows by @midasvo in #268
- feat(home): switch for the remembered Home rows, Clear cache row, no dip on cold start by @midasvo in #270
- feat(player): media segments polish: TV skip timeout, one per-type setting, SegmentTracker, Ephyra button by @midasvo in #283
- perf(phone): reload the Media tab only when stale or dirty by @midasvo in #273
- perf(film): person limit, concurrent Movie/Episode loads, seriesId to Season by @midasvo in #274
- perf(data): skip source lookups without downloads, pager total from page one by @midasvo in #275
- refactor(settings): remove the no-op lazy trickplay developer toggle by @midasvo in #276
- perf(downloads): skip speed-only queue emissions, poll at 2 s with several downloads by @midasvo in #277
- perf(tv): cap detail-page backdrops at 1280 px by @midasvo in #278
- perf(phone): contentType and remembered lists on the Downloads screen by @midasvo in #279
- feat(item): HDR10+ and Dolby Atmos badges on the movie and episode pages by @midasvo in #282
- perf(phone): commit the baseline profile and record the #249 benchmark by @midasvo in #285
- Tablet: research, design and first stop-gaps by @midasvo in #288
- feat(player): free orientation and edge gesture zones on wide windows (R6) by @midasvo in #289
- feat(phone): row, grid, search and downloads sizing from layout tokens (R4) by @midasvo in #290
- docs(tablet): align the design with R2-R6 and tick the roadmap by @midasvo in #292
- feat(phone): hero detail layout for movie, show and episode on wide windows (R2, R3) by @midasvo in #291
- perf(downloads): load the Downloads list at once, stop recomposing the button per frame by @midasvo in #293
- perf(images): load artwork at display size by default by @midasvo in #294
- feat(phone): season as list-detail on expanded windows (R5) by @midasvo in #297
- feat(player): roomier controls on expanded windows (R7) by @midasvo in #301
- docs(tablet): test matrix, AVD script and 10-inch store screenshots (R11) by @midasvo in #302
- feat(phone): keyboard and mouse support in the player and on cards (R8) by @midasvo in #310
- chore: normalise the remaining CRLF files and enforce LF by @midasvo in #311
- feat(player): tabletop posture on foldables and live control sizing (R9) by @midasvo in #313
- docs(player): mpv research for #284, phases 1 to 4 by @midasvo in #287
- fix(player): mpv reaches STATE_READY on the first restart when no seek is pending by @midasvo in #312
- feat(player): episode side sheet on expanded windows (R10) by @midasvo in #314
- docs: new screenshots from the demo server, with a tablet section by @midasvo in #315
- chore(release): v2.2.0 by @midasvo in #316
New Contributors
Full Changelog: v2.1.0...v2.2.0
Which APK? ephyra-v<version>-libre-<abi>.apk is for phones and tablets,
ephyra-v<version>-libre-tv-<abi>.apk for Android TV. Most phones need arm64-v8a;
32-bit TV boxes such as the Xiaomi Mi Box need armeabi-v7a. In Obtainium, filter the TV APK
with .*-tv-armeabi-v7a\.apk.