mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
feat: improve global favorites handling and channel display logic in the UI
This commit is contained in:
1 parent
c253db4cef
commit
edcd7cb148
5 files changed
+38
-18
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import { Component, input, output } from '@angular/core';
|
||||
import { MatIconButton } from '@angular/material/button';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { PlaylistSwitcherComponent, ResizableDirective } from 'components';
|
||||
@@ -16,6 +17,7 @@ import { ContentCardComponent } from '../content-card/content-card.component';
|
||||
CategoryViewComponent,
|
||||
ContentCardComponent,
|
||||
MatIcon,
|
||||
MatIconButton,
|
||||
PlaylistSwitcherComponent,
|
||||
ResizableDirective,
|
||||
TranslatePipe,
|
||||
|
||||
@@ -57,6 +57,10 @@ export class PlaylistEffects {
|
||||
this.store.select(selectFavorites),
|
||||
this.store.select(selectActivePlaylistId)
|
||||
),
|
||||
filter(
|
||||
([, , playlistId]) =>
|
||||
playlistId !== GLOBAL_FAVORITES_PLAYLIST_ID
|
||||
),
|
||||
switchMap(([, favorites, playlistId]) =>
|
||||
this.playlistsService.updateFavorites(playlistId, favorites)
|
||||
),
|
||||
|
||||
@@ -44,6 +44,7 @@ export function createFavoritesPlaylist(
|
||||
playlist: {
|
||||
items: channels,
|
||||
},
|
||||
favorites: channels.map((channel) => channel.url),
|
||||
filename: 'Global favorites',
|
||||
};
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
@if (_channelList) {
|
||||
@if (displayedChannels().length) {
|
||||
<mat-tab-group color="primary" backgroundColor="primary">
|
||||
<!-- All Channels Tab -->
|
||||
<mat-tab>
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
<app-all-channels-tab
|
||||
[channels]="_channelList"
|
||||
[channels]="displayedChannels()"
|
||||
[channelEpgMap]="channelEpgMap()"
|
||||
[progressTick]="progressTick()"
|
||||
[shouldShowEpg]="shouldShowEpg()"
|
||||
@@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
<app-groups-tab
|
||||
[groupedChannels]="groupedChannels"
|
||||
[groupedChannels]="groupedChannels()"
|
||||
[channelEpgMap]="channelEpgMap()"
|
||||
[progressTick]="progressTick()"
|
||||
[shouldShowEpg]="shouldShowEpg()"
|
||||
|
||||
+28
-15
@@ -10,11 +10,10 @@ import {
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { StorageMap } from '@ngx-pwa/local-storage';
|
||||
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import * as _ from 'lodash';
|
||||
import {
|
||||
ChannelActions,
|
||||
@@ -25,7 +24,13 @@ import {
|
||||
} from 'm3u-state';
|
||||
import { BehaviorSubject, combineLatest, map, skipWhile } from 'rxjs';
|
||||
import { EpgService } from 'services';
|
||||
import { Channel, EpgProgram, Settings, STORE_KEY } from 'shared-interfaces';
|
||||
import {
|
||||
Channel,
|
||||
EpgProgram,
|
||||
GLOBAL_FAVORITES_PLAYLIST_ID,
|
||||
Settings,
|
||||
STORE_KEY,
|
||||
} from 'shared-interfaces';
|
||||
import { AllChannelsTabComponent } from './all-channels-tab/all-channels-tab.component';
|
||||
import { FavoritesTabComponent } from './favorites-tab/favorites-tab.component';
|
||||
import { GroupsTabComponent } from './groups-tab/groups-tab.component';
|
||||
@@ -47,10 +52,8 @@ import { GroupsTabComponent } from './groups-tab/groups-tab.component';
|
||||
})
|
||||
export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
private readonly epgService = inject(EpgService);
|
||||
private readonly snackBar = inject(MatSnackBar);
|
||||
private readonly storage = inject(StorageMap);
|
||||
private readonly store = inject(Store);
|
||||
private readonly translateService = inject(TranslateService);
|
||||
|
||||
/** Map of channel ID to current EPG program */
|
||||
readonly channelEpgMap = signal(new Map<string, EpgProgram | null>());
|
||||
@@ -72,6 +75,7 @@ export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
|
||||
/** Channels array */
|
||||
_channelList: Channel[] = [];
|
||||
private readonly channelListSignal = signal<Channel[]>([]);
|
||||
private channelList$ = new BehaviorSubject<Channel[]>([]);
|
||||
|
||||
get channelList(): Channel[] {
|
||||
@@ -81,13 +85,28 @@ export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
set channelList(value: Channel[]) {
|
||||
this._channelList = value;
|
||||
this.channelListSignal.set(value);
|
||||
this.channelList$.next(value);
|
||||
this.groupedChannels = _.default.groupBy(value, 'group.title');
|
||||
this.fetchEpgForChannels(value);
|
||||
}
|
||||
|
||||
/** Active playlist ID as signal */
|
||||
private readonly activePlaylistIdSignal =
|
||||
this.store.selectSignal(selectActivePlaylistId);
|
||||
|
||||
/** Displayed channels - filters out unfavorited channels in global favorites view */
|
||||
readonly displayedChannels = computed(() => {
|
||||
const channels = this.channelListSignal();
|
||||
if (this.activePlaylistIdSignal() === GLOBAL_FAVORITES_PLAYLIST_ID) {
|
||||
return channels.filter((ch) => this.favoriteIds().has(ch.url));
|
||||
}
|
||||
return channels;
|
||||
});
|
||||
|
||||
/** Object with channels sorted by groups */
|
||||
groupedChannels: { [key: string]: Channel[] } = {};
|
||||
readonly groupedChannels = computed(() =>
|
||||
_.default.groupBy(this.displayedChannels(), 'group.title')
|
||||
);
|
||||
|
||||
/** Selected channel */
|
||||
readonly activeChannel = this.store.selectSignal(selectActive);
|
||||
@@ -105,7 +124,8 @@ export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
|
||||
/** Set of favorite channel URLs for quick lookup */
|
||||
readonly favoriteIds = signal<Set<string>>(new Set());
|
||||
private readonly _favorites = this.store.selectSignal(selectFavorites);
|
||||
readonly favoriteIds = computed(() => new Set(this._favorites()));
|
||||
|
||||
/** List with favorites */
|
||||
favorites$ = combineLatest([
|
||||
@@ -113,8 +133,6 @@ export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
this.channelList$,
|
||||
]).pipe(
|
||||
map(([favoriteChannelIds, channelList]) => {
|
||||
// Update the favoriteIds signal for quick lookup
|
||||
this.favoriteIds.set(new Set(favoriteChannelIds));
|
||||
return favoriteChannelIds
|
||||
.map((favoriteChannelId) =>
|
||||
channelList.find(
|
||||
@@ -205,11 +223,6 @@ export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
onFavoriteToggled(event: { channel: Channel; event: MouseEvent }): void {
|
||||
event.event.stopPropagation();
|
||||
this.snackBar.open(
|
||||
this.translateService.instant('CHANNELS.FAVORITES_UPDATED'),
|
||||
undefined,
|
||||
{ duration: 2000 }
|
||||
);
|
||||
this.store.dispatch(
|
||||
FavoritesActions.updateFavorites({ channel: event.channel })
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user