mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 01:16:15 -08:00
feat: draggable channels in favorites list
This commit is contained in:
1 parent
de17686cdf
commit
ba41c8dae5
9 files changed
+101
-23
No files matched your search
+18
-18
@@ -98,28 +98,28 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
<mat-nav-list
|
||||
cdkDropList
|
||||
*ngIf="favorites$ | async as favorites"
|
||||
(cdkDropListDropped)="drop($event, favorites)"
|
||||
id="favorites-list"
|
||||
>
|
||||
<ng-container *ngIf="favorites.length > 0; else noFavorites">
|
||||
<ng-container *ngFor="let channel of favorites; index as i">
|
||||
<app-channel-list-item
|
||||
[name]="
|
||||
i +
|
||||
1 +
|
||||
'. ' +
|
||||
(channel?.name || 'CHANNELS.UNNAMED_CHANNEL'
|
||||
| translate)
|
||||
"
|
||||
[logo]="channel?.tvg?.logo"
|
||||
(clicked)="selectChannel(channel)"
|
||||
[selected]="selected?.id === channel.id"
|
||||
[showFavoriteButton]="true"
|
||||
(favoriteToggled)="
|
||||
toggleFavoriteChannel(channel, $event)
|
||||
"
|
||||
></app-channel-list-item>
|
||||
</ng-container>
|
||||
<app-channel-list-item
|
||||
*ngFor="let channel of favorites; index as i"
|
||||
[name]="
|
||||
i +
|
||||
1 +
|
||||
'. ' +
|
||||
(channel?.name || 'CHANNELS.UNNAMED_CHANNEL'
|
||||
| translate)
|
||||
"
|
||||
[isDraggable]="true"
|
||||
[logo]="channel?.tvg?.logo"
|
||||
(clicked)="selectChannel(channel)"
|
||||
[selected]="selected?.id === channel.id"
|
||||
[showFavoriteButton]="true"
|
||||
(favoriteToggled)="toggleFavoriteChannel(channel, $event)"
|
||||
></app-channel-list-item>
|
||||
</ng-container>
|
||||
<ng-template #noFavorites>
|
||||
<mat-list-item
|
||||
|
||||
+16
-5
@@ -1,3 +1,4 @@
|
||||
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
@@ -11,7 +12,6 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import * as _ from 'lodash';
|
||||
import { map, skipWhile } from 'rxjs';
|
||||
import { Channel } from '../../../../../shared/channel.interface';
|
||||
import { PlaylistsService } from '../../../services/playlists.service';
|
||||
import * as PlaylistActions from '../../../state/actions';
|
||||
import {
|
||||
selectActivePlaylistId,
|
||||
@@ -73,15 +73,16 @@ export class ChannelListContainerComponent {
|
||||
favorites$ = this.store
|
||||
.select(selectFavorites)
|
||||
.pipe(
|
||||
map((favorites) =>
|
||||
this.channelList.filter((channel) =>
|
||||
favorites.includes(channel.id)
|
||||
map((favoriteChannelIds) =>
|
||||
favoriteChannelIds.map((favoriteChannelId) =>
|
||||
this.channelList.find(
|
||||
(channel) => channel.id === favoriteChannelId
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
constructor(
|
||||
private playlistService: PlaylistsService,
|
||||
private readonly store: Store,
|
||||
private snackBar: MatSnackBar,
|
||||
private translateService: TranslateService
|
||||
@@ -119,4 +120,14 @@ export class ChannelListContainerComponent {
|
||||
trackByFn(index: number, channel: Channel): string {
|
||||
return channel.id;
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<Channel[]>, favorites: Channel[]) {
|
||||
moveItemInArray(favorites, event.previousIndex, event.currentIndex);
|
||||
console.log(favorites);
|
||||
this.store.dispatch(
|
||||
PlaylistActions.setFavorites({
|
||||
channelIds: favorites.map((item) => item.id),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
+5
@@ -24,3 +24,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drag-icon {
|
||||
cursor: move;
|
||||
margin-left: -20px;
|
||||
}
|
||||
+11
@@ -4,10 +4,20 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
selector: 'app-channel-list-item',
|
||||
styleUrls: ['./channel-list-item.component.scss'],
|
||||
template: `<mat-list-item
|
||||
cdkDrag
|
||||
[cdkDragDisabled]="!isDraggable"
|
||||
cdkDragPreviewContainer="parent"
|
||||
[class.active]="selected"
|
||||
(click)="clicked.emit()"
|
||||
data-test-id="channel-item"
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="isDraggable"
|
||||
mat-list-icon
|
||||
cdkDragHandle
|
||||
class="drag-icon"
|
||||
>drag_indicator</mat-icon
|
||||
>
|
||||
<div class="channel-logo" *ngIf="logo">
|
||||
<img [src]="logo" width="48" onerror="this.style.display='none'" />
|
||||
</div>
|
||||
@@ -27,6 +37,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
></mat-list-item>`,
|
||||
})
|
||||
export class ChannelListItemComponent {
|
||||
@Input() isDraggable = false;
|
||||
@Input() logo!: string;
|
||||
@Input() name = '';
|
||||
@Input() showFavoriteButton = false;
|
||||
|
||||
@@ -180,4 +180,15 @@ export class PlaylistsService {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
setFavorites(playlistId: string, favorites: string[]) {
|
||||
return this.getPlaylistById(playlistId).pipe(
|
||||
switchMap((playlist) =>
|
||||
this.dbService.update(DbStores.Playlists, {
|
||||
...playlist,
|
||||
favorites,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import { MomentDatePipe } from './pipes/moment-date.pipe';
|
||||
}),
|
||||
],
|
||||
exports: [
|
||||
DragDropModule,
|
||||
FilterPipe,
|
||||
FormsModule,
|
||||
HeaderComponent,
|
||||
|
||||
@@ -66,6 +66,11 @@ export const updateFavorites = createAction(
|
||||
props<{ channel: Channel }>()
|
||||
);
|
||||
|
||||
export const setFavorites = createAction(
|
||||
`${STORE_KEY} Set favorites`,
|
||||
props<{ channelIds: string[] }>()
|
||||
);
|
||||
|
||||
export const setActiveChannel = createAction(
|
||||
`${STORE_KEY} Set active channel`,
|
||||
props<{ channel: Channel }>()
|
||||
|
||||
@@ -35,6 +35,24 @@ export class PlaylistEffects {
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
setFavorites$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(PlaylistActions.setFavorites),
|
||||
combineLatestWith(this.store.select(selectActivePlaylistId)),
|
||||
switchMap(([action, playlistId]) =>
|
||||
this.playlistsService.setFavorites(
|
||||
playlistId,
|
||||
action.channelIds
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
{
|
||||
dispatch: false,
|
||||
}
|
||||
);
|
||||
|
||||
setActiveChannel$ = createEffect(() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(PlaylistActions.setActiveChannel),
|
||||
|
||||
@@ -79,6 +79,22 @@ export const playlistReducer = createReducer(
|
||||
},
|
||||
};
|
||||
}),
|
||||
on(PlaylistActions.setFavorites, (state, action): PlaylistState => {
|
||||
const { channelIds } = action;
|
||||
return {
|
||||
...state,
|
||||
playlists: {
|
||||
...state.playlists,
|
||||
entities: {
|
||||
...state.playlists.entities,
|
||||
[state.playlists.selectedId]: {
|
||||
...state.playlists.entities[state.playlists.selectedId],
|
||||
favorites: channelIds,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}),
|
||||
on(PlaylistActions.loadPlaylistsSuccess, (state, action): PlaylistState => {
|
||||
return {
|
||||
...state,
|
||||
|
||||
Reference in new issue
Block a user