mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 12:06:16 -08:00
fix(stalker): keep live playback when switching the ITV/radio category (#1517)
Switching the Live TV or radio category in the shell context panel tore down the Stalker player: `onStalkerCategoryClicked` cleared the selected item for every section, and the live layout gates its player on `selectedItem`. Xtream live (#936) and M3U groups already keep the channel playing across a category/group switch. - Context panel: return before `clearSelectedItem()` for `itv`/`radio`; VOD/series clicks still drop the open detail before navigating. - Live layout: the category-change reset effect no longer wipes the playing channel's short-EPG fallback or cancels a fallback load in flight; only a section change (itv <-> radio) does that now. - Regression coverage in the context panel spec, the live layout spec and a new web E2E scenario; docs and a `.changes/` note added. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
308ed9cb41
commit
2fc1bd5601
9 files changed
+258
-3
No files matched your search
+64
-2
@@ -534,7 +534,7 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('labels Stalker radio categories and keeps category selection in the radio layout', () => {
|
||||
it('labels Stalker radio categories and keeps the playing station on a category click', () => {
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'stalker',
|
||||
playlistId: 'stalker-1',
|
||||
@@ -558,10 +558,72 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
|
||||
expect(stalkerStore.setSelectedCategory).toHaveBeenCalledWith('*');
|
||||
expect(stalkerStore.setPage).toHaveBeenCalledWith(0);
|
||||
expect(stalkerStore.clearSelectedItem).toHaveBeenCalled();
|
||||
// The radio layout renders its audio player only while the store has
|
||||
// a selected item — clearing it here would silence the station.
|
||||
expect(stalkerStore.clearSelectedItem).not.toHaveBeenCalled();
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('preserves the playing Stalker ITV channel when switching live categories', () => {
|
||||
// Regression: the click handler used to clearSelectedItem() for every
|
||||
// Stalker section. The live layout gates its player on selectedItem,
|
||||
// so a category switch in the sidebar stopped a channel the user never
|
||||
// switched away from — unlike Xtream live (#936) and M3U groups.
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'stalker',
|
||||
playlistId: 'stalker-1',
|
||||
});
|
||||
fixture.componentRef.setInput('section', 'itv');
|
||||
stalkerStore.getCategoryResource.set([
|
||||
{ category_id: '*', category_name: 'All channels' },
|
||||
{ category_id: '7', category_name: 'Sports' },
|
||||
]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const categoryButtons = Array.from(
|
||||
fixture.nativeElement.querySelectorAll('.category-item')
|
||||
) as HTMLButtonElement[];
|
||||
|
||||
categoryButtons[1]?.click();
|
||||
|
||||
expect(stalkerStore.setSelectedCategory).toHaveBeenCalledWith('7');
|
||||
expect(stalkerStore.setPage).toHaveBeenCalledWith(0);
|
||||
expect(stalkerStore.clearSelectedItem).not.toHaveBeenCalled();
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('still closes the open Stalker detail when switching VOD categories', () => {
|
||||
// VOD/series category clicks navigate to a list route, so the open
|
||||
// detail must be dropped there — the live exemption is deliberate and
|
||||
// narrow.
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'stalker',
|
||||
playlistId: 'stalker-1',
|
||||
});
|
||||
fixture.componentRef.setInput('section', 'vod');
|
||||
stalkerStore.getCategoryResource.set([
|
||||
{ category_id: '*', category_name: 'All movies' },
|
||||
{ category_id: '7', category_name: 'Action' },
|
||||
]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const categoryButtons = Array.from(
|
||||
fixture.nativeElement.querySelectorAll('.category-item')
|
||||
) as HTMLButtonElement[];
|
||||
|
||||
categoryButtons[1]?.click();
|
||||
|
||||
expect(stalkerStore.setSelectedCategory).toHaveBeenCalledWith('7');
|
||||
expect(stalkerStore.clearSelectedItem).toHaveBeenCalled();
|
||||
expect(router.navigate).toHaveBeenCalledWith([
|
||||
'/workspace',
|
||||
'stalker',
|
||||
'stalker-1',
|
||||
'vod',
|
||||
'7',
|
||||
]);
|
||||
});
|
||||
|
||||
describe('Stalker category error description', () => {
|
||||
afterEach(() => {
|
||||
stalkerStore.isCategoryResourceFailed.set(false as never);
|
||||
|
||||
+7
-1
@@ -458,12 +458,18 @@ export class WorkspaceContextPanelComponent {
|
||||
this.contextDrawer?.close();
|
||||
this.stalkerStore.setSelectedCategory(categoryId);
|
||||
this.stalkerStore.setPage(0);
|
||||
this.stalkerStore.clearSelectedItem();
|
||||
|
||||
if (section === 'itv' || section === 'radio') {
|
||||
// Live TV / radio: the category only re-filters the channel
|
||||
// sidebar, the selected channel keeps playing (Xtream parity,
|
||||
// #936). The live layout gates its player on `selectedItem`, so
|
||||
// clearing it here would tear the player down for a channel the
|
||||
// user never switched away from.
|
||||
return;
|
||||
}
|
||||
|
||||
this.stalkerStore.clearSelectedItem();
|
||||
|
||||
if (categoryId === '*') {
|
||||
this.router.navigate([
|
||||
'/workspace',
|
||||
|
||||
Reference in new issue
Block a user