mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 17:36:15 -08:00
fix(xtream): keep live playback on category switch (#936)
This commit is contained in:
1 parent
db08ec2958
commit
2a5b1d1da7
4 files changed
+114
-3
No files matched your search
@@ -525,6 +525,14 @@ test.describe('Electron Workspace Search', () => {
|
||||
app.mainWindow,
|
||||
`Live TV / ${sample.categoryName}`
|
||||
);
|
||||
await expect(
|
||||
app.mainWindow.locator(
|
||||
'app-live-stream-layout .content-container .video-player'
|
||||
)
|
||||
).toBeVisible({ timeout: 20000 });
|
||||
await expect(
|
||||
channelItemByTitle(app.mainWindow, sample.targetTitle).first()
|
||||
).toHaveClass(/(^|\s)active(\s|$)/);
|
||||
await fillWorkspaceSearch(app.mainWindow, sample.targetTitle);
|
||||
|
||||
await expectPathname(
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
import type { ActivatedRouteSnapshot } from '@angular/router';
|
||||
|
||||
export function hasActiveLiveCategoryRoute(
|
||||
route: ActivatedRouteSnapshot
|
||||
): boolean {
|
||||
if (
|
||||
route.routeConfig?.path === 'live/:categoryId' &&
|
||||
route.paramMap.has('categoryId')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return route.children.some((child) => hasActiveLiveCategoryRoute(child));
|
||||
}
|
||||
+70
@@ -21,6 +21,27 @@ const translations: Record<string, string> = {
|
||||
'Fetching playlist data from source...',
|
||||
};
|
||||
|
||||
interface RouteSnapshotStub {
|
||||
routeConfig: { path: string } | null;
|
||||
paramMap: { has: (param: string) => boolean };
|
||||
children: RouteSnapshotStub[];
|
||||
}
|
||||
|
||||
function createRouteSnapshot(
|
||||
path: string | null,
|
||||
hasCategoryId = false,
|
||||
children: RouteSnapshotStub[] = []
|
||||
): RouteSnapshotStub {
|
||||
return {
|
||||
routeConfig: path ? { path } : null,
|
||||
paramMap: {
|
||||
has: (param: string) =>
|
||||
hasCategoryId && param === 'categoryId',
|
||||
},
|
||||
children,
|
||||
};
|
||||
}
|
||||
|
||||
describe('WorkspaceContextPanelComponent', () => {
|
||||
let fixture: ComponentFixture<WorkspaceContextPanelComponent>;
|
||||
const xtreamCategories = signal([
|
||||
@@ -65,6 +86,11 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
clearSelectedItem: jest.fn(),
|
||||
};
|
||||
const router = {
|
||||
routerState: {
|
||||
snapshot: {
|
||||
root: createRouteSnapshot(null),
|
||||
},
|
||||
},
|
||||
navigate: jest.fn(),
|
||||
};
|
||||
const dialog = {
|
||||
@@ -90,6 +116,9 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
stalkerStore.setSelectedCategory.mockClear();
|
||||
stalkerStore.setPage.mockClear();
|
||||
stalkerStore.clearSelectedItem.mockClear();
|
||||
router.routerState.snapshot.root = createRouteSnapshot(null, false, [
|
||||
createRouteSnapshot('live'),
|
||||
]);
|
||||
router.navigate.mockClear();
|
||||
dialog.open.mockClear();
|
||||
|
||||
@@ -226,6 +255,47 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves the active xtream live item when switching live categories', () => {
|
||||
fixture.componentRef.setInput('section', 'live');
|
||||
xtreamSelectedTypeContentState.set('ready');
|
||||
fixture.detectChanges();
|
||||
|
||||
const categoryButtons = Array.from(
|
||||
fixture.nativeElement.querySelectorAll('.category-item')
|
||||
) as HTMLButtonElement[];
|
||||
|
||||
categoryButtons[1]?.click();
|
||||
|
||||
expect(xtreamStore.setSelectedCategory).toHaveBeenCalledWith(2);
|
||||
expect(xtreamStore.setSelectedItem).not.toHaveBeenCalled();
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('updates the live category URL without clearing playback when already deep linked', () => {
|
||||
fixture.componentRef.setInput('section', 'live');
|
||||
router.routerState.snapshot.root = createRouteSnapshot(null, false, [
|
||||
createRouteSnapshot('live/:categoryId', true),
|
||||
]);
|
||||
xtreamSelectedTypeContentState.set('ready');
|
||||
fixture.detectChanges();
|
||||
|
||||
const categoryButtons = Array.from(
|
||||
fixture.nativeElement.querySelectorAll('.category-item')
|
||||
) as HTMLButtonElement[];
|
||||
|
||||
categoryButtons[1]?.click();
|
||||
|
||||
expect(xtreamStore.setSelectedCategory).toHaveBeenCalledWith(2);
|
||||
expect(xtreamStore.setSelectedItem).not.toHaveBeenCalled();
|
||||
expect(router.navigate).toHaveBeenCalledWith(
|
||||
['/workspace', 'xtreams', 'playlist-1', 'live', 2],
|
||||
{
|
||||
queryParamsHandling: 'preserve',
|
||||
replaceUrl: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('labels Stalker radio categories and keeps category selection in the radio layout', () => {
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'stalker',
|
||||
|
||||
+22
-3
@@ -20,6 +20,7 @@ import { StalkerStore } from '@iptvnator/portal/stalker/data-access';
|
||||
import { XtreamStore } from '@iptvnator/portal/xtream/data-access';
|
||||
import { WorkspaceContextCategoryViewComponent } from './components/workspace-context-category-view.component';
|
||||
import { WorkspaceContextErrorViewComponent } from './components/workspace-context-error-view.component';
|
||||
import { hasActiveLiveCategoryRoute } from './workspace-context-panel-route.utils';
|
||||
|
||||
type WorkspaceProvider = 'xtreams' | 'stalker' | 'playlists';
|
||||
|
||||
@@ -297,13 +298,31 @@ export class WorkspaceContextPanelComponent {
|
||||
}
|
||||
const categoryId = numericCategoryId;
|
||||
|
||||
this.xtreamStore.setSelectedItem(null);
|
||||
this.xtreamStore.setSelectedCategory(categoryId);
|
||||
|
||||
if (section === 'live') {
|
||||
this.xtreamStore.setSelectedCategory(categoryId);
|
||||
const liveRouteHasCategory = hasActiveLiveCategoryRoute(
|
||||
this.router.routerState.snapshot.root
|
||||
);
|
||||
if (liveRouteHasCategory) {
|
||||
void this.router.navigate(
|
||||
[
|
||||
'/workspace',
|
||||
'xtreams',
|
||||
context.playlistId,
|
||||
'live',
|
||||
categoryId,
|
||||
],
|
||||
{
|
||||
queryParamsHandling: 'preserve',
|
||||
replaceUrl: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.xtreamStore.setSelectedItem(null);
|
||||
this.xtreamStore.setSelectedCategory(categoryId);
|
||||
this.router.navigate([
|
||||
'/workspace',
|
||||
'xtreams',
|
||||
|
||||
Reference in new issue
Block a user