Skip to content

Episode page: a Go to Show disc (refs #879) - #1035

Draft
Bardioc1977 wants to merge 4 commits into
GLinnik21:mainfrom
Bardioc1977:fix-879-episode-to-show
Draft

Bardioc1977 wants to merge 4 commits into
GLinnik21:mainfrom
Bardioc1977:fix-879-episode-to-show

Conversation

@Bardioc1977

@Bardioc1977 Bardioc1977 commented Oct 25, 2026 •

Copy link
Copy Markdown

An episode opened from Search, a Related shelf, Home Recently Added, "Go to Episode" or a deep link had no
route to its show: the only way was the hold menu on a card, which nothing hints at. The hero row of an
episode page now ends with a Go to Show disc (same unfurl as Restart, Mark as Watched and Play Version) that
opens the show on the episode's season. BACK returns to the episode page with the disc focused.

  • The press is the existing Action::GoToShow(show_rk, season) through the existing AppFx::ItemMenu ->
    apply_item_action -> open_detail route, the one the bookmark disc already uses; the show page selects the
    season by number. No new request: the episode Detail already carries show_rk, season and its server.
  • hero::show_target is the one place that says where the disc goes; the disc exists only on an episode page
    that names its show.
  • New mark Icon::EpisodeList (three rows with leading dots) so no two discs of the row share art: the Play
    Version disc next to it keeps Icon::Show, and the item menu's Go to Show row keeps Icon::Show too (the
    hero and the menu deliberately wear different marks, as Restart and Play from Start do). hero::disc_icon is
    the one table of marks the draw and a test read. The art is mine and unreviewed by a designer.
  • New key browse.detail.go_show in be, de, en, es, fr, hu, it, pt, ru (the hero's discs have their own keys;
    the description tells translators the label slides out and gates the row's width). The wording is a reuse of the
    shipped browse.menu.go_show strings, not a new translation (docs/localization.md asks for the reviewer to be named):
    German ("Zur Serie") is for the owner to review; be, es, fr, hu, it, pt, ru need a native reader, who has so far
    seen the words only as a menu row, not as a slide-out label.
  • MAX_CTLS 7 -> 8 and DISCS 4 -> 5. ELEM_GO_SHOW = 8; a PR adding another hero control takes 9 / disc slot 5 /
    MAX_CTLS 9. No SHAPE or SCREEN_SHAPES_PIN change, no replay re-record, no new ledger entry, no
    Makefile/Cargo/CI change (so no build-bench table).
  • A real bug the host route test could not see and the simulator did: BACK from the show page sent the focus to
    Play. The show's page takes the store's one current item, the episode page that BACK reveals asks its server
    again, and until the item lands the hero is only Play and the watch disc, so DetailScreen::reconcile moved a
    focus held on Go to Show to Play for the length of the load. A returning page with no item yet now holds a
    focus on a hero control (the 4th commit; the route test models the reload and fails without it). The message of 0cf2585 says the route test
    passes "BACK included"; that only became true with the 4th commit (the squash hides this).

Behaviour notes

  • Specials and episodes without a season number land on the show's default season (same as the hold menu:
    Action::GoToShow's season <= 0 convention cannot tell them apart). A follow-up could thread a tri-state.
  • Any row that also carries the Also available pill (it needs a second pinned source) has less room with the extra
    disc. Measured, rows that used to unfurl and now do not: en: Restart + Also available + Play Version; fr: Also
    available + Play Version, and Restart + Also available; es, it, pt, de, hu: the same two rows as fr; be and ru: a
    plain Play + Also available + Watch row, no Restart. In those rows every disc stays a circle and none crosses the
    People column (the existing degradation, tested). Rows without Also available unfurl Go to Show in all nine
    locales (test).
  • A show that no longer exists leaves the pushed show page in its loading state (the only trace is the
    detail: rk=.. no metadata event-log line); BACK still works, exactly like the hold menu's Go to Show.
  • Opening the show from an episode that was reached from that very show pushes a second show page; BACK unwinds.

Not in this PR: Option 2 of the issue (a Recently Added episode tile opening the show on its season) and Option 3.
Option 2 reverses the decision documented in activate_card (the tile opens the episode's page on purpose), so it
is the maintainer's call. What it would take: the deck_press_opens_show(mm, from_deck, want_play) bool pair in
app/input.rs becomes a shelf kind (Deck / Recently Added / other) decided at the Home press site (the card
menu's deck_episode_opens_show in screens/src/item_menu.rs generalised the same way, which if it needs a new
field on ItemMenuKind::Card moves SCREEN_SHAPES_PIN and forces a re-record of the three anchors; leaving the
menu as is moves nothing), plus the two tests next to a_deck_episode_press_opens_the_show_and_nothing_else_reroutes.
With this PR the show is one focus move away from every episode page, so Option 2 would only save a key press.
Refs, not Closes, for that reason.

Verification

  • host, on the committed tree: make check stops at ci/test_disk_preflight.py on this machine (AssertionError: 1 != 2 : disk-preflight: only 2.0 GiB free for ~/main/rust-modules/target; this build needs ~1.0 GiB plus a 3.0 GiB reserve (4.0 GiB), an assertion about the free space of this Mac, unrelated to the change), so its parts ran
    separately and all pass: make check-cargo (lint + both unit passes: 295, 347, 732, 1246, 288, 207, 1391, 225,
    1719, 94 passed ...; hostsim pass 1906 passed, 0 failed), make test-hostsim (1173 passed), make check-nodef,
    make check-python-harness (543 tests OK), make check-replay (all six lanes SAME), make test-crate C=plx_platform T=catalog (21 passed), ci/check-deps.sh (ledgers unchanged), ci/check-module-layers.py, ci/check-list-caps.py,
    ci/check-localization.py.
  • simulator (macOS, 1280x720 window, mock server, PLXNATIVE_LOCALE en / de / ru): Home Recently Added episode tile ->
    episode page -> RIGHT to the disc (the verb unfurls inside the capsule, no caption under the row) -> OK lands on
    the show with the episode's season tab selected -> BACK returns with the disc focused; a part-watched episode
    (Resume, Restart, watched, Go to Show); an episode with two versions (Play Version and Go to Show side by side,
    two different marks); Magic Remote click on the disc; movie and show pages show no disc; the hold menu on the
    tile is unchanged. Screenshots below.
  • Not verified on a TV: the disc's unfurl pixels, text rasterization and the new mark at panel size are TV-only claims.
    Not exercised in the simulator: a Search-result episode, pointer hover, a row with the Also available pill, full-trailer
    mode, and an episode that is both part-watched and has two versions (the mock has none).

Screenshots

Simulator at 1280x720 against tests/mock_pms.py (synthetic library; the TV was not used).

Part-watched episode, the Go to Show disc focused (its verb unfurls) en episode disc focused
Episode with two versions: Play Version and Go to Show side by side, different marks two versions, Go to Show focused
Two versions, at rest two versions at rest
OK opens the show on the episode's season (S2) show page on the episode's season
BACK returns to the episode page with the disc still focused back on the episode, disc focused
German de disc focused

Signed-off-by: Heiko Kopp 47413920+Bardioc1977@users.noreply.github.com

🤖 Generated with Claude Code

Bardioc1977 and others added 4 commits October 25, 2026 12:06
An episode opened from Search, Related, Recently Added or a deep link has no
way to its show. The plan is a Go to Show disc in the hero row that emits the
existing Action::GoToShow through the existing item-menu route. These are the
tests that pin it first:

- screen: Activate on the Go to Show elem of an episode page asks for
  GoToShow(show_rk, season) on the episode's server (red: no such disc);
- app: apply_item_action(GoToShow) seeds the show's page on the season, 0 means
  the show's own default, and the show on the episode's server is the page on
  top (green on purpose: the route is characterised before it is relied on);
- route, by keys: Right, Right reaches the disc, its verb unfurls and no
  caption stands under the row, OK opens the show on the episode's season and
  BACK returns with the disc focused (red: no such disc).

World gains detail_arg_for / detail_episode so a route test can mount an
episode page of a real server (detail_page hard-coded the movie argument).

Signed-off-by: Heiko Kopp <47413920+Bardioc1977@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An episode opened from Search, a Related shelf, Home Recently Added or a deep
link had no route to its show; the only one was the hold menu on a card, which
nothing hints at. The hero row of an episode page now ends with a Go to Show
disc that unfurls its verb on focus like Restart, Mark as Watched and Play
Version, and opens the show on the episode's season.

- HeroCtl::GoToShow, HeroSet::go_show, ELEM_GO_SHOW = 8, disc slot 4
  (MAX_CTLS 7 -> 8, DISCS 4 -> 5). It is last in the row, so every older set
  keeps its indices.
- hero::show_target(&Detail) is the one place that decides where the disc
  goes: an episode that names its show, with the season clamped to the
  Action::GoToShow convention (<= 0 is the show's own default).
- The press is the existing Action::GoToShow through the existing
  AppFx::ItemMenu -> apply_item_action -> open_detail route the bookmark disc
  already uses; no new Action, shape or request, so SCREEN_SHAPES_PIN does not
  move. A small helper shared with the bookmark arm pushes the request.
- hero::disc_icon is the one table of marks: the draw reads it and a test
  asserts no two controls of a row (and no disc and a pill) share one.
- New mark Icon::EpisodeList (three rows with leading dots,
  assets/icons/episode-list.svg) so the disc does not share Icon::Show with
  the adjacent Play Version disc. The hero and the menu row deliberately wear
  different marks for one destination, as Restart and Play from Start do.
- New key browse.detail.go_show in all nine locales (the hero's discs have
  their own keys; the description tells translators the label slides out and
  gates the row's width). The values are the shipped browse.menu.go_show
  strings; every language but English needs a native read.

Tests added: the control set and order over the power set, the elem, the
mark table, show_target, the real verb of every language, never across the
People column in the widest episode row, unfurling in all nine languages when
the row has no Also available pill, hero_set wiring, place == draw == hit
rect at rest and unfurled, and the icon asset's bounds and rasterization.
The route test from the previous commit now passes, BACK included.

Signed-off-by: Heiko Kopp <47413920+Bardioc1977@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Detail page's action-row table in docs/ux-scenario.md lists the controls
of the hero row; an episode page now ends it with the Go to Show disc.

The doc-claim audit of the branch found three sentences the change or its
neighbourhood left wrong, fixed here:
- the widest-row test's doc counted "four discs" and called a row without Go
  to Show the widest; it now says what it covers and names the episode-row
  test (renamed with it);
- the mark-table test's doc read as if the menu row wore Icon::EpisodeList;
- docs/parity-gaps.md placed the Play Version disc "after Play and the
  bookmark", which it has not been since it moved behind the watched toggle.

Signed-off-by: Heiko Kopp <47413920+Bardioc1977@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…GLinnik21#879)

The route test for the Go to Show disc mounted the episode page with its item
installed for good, so BACK found the disc focused. In the simulator it did
not: the show's page takes the store's one current item, the episode page
that BACK reveals asks its server again, and until that lands the hero is
only Play and the watch disc. DetailScreen::reconcile sent a focus held on
Go to Show to Play for the length of the load, so by the time the item
landed Play owned the focus and the restore had nothing left to seat.

A page that is returning (return_pending) and has no item yet now holds a
focus on a hero control: the control is not gone, only not here yet.
pump_restore already ends the wait when the request fails, after which
reconcile falls back to Play as before.

- the route test now models the reload (the show's item current while the
  episode page is revealed, the episode re-landing a frame later); on the
  previous commit it fails with `left: Some(0) right: Some(8)` (Play, not the
  disc), and the new unit test with `left: 0 right: 8`;
- a screen test pins the hold, the fallback to Play when the page is not
  returning, and that the held focus is valid once the item is in.

Seen in the simulator: Home -> Recently Added episode -> Go to Show -> BACK
lands on the disc with its verb unfurled.

Signed-off-by: Heiko Kopp <47413920+Bardioc1977@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant