mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
fix(live-tv): keep a hidden channel list discoverable and scoped per surface (#1555)
* fix(live-tv): keep a hidden channel list discoverable and scoped per surface The second report in #1458 ("all channels disappear after clearing the playback history, reset does not bring them back") was not data loss: the history write never touches playlist items. The reporter's screenshot shows a collapsed channel rail, a state persisted under one localStorage key shared by the M3U player, the Xtream/Stalker live layouts and the favorites/recent live tab. It survived restart, "Remove all playlists" and re-import, and the only way back was a 32px chevron or Ctrl/Cmd+B. - LiveLayoutSidebarStateService keeps the state per surface (m3u / portal / collection) under live-sidebar-state:<surface>; the M3U player now goes through the service instead of its own signal. The legacy shared key is forgotten on startup and never read, so the update itself restores the list for everyone who got stuck. - The workspace header renders a view_sidebar toggle on every route that renders its own rail (M3U all/groups, Xtream live, Stalker itv/radio), so the control exists in both states instead of disappearing with the rail. Collection pages keep their own toggle beside the content switch. - While the rail is collapsed and nothing plays, every live host shows app-channel-list-hidden-state (title, shortcut hint, full-size "Show channels list" button) instead of asking to pick from a list that is not on screen. app-portal-empty-state gained optional hint/action inputs. - New LAYOUT.CHANNELS_LIST_HIDDEN(_HINT) strings in en plus 18 locales. Tests: service, empty-state, hidden-state and header component specs, a separate video-player-sidebar spec (the main M3U spec sits at the test line budget), and an Electron E2E covering history clearing, restore via button/header/shortcut across restart and re-import, per-surface scoping against an Xtream portal, and legacy-key cleanup. Refs #1458 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(live-tv): mirror the EPG offset setting in the sidebar spec mock Master's player reads `resolvedEpgOffsetMinutes` from the settings store; the new sidebar spec was cloned from the movie-gate harness before that field landed, so its playing-channel case threw inside the EPG effect. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(web-e2e): scope the Stalker radio rail toggles to the rail The workspace header now carries a second "Hide/Show channels list" toggle, so the role+name locators matched more than one button and tripped Playwright's strict mode. Target the rail's own chevron and the floating restore button, and assert the header toggle mirrors the state. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(live-tv): honour Cmd/Ctrl+B on collection pages and hide the header rail toggle on phones Codex review follow-ups on #1555: - The hidden-list state advertises Cmd/Ctrl+B, but the favorites/recent collection page had no handler; only the routed M3U/Xtream/Stalker live layouts did. The page now toggles the collection surface while its live tab is on screen, with the same typing/inert guards as the other hosts. - At the phone breakpoint the header already holds the drawer toggle, switcher, search and Add; the live rail is a bottom drawer with its own toggle there, so the header rail toggle is hidden below 640px. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(live-tv): migrate the live navigation helpers to the per-surface sidebar API master (#1554) added `XtreamLiveChannelNavigationService` and `stalker-live-navigation.ts`, which expand the rail through `sidebar.setState('expanded')` on the pre-split signature. Point them at the `portal` surface and update their specs; drop the now-unused hidden-state stub from the Xtream layout spec, which master pushed to the max-lines budget. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
436825bdec
commit
0dcfba7045
67 files changed
+1687
-130
No files matched your search
@@ -267,8 +267,8 @@ remain local when the meaning is explicit.
|
||||
|
||||
### Collapsible Live Sidebar
|
||||
|
||||
- M3U, Xtream, and Stalker live layouts share a single sidebar collapse toggle
|
||||
that hides the channels rail to give the player and EPG full width.
|
||||
- M3U, Xtream, and Stalker live layouts share a sidebar collapse toggle that
|
||||
hides the channels rail to give the player and EPG full width.
|
||||
- Xtream Live TV's root view (`/live` with no selected category) follows the
|
||||
same paginated `All Items` shell as VOD and Series: a widget header with the
|
||||
total channel count, page-size controls, and page navigation above the shared
|
||||
@@ -285,15 +285,41 @@ remain local when the meaning is explicit.
|
||||
is `live` (Xtream) or `itv`/`radio` (Stalker); movies, series, favorites,
|
||||
and recent routes leave it untouched.
|
||||
- Collapsed state is owned by `LiveLayoutSidebarStateService`
|
||||
(`providedIn: 'root'`) in `@iptvnator/portal/shared/util`. Every surface that
|
||||
participates injects the service and reads `isCollapsed`; any toggle calls
|
||||
`service.toggle()`. Persistence delegates to the existing
|
||||
`live-sidebar-state` helpers, so the localStorage key stays unchanged and
|
||||
missing/invalid values restore to expanded.
|
||||
- A `mat-icon-button` with `chevron_left` lives in the sidebar header and
|
||||
toggles state. While collapsed, a floating `chevron_right` mini-fab appears
|
||||
at the left edge of `.content-container` to restore the rail (and the
|
||||
categories rail, in Xtream/Stalker live).
|
||||
(`providedIn: 'root'`) in `@iptvnator/portal/shared/util` and kept **per
|
||||
surface** (`LiveSidebarSurface`): `m3u` (the M3U player), `portal` (Xtream
|
||||
and Stalker live layouts plus the shell categories rail) and `collection`
|
||||
(the unified favorites/recent live tab). Every participant injects the
|
||||
service, holds `isCollapsedFor(surface)` (a stable signal) and calls
|
||||
`toggle(surface)`; nothing reads localStorage directly. Persistence lives
|
||||
under `live-sidebar-state:<surface>`. Hiding the list is a per-context
|
||||
choice: it must not follow the user from a portal to an M3U playlist, nor
|
||||
from the desktop rail to the phone bottom drawer of another surface. The
|
||||
pre-split shared key `live-sidebar-state` is forgotten on service
|
||||
construction and never read — a stored `collapsed` there hid every channel
|
||||
list in the app behind a 32px chevron and survived restart, "Remove all
|
||||
playlists" and re-import (issue #1458).
|
||||
- The control never moves. Inside the rail a `mat-icon-button` with
|
||||
`chevron_left` hides it; while collapsed a floating `chevron_right` mini-fab
|
||||
sits at the left edge of `.content-container`. Because both of those live
|
||||
in the thing they hide, the workspace header additionally renders
|
||||
`view_sidebar` (`headerSidebarToggle`, `WorkspaceShellHeaderService`) on
|
||||
every route that renders its own rail — M3U `all`/`groups`, Xtream `live`,
|
||||
Stalker `itv`/`radio` (`resolveRouteLiveSidebarSurface`). It stays in place
|
||||
in both states, uses `aria-pressed` (pressed = rail visible) and tints
|
||||
primary only while the rail is hidden, since the hidden state is the
|
||||
exception that deserves the cue. Collection pages are deliberately excluded:
|
||||
only the page knows whether its live tab, and therefore the rail, is on
|
||||
screen, so its own header toggle beside the content switch stays the owner.
|
||||
At the phone breakpoint (≤640px) the header toggle is hidden: the rail is a
|
||||
bottom drawer there with its own toggle and the header has no spare width.
|
||||
- While the rail is collapsed and nothing is playing, every live host renders
|
||||
`app-channel-list-hidden-state` (`@iptvnator/portal/shared/ui`) instead of
|
||||
the "select a channel" empty state: a title that says the list is hidden, a
|
||||
one-line hint naming the shortcut, and a full-size "Show channels list"
|
||||
stroked button wired to the same toggle. The generic
|
||||
`app-portal-empty-state` grew optional `hint`, `actionLabel`, `actionIcon`
|
||||
inputs and an `action` output for this; the action keeps full opacity while
|
||||
icon and copy stay muted, because it is the way out of the state.
|
||||
- Keyboard shortcut: `Cmd/Ctrl+B`. The handler ignores events that originate
|
||||
inside `<input>`, `<textarea>`, `<select>`, or content-editable elements via
|
||||
the shared `isTypingInInput` helper.
|
||||
|
||||
Reference in new issue
Block a user