mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 13:46:16 -08:00
fix(settings): bind the M3U group management result to its playlist
The groups view captures the playlist before the PIN prompt and drops the management dialog's hidden and locked group lists once another playlist is open, so they cannot be saved under that playlist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4c64b798e1
commit
0f225d8f95
5 files changed
+38
-5
No files matched your search
@@ -372,7 +372,10 @@ on either side.
|
||||
lock store, failure snackbar); the M3U rail emits the toggled group to
|
||||
`ChannelListContainerComponent`, which captures the playlist, asks for
|
||||
the PIN, and persists the edit only if that playlist is still open (two
|
||||
playlists can share a group name). Bulk actions stay in the dialog, and while the session is locked
|
||||
playlists can share a group name). The M3U management dialog is bound
|
||||
the same way: `GroupsViewComponent` captures its `playlistId` input
|
||||
before the PIN and drops the dialog's result once another playlist is
|
||||
open. Bulk actions stay in the dialog, and while the session is locked
|
||||
a locked category is not in the rail, so unlocking always goes through
|
||||
the "N locked · Enter PIN to show" row or the dialog. The M3U dialog
|
||||
hands its lock list back to `ChannelListContainerComponent`, which
|
||||
|
||||
+1
@@ -62,6 +62,7 @@
|
||||
[activeChannelUrl]="activeChannelUrl()"
|
||||
[favoriteIds]="favoriteIds()"
|
||||
[hiddenGroupTitles]="hiddenGroupTitles()"
|
||||
[playlistId]="activePlaylist()?._id ?? null"
|
||||
[lockedGroupTitles]="lockedGroupTitles()"
|
||||
[withheldGroupCount]="withheldGroupCount()"
|
||||
[managementGroups]="managementGroups()"
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ export class ChannelListContainerComponent implements OnInit, OnDestroy {
|
||||
/** Route-aware playlist ID for recent-item mutations */
|
||||
private readonly resolvedPlaylistId =
|
||||
this.playlistContext.resolvedPlaylistId;
|
||||
private readonly activePlaylist = this.playlistContext.activePlaylist;
|
||||
protected readonly activePlaylist = this.playlistContext.activePlaylist;
|
||||
|
||||
/** Map of channel ID to current EPG program */
|
||||
readonly channelEpgMap = signal(new Map<string, EpgProgram | null>());
|
||||
|
||||
+20
-1
@@ -4,7 +4,7 @@ import { By } from '@angular/platform-browser';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of } from 'rxjs';
|
||||
import { of, Subject } from 'rxjs';
|
||||
import { ParentalLockService } from '@iptvnator/services';
|
||||
import { Channel } from '@iptvnator/shared/interfaces';
|
||||
import { ChannelDetailsDialogComponent } from '../channel-details-dialog/channel-details-dialog.component';
|
||||
@@ -537,6 +537,25 @@ describe('GroupsViewComponent', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('drops the manage-groups result once another playlist is open', async () => {
|
||||
const hiddenGroupTitlesChanged = jest.fn();
|
||||
const lockedGroupTitlesChanged = jest.fn();
|
||||
component.hiddenGroupTitlesChanged.subscribe(hiddenGroupTitlesChanged);
|
||||
component.lockedGroupTitlesChanged.subscribe(lockedGroupTitlesChanged);
|
||||
fixture.componentRef.setInput('playlistId', 'playlist-a');
|
||||
fixture.componentRef.setInput('lockedGroupTitles', ['News']);
|
||||
fixture.detectChanges();
|
||||
const closed = new Subject<unknown>();
|
||||
dialog.open.mockReturnValue({ afterClosed: () => closed });
|
||||
|
||||
await component.openGroupManagement();
|
||||
fixture.componentRef.setInput('playlistId', 'playlist-b');
|
||||
closed.next({ hiddenGroupTitles: [], lockedGroupTitles: [] });
|
||||
|
||||
expect(hiddenGroupTitlesChanged).not.toHaveBeenCalled();
|
||||
expect(lockedGroupTitlesChanged).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('emits a single-group toggle from the right-click menu (the host asks for the PIN)', () => {
|
||||
const groupLockToggled = jest.fn();
|
||||
component.groupLockToggled.subscribe(groupLockToggled);
|
||||
|
||||
+12
-2
@@ -153,6 +153,12 @@ export class GroupsViewComponent {
|
||||
* of the playlist, locked ones included, because `groupedChannels`
|
||||
* arrives with the withheld groups already removed.
|
||||
*/
|
||||
/**
|
||||
* The playlist the groups belong to. The management dialog's result is
|
||||
* applied only while it is still the open one: the host saves hidden
|
||||
* and locked groups under the CURRENT playlist.
|
||||
*/
|
||||
readonly playlistId = input<string | null>(null);
|
||||
readonly lockedGroupTitles = input<string[] | null>(null);
|
||||
readonly managementGroups = input<GroupManagementDialogGroup[] | null>(
|
||||
null
|
||||
@@ -535,7 +541,11 @@ export class GroupsViewComponent {
|
||||
// The dialog lists every group by name, locked ones included, and can
|
||||
// rewrite the locks — so it sits behind the PIN like the portal
|
||||
// dialogs do.
|
||||
if (!(await this.parentalLock.requestUnlock())) {
|
||||
const playlistId = this.playlistId();
|
||||
if (
|
||||
!(await this.parentalLock.requestUnlock()) ||
|
||||
this.playlistId() !== playlistId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const groups =
|
||||
@@ -558,7 +568,7 @@ export class GroupsViewComponent {
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result) => {
|
||||
if (result === undefined) {
|
||||
if (result === undefined || this.playlistId() !== playlistId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user