mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 10:06:15 -08:00
feat(downloads): add focused offline detail routes
This commit is contained in:
1 parent
95cdf83aa2
commit
05ea3ad636
7 files changed
+191
-21
No files matched your search
@@ -111,6 +111,13 @@ export const routes: Routes = [
|
||||
(c) => c.GlobalSearchResultsComponent
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'downloads/:downloadId',
|
||||
loadComponent: () =>
|
||||
import('@iptvnator/portal/downloads/feature').then(
|
||||
(c) => c.DownloadOfflineDetailComponent
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'downloads',
|
||||
loadComponent: () =>
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './lib/downloads.component';
|
||||
export * from './lib/offline-detail/download-offline-detail.component';
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { PortalDetailShellComponent } from '@iptvnator/ui/components';
|
||||
|
||||
@Component({
|
||||
selector: 'app-download-offline-detail',
|
||||
imports: [PortalDetailShellComponent],
|
||||
template: '<app-portal-detail-shell [isLoading]="true" />',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DownloadOfflineDetailComponent {}
|
||||
@@ -11,6 +11,11 @@ const loadDownloadsComponent: ComponentLoader = () =>
|
||||
(c) => c.DownloadsComponent
|
||||
);
|
||||
|
||||
const loadDownloadOfflineDetailComponent: ComponentLoader = () =>
|
||||
import('@iptvnator/portal/downloads/feature').then(
|
||||
(c) => c.DownloadOfflineDetailComponent
|
||||
);
|
||||
|
||||
const loadStalkerLiveStreamLayoutComponent: ComponentLoader = () =>
|
||||
import('./stalker-live-stream-layout/stalker-live-stream-layout.component').then(
|
||||
(c) => c.StalkerLiveStreamLayoutComponent
|
||||
@@ -129,6 +134,10 @@ export function createStalkerRoutes(): Route[] {
|
||||
path: 'actor/:personId',
|
||||
loadComponent: loadStalkerActorRouteComponent,
|
||||
},
|
||||
{
|
||||
path: 'downloads/:downloadId',
|
||||
loadComponent: loadDownloadOfflineDetailComponent,
|
||||
},
|
||||
{
|
||||
path: 'downloads',
|
||||
loadComponent: loadDownloadsComponent,
|
||||
|
||||
@@ -9,6 +9,11 @@ const loadDownloadsComponent: ComponentLoader = () =>
|
||||
(c) => c.DownloadsComponent
|
||||
);
|
||||
|
||||
const loadDownloadOfflineDetailComponent: ComponentLoader = () =>
|
||||
import('@iptvnator/portal/downloads/feature').then(
|
||||
(c) => c.DownloadOfflineDetailComponent
|
||||
);
|
||||
|
||||
const loadXtreamContentGateComponent: ComponentLoader = () =>
|
||||
import('./xtream-content-gate.component').then(
|
||||
(c) => c.XtreamContentGateComponent
|
||||
@@ -83,11 +88,13 @@ export function createXtreamRoutes(): Route[] {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: loadCategoryContentViewComponent,
|
||||
loadComponent:
|
||||
loadCategoryContentViewComponent,
|
||||
},
|
||||
{
|
||||
path: ':categoryId',
|
||||
loadComponent: loadCategoryContentViewComponent,
|
||||
loadComponent:
|
||||
loadCategoryContentViewComponent,
|
||||
},
|
||||
{
|
||||
path: ':categoryId/:vodId',
|
||||
@@ -101,11 +108,13 @@ export function createXtreamRoutes(): Route[] {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: loadCategoryContentViewComponent,
|
||||
loadComponent:
|
||||
loadCategoryContentViewComponent,
|
||||
},
|
||||
{
|
||||
path: ':categoryId',
|
||||
loadComponent: loadCategoryContentViewComponent,
|
||||
loadComponent:
|
||||
loadCategoryContentViewComponent,
|
||||
},
|
||||
{
|
||||
path: ':categoryId/:serialId',
|
||||
@@ -137,6 +146,10 @@ export function createXtreamRoutes(): Route[] {
|
||||
loadComponent: loadXtreamCollectionRouteComponent,
|
||||
data: { mode: 'recent', portalType: 'xtream' },
|
||||
},
|
||||
{
|
||||
path: 'downloads/:downloadId',
|
||||
loadComponent: loadDownloadOfflineDetailComponent,
|
||||
},
|
||||
{
|
||||
path: 'downloads',
|
||||
loadComponent: loadDownloadsComponent,
|
||||
|
||||
@@ -54,6 +54,128 @@ describe('workspace-shell-route.utils', () => {
|
||||
expect(parseWorkspaceShellRoute('/workspace/downloads')).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'downloads',
|
||||
section: null,
|
||||
contextPanel: 'none',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('disables collection shell state for focused download details', () => {
|
||||
expect(
|
||||
parseWorkspaceShellRoute(
|
||||
'/workspace/downloads/42?query=matrix#technical-details'
|
||||
)
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'downloads',
|
||||
context: null,
|
||||
section: null,
|
||||
contextPanel: 'none',
|
||||
searchMode: 'none',
|
||||
usesQuerySearch: false,
|
||||
})
|
||||
);
|
||||
|
||||
expect(
|
||||
parseWorkspaceShellRoute('/workspace/xtreams/pl-1/downloads/42')
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
context: {
|
||||
provider: 'xtreams',
|
||||
playlistId: 'pl-1',
|
||||
},
|
||||
section: 'downloads',
|
||||
contextPanel: 'none',
|
||||
searchMode: 'none',
|
||||
usesQuerySearch: false,
|
||||
})
|
||||
);
|
||||
|
||||
expect(
|
||||
parseWorkspaceShellRoute('/workspace/stalker/pl-1/downloads/42')
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
context: {
|
||||
provider: 'stalker',
|
||||
playlistId: 'pl-1',
|
||||
},
|
||||
section: 'downloads',
|
||||
contextPanel: 'none',
|
||||
searchMode: 'none',
|
||||
usesQuerySearch: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps manager shell state outside exact focused download routes', () => {
|
||||
expect(parseWorkspaceShellRoute('/workspace/downloads/')).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'downloads',
|
||||
contextPanel: 'none',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
expect(
|
||||
parseWorkspaceShellRoute('/workspace/downloads/42/extra')
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'downloads',
|
||||
contextPanel: 'none',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
expect(
|
||||
parseWorkspaceShellRoute('/workspace/xtreams/pl-1/downloads')
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
section: 'downloads',
|
||||
contextPanel: 'collection',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
expect(
|
||||
parseWorkspaceShellRoute(
|
||||
'/workspace/xtreams/pl-1/downloads/42/extra'
|
||||
)
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
section: 'downloads',
|
||||
contextPanel: 'collection',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
expect(
|
||||
parseWorkspaceShellRoute('/workspace/stalker/pl-1/downloads')
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
section: 'downloads',
|
||||
contextPanel: 'collection',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
expect(
|
||||
parseWorkspaceShellRoute(
|
||||
'/workspace/stalker/pl-1/downloads/42/extra'
|
||||
)
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
section: 'downloads',
|
||||
contextPanel: 'collection',
|
||||
searchMode: 'local-filter',
|
||||
usesQuerySearch: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -103,9 +225,7 @@ describe('workspace-shell-route.utils', () => {
|
||||
});
|
||||
|
||||
it('parses Stalker portal routes and detects context-panel/query-search state', () => {
|
||||
expect(
|
||||
parseWorkspaceShellRoute('/workspace/stalker/pl-2/itv')
|
||||
).toEqual(
|
||||
expect(parseWorkspaceShellRoute('/workspace/stalker/pl-2/itv')).toEqual(
|
||||
expect.objectContaining({
|
||||
kind: 'portal',
|
||||
context: {
|
||||
|
||||
@@ -15,11 +15,7 @@ export type WorkspaceShellPageKind =
|
||||
| 'unknown';
|
||||
|
||||
export type WorkspaceShellContextPanel =
|
||||
| 'none'
|
||||
| 'sources'
|
||||
| 'settings'
|
||||
| 'category'
|
||||
| 'collection';
|
||||
'none' | 'sources' | 'settings' | 'category' | 'collection';
|
||||
|
||||
export interface WorkspacePortalContext {
|
||||
provider: PortalProvider;
|
||||
@@ -27,10 +23,7 @@ export interface WorkspacePortalContext {
|
||||
}
|
||||
|
||||
export type WorkspaceShellSearchMode =
|
||||
| 'none'
|
||||
| 'local-filter'
|
||||
| 'remote-search'
|
||||
| 'advanced-only';
|
||||
'none' | 'local-filter' | 'remote-search' | 'advanced-only';
|
||||
|
||||
export interface WorkspaceShellRoute {
|
||||
kind: WorkspaceShellPageKind;
|
||||
@@ -266,6 +259,11 @@ export function parseWorkspaceShellRoute(url: string): WorkspaceShellRoute {
|
||||
playlistId: segments[2],
|
||||
};
|
||||
const section = asPortalRailSection(sectionSegment);
|
||||
const isFocusedDownloadDetail =
|
||||
(provider === 'xtreams' || provider === 'stalker') &&
|
||||
section === 'downloads' &&
|
||||
segments.length === 5 &&
|
||||
Boolean(segments[4]);
|
||||
|
||||
return {
|
||||
kind: 'portal',
|
||||
@@ -275,9 +273,15 @@ export function parseWorkspaceShellRoute(url: string): WorkspaceShellRoute {
|
||||
section === 'favorites' &&
|
||||
(provider === 'xtreams' || provider === 'stalker') &&
|
||||
queryParams.get('scope') === 'all',
|
||||
searchMode: resolveRouteSearchMode('portal', context, section),
|
||||
usesQuerySearch: usesWorkspaceRouteQuerySearch(context, section),
|
||||
contextPanel: resolveContextPanel('portal', context, section),
|
||||
searchMode: isFocusedDownloadDetail
|
||||
? 'none'
|
||||
: resolveRouteSearchMode('portal', context, section),
|
||||
usesQuerySearch: isFocusedDownloadDetail
|
||||
? false
|
||||
: usesWorkspaceRouteQuerySearch(context, section),
|
||||
contextPanel: isFocusedDownloadDetail
|
||||
? 'none'
|
||||
: resolveContextPanel('portal', context, section),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -298,7 +302,11 @@ export function parseWorkspaceShellRoute(url: string): WorkspaceShellRoute {
|
||||
: page === 'downloads'
|
||||
? 'downloads'
|
||||
: 'unknown';
|
||||
const searchMode = resolveRouteSearchMode(kind, null, null);
|
||||
const isFocusedDownloadDetail =
|
||||
kind === 'downloads' && segments.length === 3 && Boolean(segments[2]);
|
||||
const searchMode = isFocusedDownloadDetail
|
||||
? 'none'
|
||||
: resolveRouteSearchMode(kind, null, null);
|
||||
|
||||
return {
|
||||
kind,
|
||||
@@ -308,6 +316,8 @@ export function parseWorkspaceShellRoute(url: string): WorkspaceShellRoute {
|
||||
searchMode,
|
||||
usesQuerySearch:
|
||||
searchMode === 'local-filter' || searchMode === 'remote-search',
|
||||
contextPanel: resolveContextPanel(kind, null, null),
|
||||
contextPanel: isFocusedDownloadDetail
|
||||
? 'none'
|
||||
: resolveContextPanel(kind, null, null),
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user