mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
feat(workspace): implement workspace shell and sources filters panel
- Added WorkspaceShellComponent to manage the main workspace layout and navigation. - Introduced WorkspaceSourcesFiltersPanelComponent for filtering and sorting playlists. - Created WorkspaceSourcesComponent to display playlists with search functionality. - Implemented HTML and SCSS for the new components to ensure proper styling and layout. - Updated typings to include new database method for fetching global favorites.
This commit is contained in:
1 parent
349fbcea47
commit
27bcc9d059
20 files changed
+3282
No files matched your search
@@ -0,0 +1,196 @@
|
||||
import { Component, computed, inject, input } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatIconButton } from '@angular/material/button';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { MatTooltip } from '@angular/material/tooltip';
|
||||
import { Router } from '@angular/router';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { PlaylistErrorViewComponent } from '../xtream-electron/playlist-error-view/playlist-error-view.component';
|
||||
import {
|
||||
CategoryManagementDialogComponent,
|
||||
CategoryManagementDialogData,
|
||||
} from '../xtream-electron/category-management-dialog/category-management-dialog.component';
|
||||
import { CategoryViewComponent } from '../xtream-electron/category-view/category-view.component';
|
||||
import { XtreamStore } from '../xtream-electron/stores/xtream.store';
|
||||
import { StalkerStore } from '../stalker/stalker.store';
|
||||
|
||||
type WorkspaceProvider = 'xtreams' | 'stalker' | 'playlists';
|
||||
|
||||
interface WorkspaceContextRoute {
|
||||
provider: WorkspaceProvider;
|
||||
playlistId: string;
|
||||
}
|
||||
|
||||
interface XtreamCategoryLike {
|
||||
id?: number | string;
|
||||
category_id?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-workspace-context-panel',
|
||||
imports: [
|
||||
CategoryViewComponent,
|
||||
MatIcon,
|
||||
MatIconButton,
|
||||
MatTooltip,
|
||||
NgxSkeletonLoaderModule,
|
||||
PlaylistErrorViewComponent,
|
||||
],
|
||||
templateUrl: './workspace-context-panel.component.html',
|
||||
styleUrl: './workspace-context-panel.component.scss',
|
||||
})
|
||||
export class WorkspaceContextPanelComponent {
|
||||
private readonly router = inject(Router);
|
||||
private readonly dialog = inject(MatDialog);
|
||||
private readonly xtreamStore = inject(XtreamStore);
|
||||
private readonly stalkerStore = inject(StalkerStore);
|
||||
|
||||
readonly context = input.required<WorkspaceContextRoute>();
|
||||
readonly section = input.required<string>();
|
||||
|
||||
readonly isXtreamCategories = computed(
|
||||
() =>
|
||||
this.context().provider === 'xtreams' &&
|
||||
(this.section() === 'vod' ||
|
||||
this.section() === 'series' ||
|
||||
this.section() === 'live')
|
||||
);
|
||||
readonly isStalkerCategories = computed(
|
||||
() =>
|
||||
this.context().provider === 'stalker' &&
|
||||
(this.section() === 'vod' ||
|
||||
this.section() === 'series' ||
|
||||
this.section() === 'itv')
|
||||
);
|
||||
|
||||
readonly xtreamCategories = this.xtreamStore.getCategoriesBySelectedType;
|
||||
readonly xtreamCategoryItemCounts = this.xtreamStore.getCategoryItemCounts;
|
||||
readonly xtreamSelectedCategoryId = this.xtreamStore.selectedCategoryId;
|
||||
|
||||
readonly stalkerCategories = this.stalkerStore.getCategoryResource;
|
||||
readonly stalkerSelectedCategoryId = this.stalkerStore.selectedCategoryId;
|
||||
readonly isStalkerCategoryLoading = this.stalkerStore.isCategoryResourceLoading;
|
||||
readonly isStalkerCategoryFailed = this.stalkerStore.isCategoryResourceFailed;
|
||||
|
||||
readonly title = computed(() => {
|
||||
if (this.isXtreamCategories()) {
|
||||
if (this.section() === 'vod') return 'Movie Categories';
|
||||
if (this.section() === 'series') return 'Series Categories';
|
||||
return 'Live Categories';
|
||||
}
|
||||
|
||||
if (this.isStalkerCategories()) {
|
||||
if (this.section() === 'vod') return 'Movie Categories';
|
||||
if (this.section() === 'series') return 'Series Categories';
|
||||
return 'Live Categories';
|
||||
}
|
||||
|
||||
return 'Categories';
|
||||
});
|
||||
|
||||
readonly subtitle = computed(() => {
|
||||
if (this.isXtreamCategories()) {
|
||||
return 'Xtream source';
|
||||
}
|
||||
if (this.isStalkerCategories()) {
|
||||
return 'Stalker portal';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
onXtreamCategoryClicked(category: XtreamCategoryLike): void {
|
||||
const context = this.context();
|
||||
const section = this.section();
|
||||
const rawCategoryId = category.category_id ?? category.id;
|
||||
if (rawCategoryId === undefined || rawCategoryId === null) {
|
||||
return;
|
||||
}
|
||||
const numericCategoryId = Number(rawCategoryId);
|
||||
if (Number.isNaN(numericCategoryId)) {
|
||||
return;
|
||||
}
|
||||
const categoryId = numericCategoryId;
|
||||
|
||||
this.xtreamStore.setSelectedItem(null);
|
||||
this.xtreamStore.setSelectedCategory(categoryId);
|
||||
|
||||
if (section === 'live') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigate([
|
||||
'/workspace',
|
||||
'xtreams',
|
||||
context.playlistId,
|
||||
section,
|
||||
categoryId,
|
||||
]);
|
||||
}
|
||||
|
||||
onStalkerCategoryClicked(item: { category_id?: string | number }): void {
|
||||
const context = this.context();
|
||||
const section = this.section();
|
||||
const categoryId = String(item.category_id ?? '*');
|
||||
|
||||
this.stalkerStore.setSelectedCategory(categoryId);
|
||||
this.stalkerStore.setPage(0);
|
||||
this.stalkerStore.clearSelectedItem();
|
||||
|
||||
if (section === 'itv') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (categoryId === '*') {
|
||||
this.router.navigate([
|
||||
'/workspace',
|
||||
'stalker',
|
||||
context.playlistId,
|
||||
section,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.navigate([
|
||||
'/workspace',
|
||||
'stalker',
|
||||
context.playlistId,
|
||||
section,
|
||||
categoryId,
|
||||
]);
|
||||
}
|
||||
|
||||
openXtreamCategoryManagement(): void {
|
||||
const context = this.context();
|
||||
const section = this.section();
|
||||
if (!this.isXtreamCategories()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentType =
|
||||
section === 'series'
|
||||
? 'series'
|
||||
: section === 'live'
|
||||
? 'live'
|
||||
: 'vod';
|
||||
|
||||
const dialogRef = this.dialog.open<
|
||||
CategoryManagementDialogComponent,
|
||||
CategoryManagementDialogData,
|
||||
boolean
|
||||
>(CategoryManagementDialogComponent, {
|
||||
data: {
|
||||
playlistId: context.playlistId,
|
||||
contentType,
|
||||
itemCounts: this.xtreamCategoryItemCounts(),
|
||||
},
|
||||
width: '500px',
|
||||
maxHeight: '80vh',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result) => {
|
||||
if (result) {
|
||||
this.xtreamStore.reloadCategories();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user