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
@@ -134,9 +134,7 @@ test.describe('portrait phone 375x812', () => {
|
||||
// sections; now the list scrolls and ends above the footer.
|
||||
const listBox = await boxOf(panel.locator('.settings-sections-list'));
|
||||
const footerBox = await boxOf(footer);
|
||||
expect(listBox.y + listBox.height).toBeLessThanOrEqual(
|
||||
footerBox.y + 1
|
||||
);
|
||||
expect(listBox.y + listBox.height).toBeLessThanOrEqual(footerBox.y + 1);
|
||||
|
||||
// Tapping the backdrop (right of the drawer) closes it.
|
||||
await page
|
||||
@@ -216,7 +214,16 @@ test.describe('xtream portal routes on a phone', () => {
|
||||
const sidebar = page.locator('app-live-stream-layout .sidebar');
|
||||
await expect(sidebar).toBeVisible();
|
||||
|
||||
// The workspace header carries the live rail toggle at desktop
|
||||
// width only; on the phone the rail is a bottom drawer with its own
|
||||
// toggle and the header has no room for another permanent icon.
|
||||
const headerRailToggle = page.locator(
|
||||
'app-workspace-shell-header .header-sidebar-toggle'
|
||||
);
|
||||
await expect(headerRailToggle).toBeVisible();
|
||||
|
||||
await page.setViewportSize(LANDSCAPE_PHONE);
|
||||
await expect(headerRailToggle).toBeHidden();
|
||||
|
||||
// The sidebar stacks at full width above the player.
|
||||
await expect
|
||||
|
||||
@@ -513,13 +513,22 @@ test('@stalker radio — stations use the inline audio player without EPG', asyn
|
||||
timeout: 20_000,
|
||||
});
|
||||
|
||||
await page.getByRole('button', { name: 'Hide channels list' }).click();
|
||||
const restoreButton = page.getByRole('button', {
|
||||
name: 'Show channels list',
|
||||
});
|
||||
// The rail's own chevron hides the list; the workspace header carries a
|
||||
// second toggle with the same accessible name, so scope to the rail.
|
||||
await page
|
||||
.locator('.sidebar')
|
||||
.getByRole('button', { name: 'Hide channels list' })
|
||||
.click();
|
||||
const restoreButton = page.locator('.sidebar-restore');
|
||||
await expect(restoreButton).toBeVisible();
|
||||
await expect(
|
||||
page.locator('app-workspace-shell-header .header-sidebar-toggle')
|
||||
).toHaveAttribute('aria-pressed', 'false');
|
||||
await restoreButton.click();
|
||||
await expect(stations.first()).toBeVisible();
|
||||
await expect(
|
||||
page.locator('app-workspace-shell-header .header-sidebar-toggle')
|
||||
).toHaveAttribute('aria-pressed', 'true');
|
||||
|
||||
await expect(page.locator('app-epg-timeline')).toHaveCount(0);
|
||||
expect(epgRequests).toHaveLength(0);
|
||||
|
||||
Reference in new issue
Block a user