mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
184 lines
7.0 KiB
TypeScript
184 lines
7.0 KiB
TypeScript
import { Component, computed, inject, OnInit } from '@angular/core';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { MatIconButton } from '@angular/material/button';
|
|
import { MatDialog } from '@angular/material/dialog';
|
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
import { MatIcon } from '@angular/material/icon';
|
|
import { MatInputModule } from '@angular/material/input';
|
|
import { MatMenuModule } from '@angular/material/menu';
|
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
|
|
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
|
import { PlaylistSwitcherComponent, ResizableDirective } from 'components';
|
|
import { XtreamCategory } from 'shared-interfaces';
|
|
import {
|
|
CategoryManagementDialogComponent,
|
|
CategoryManagementDialogData,
|
|
} from './category-management-dialog/category-management-dialog.component';
|
|
import { CategoryViewComponent } from './category-view/category-view.component';
|
|
import { XtreamStore } from './stores/xtream.store';
|
|
import { XtreamCategorySortMode } from './stores/features/with-selection.feature';
|
|
|
|
const XTREAM_CATEGORY_SORT_STORAGE_KEY = 'xtream-category-sort-mode';
|
|
|
|
@Component({
|
|
selector: 'app-xtream-main-container',
|
|
templateUrl: './xtream-main-container.component.html',
|
|
styleUrls: ['./xtream-main-container.component.scss', './sidebar.scss'],
|
|
imports: [
|
|
CategoryViewComponent,
|
|
FormsModule,
|
|
MatFormFieldModule,
|
|
MatIcon,
|
|
MatIconButton,
|
|
MatInputModule,
|
|
MatMenuModule,
|
|
MatTooltipModule,
|
|
PlaylistSwitcherComponent,
|
|
ResizableDirective,
|
|
RouterOutlet,
|
|
TranslateModule,
|
|
],
|
|
})
|
|
export class XtreamMainContainerComponent implements OnInit {
|
|
readonly router = inject(Router);
|
|
readonly route = inject(ActivatedRoute);
|
|
readonly translateService = inject(TranslateService);
|
|
readonly xtreamStore = inject(XtreamStore);
|
|
private readonly dialog = inject(MatDialog);
|
|
|
|
readonly categories = this.xtreamStore.getCategoriesBySelectedType;
|
|
readonly categoryItemCounts = this.xtreamStore.getCategoryItemCounts;
|
|
readonly currentPlaylist = this.xtreamStore.currentPlaylist;
|
|
readonly selectedCategoryId = this.xtreamStore.selectedCategoryId;
|
|
readonly contentSortMode = this.xtreamStore.contentSortMode;
|
|
readonly categorySearchTerm = this.xtreamStore.categorySearchTerm;
|
|
readonly canShowSortMenu = computed(() => {
|
|
const hasCategorySelected = this.selectedCategoryId() != null;
|
|
const type = this.xtreamStore.selectedContentType();
|
|
return hasCategorySelected && (type === 'vod' || type === 'series');
|
|
});
|
|
readonly contentSortLabel = computed(() => {
|
|
const mode = this.contentSortMode();
|
|
if (mode === 'date-asc') return 'Date Added (Oldest First)';
|
|
if (mode === 'name-asc') return 'Name A-Z';
|
|
if (mode === 'name-desc') return 'Name Z-A';
|
|
return 'Date Added (Latest First)';
|
|
});
|
|
|
|
ngOnInit(): void {
|
|
const savedSortMode = localStorage.getItem(XTREAM_CATEGORY_SORT_STORAGE_KEY);
|
|
if (
|
|
savedSortMode === 'date-desc' ||
|
|
savedSortMode === 'date-asc' ||
|
|
savedSortMode === 'name-asc' ||
|
|
savedSortMode === 'name-desc'
|
|
) {
|
|
this.xtreamStore.setContentSortMode(savedSortMode);
|
|
}
|
|
|
|
const { categoryId } = this.route.snapshot.params;
|
|
if (categoryId)
|
|
this.xtreamStore.setSelectedCategory(Number(categoryId));
|
|
}
|
|
|
|
categoryClicked(category: XtreamCategory) {
|
|
const categoryId = (category as any).category_id ?? category.id;
|
|
|
|
// Clear any selected item when switching categories
|
|
this.xtreamStore.setSelectedItem(null);
|
|
|
|
this.xtreamStore.setSelectedCategory(Number(categoryId));
|
|
|
|
this.router.navigate([categoryId], {
|
|
relativeTo: this.route,
|
|
});
|
|
}
|
|
|
|
getContentLabel(): string {
|
|
const selectedCategoryId = this.xtreamStore.selectedCategoryId();
|
|
|
|
// When no category is selected, show "Recently Added"
|
|
if (selectedCategoryId === null || selectedCategoryId === undefined) {
|
|
const recentlyAddedLabel = this.translateService.instant('PORTALS.SIDEBAR.RECENTLY_ADDED');
|
|
|
|
// Show page number when viewing recently added (not detail view)
|
|
if (
|
|
!this.xtreamStore.selectedItem() &&
|
|
this.xtreamStore.getTotalPages() > 1
|
|
) {
|
|
const currentPage = this.xtreamStore.page() + 1;
|
|
const totalPages = this.xtreamStore.getTotalPages();
|
|
const pageLabel = this.translateService.instant('PORTALS.PAGE');
|
|
return `${recentlyAddedLabel} (${pageLabel} ${currentPage}/${totalPages})`;
|
|
}
|
|
|
|
return recentlyAddedLabel;
|
|
}
|
|
|
|
const selectedCategory = this.xtreamStore.getSelectedCategory();
|
|
const categoryName = selectedCategory
|
|
? (selectedCategory as any).name
|
|
: 'Category Content';
|
|
|
|
// Show page number when viewing category content (not detail view)
|
|
if (
|
|
!this.xtreamStore.selectedItem() &&
|
|
this.xtreamStore.getTotalPages() > 1
|
|
) {
|
|
const currentPage = this.xtreamStore.page() + 1; // +1 because page is 0-indexed
|
|
const totalPages = this.xtreamStore.getTotalPages();
|
|
const pageLabel = this.translateService.instant('PORTALS.PAGE');
|
|
return `${categoryName} (${pageLabel} ${currentPage}/${totalPages})`;
|
|
}
|
|
|
|
return categoryName;
|
|
}
|
|
|
|
historyBack() {
|
|
this.router.navigate(['.', this.xtreamStore.selectedCategoryId()], {
|
|
relativeTo: this.route,
|
|
});
|
|
}
|
|
|
|
openCategoryManagement(): void {
|
|
// The playlist id is in the parent route (xtreams/:id)
|
|
const playlistId = this.route.parent?.snapshot.params['id'];
|
|
const contentType = this.xtreamStore.selectedContentType();
|
|
|
|
const dialogRef = this.dialog.open<
|
|
CategoryManagementDialogComponent,
|
|
CategoryManagementDialogData,
|
|
boolean
|
|
>(CategoryManagementDialogComponent, {
|
|
data: {
|
|
playlistId,
|
|
contentType,
|
|
itemCounts: this.categoryItemCounts(),
|
|
},
|
|
width: '500px',
|
|
maxHeight: '80vh',
|
|
});
|
|
|
|
dialogRef.afterClosed().subscribe((result) => {
|
|
if (result) {
|
|
// Reload categories from database to reflect visibility changes
|
|
this.xtreamStore.reloadCategories();
|
|
}
|
|
});
|
|
}
|
|
|
|
setContentSortMode(mode: XtreamCategorySortMode): void {
|
|
this.xtreamStore.setContentSortMode(mode);
|
|
localStorage.setItem(XTREAM_CATEGORY_SORT_STORAGE_KEY, mode);
|
|
}
|
|
|
|
onCategorySearchChange(term: string): void {
|
|
this.xtreamStore.setCategorySearchTerm(term);
|
|
}
|
|
|
|
clearCategorySearch(): void {
|
|
this.xtreamStore.setCategorySearchTerm('');
|
|
}
|
|
}
|