mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
Merge master into perf/onpush-libs-playlist
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
300e6f2cf0
13 files changed
+75
-21
No files matched your search
@@ -149,15 +149,15 @@ picker), so each marks itself on the form's `events` through
|
||||
|
||||
### libs/portal (9)
|
||||
|
||||
- [ ] `libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.ts`
|
||||
- [ ] `libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.ts`
|
||||
- [ ] `libs/portal/shared/ui/src/lib/components/search-form/search-form.component.ts`
|
||||
- [ ] `libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.ts`
|
||||
- [ ] `libs/portal/stalker/feature/src/lib/stalker-catalog-detail/stalker-catalog-detail.component.ts`
|
||||
- [ ] `libs/portal/stalker/feature/src/lib/stalker-favorites-button/stalker-favorites-button.component.ts`
|
||||
- [ ] `libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.ts`
|
||||
- [ ] `libs/portal/xtream/feature/src/lib/global-search-results/global-search-results.component.ts`
|
||||
- [ ] `libs/portal/xtream/feature/src/lib/serial-details/serial-details.component.ts`
|
||||
- [x] `libs/portal/shared/ui/src/lib/components/favorites-layout/favorites-layout.component.ts`
|
||||
- [x] `libs/portal/shared/ui/src/lib/components/playlist-error-view/playlist-error-view.component.ts`
|
||||
- [x] `libs/portal/shared/ui/src/lib/components/search-form/search-form.component.ts`
|
||||
- [x] `libs/portal/shared/ui/src/lib/navigation/portal-rail-links.component.ts`
|
||||
- [x] `libs/portal/stalker/feature/src/lib/stalker-catalog-detail/stalker-catalog-detail.component.ts`
|
||||
- [x] `libs/portal/stalker/feature/src/lib/stalker-favorites-button/stalker-favorites-button.component.ts`
|
||||
- [x] `libs/portal/stalker/feature/src/lib/stalker-series-view/stalker-series-view.component.ts`
|
||||
- [x] `libs/portal/xtream/feature/src/lib/global-search-results/global-search-results.component.ts`
|
||||
- [x] `libs/portal/xtream/feature/src/lib/serial-details/serial-details.component.ts`
|
||||
|
||||
Test-only files that set Eager are not listed; they do not ship. The guard
|
||||
skips every `*.spec.ts` / `*.test.ts` file with or without a suffix of one
|
||||
@@ -179,9 +179,9 @@ the field a signal (or a `computed`), or writes it through one.
|
||||
| [x] | `libs/playlist/shared/ui/src/lib/recent-playlists/playlist-item/playlist-item.component.ts` `checkPortalStatus` | plain `portalStatus` assigned after `await` in `ngOnInit` (PWA only: skipped when source health is supported) | playlist |
|
||||
| [x] | `libs/playlist/shared/ui/src/lib/recent-playlists/playlist-info/playlist-info.component.ts` (EPG clear and EPG file pick handlers) | plain `playlist` reassigned after `await` | playlist |
|
||||
| [x] | `libs/playlist/import/feature/src/lib/stalker-portal-import/stalker-portal-import.component.ts` (device-id derivation) | `form.patchValue` after `await`; no fix needed: while derivation is on `hasManualDeviceIds` is false whatever the IDs are, the controls write their own DOM values, and typing goes through value-accessor listeners that mark the view | playlist |
|
||||
| [ ] | `libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts` (favorites load) | `favorites` Map filled in a `subscribe` without `markForCheck`; the component is OnPush already, so this is a latent bug today | portal |
|
||||
| [ ] | `libs/portal/xtream/feature/src/lib/portal-channels-list/portal-channels-list.component.ts` (favorites load) | same pattern; the neighbouring `favoriteMarks.changes$` handler does call `markForCheck` | portal |
|
||||
| [ ] | same file, programme dialog `afterClosed` | deletes from `epgPrograms`/`currentProgramsProgress` after `await` without marking | portal |
|
||||
| [x] | `libs/portal/stalker/feature/src/lib/stalker-live-stream-layout/stalker-live-stream-layout.component.ts` (favorites load) | `favorites` Map filled in a `subscribe` without `markForCheck`; the component is OnPush already, so this is a latent bug today | portal |
|
||||
| [x] | `libs/portal/xtream/feature/src/lib/portal-channels-list/portal-channels-list.component.ts` (favorites load) | same pattern; the neighbouring `favoriteMarks.changes$` handler does call `markForCheck` | portal |
|
||||
| [x] | same file, programme dialog `afterClosed` | deletes from `epgPrograms`/`currentProgramsProgress` after `await` without marking | portal |
|
||||
| [x] | `apps/web/src/app/settings/settings-backup.facade.ts` (backup import) | `change` listener on a detached file input → `hydrateFromStore()`; section templates read `form().value.theme`/`coverSize`; each section now marks itself on its form's `events` (`markSectionForCheckOnFormEvents`), which `settings.component.form.spec.ts` guards without a forced render | apps/web |
|
||||
| [x] | `libs/ui/epg/src/lib/epg-guide/epg-guide.component.ts` (jump to now, keyboard focus) | `afterNextRender` registered from CDK/RxJS callbacks; zone.js followed them with a tick, zoneless schedules no render, so the guide opened at midnight. It now marks itself when it registers the hook. Found by `epg-guide.e2e.ts` on the zoneless build | flag |
|
||||
| [ ] | `libs/ui/remote-control/src/lib/remote-control/remote-control.component.ts` | plain `isLoading`/`error`/`status` written after `await` and from a 2 s `setInterval` | only if `apps/remote-control-web` goes zoneless |
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ export interface FavoriteLayoutItem {
|
||||
'./favorites-layout.component.scss',
|
||||
'../../styles/portal-sidebar.scss',
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
CategoryViewComponent,
|
||||
ContentCardComponent,
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import { DialogService } from '@iptvnator/ui/components';
|
||||
selector: 'app-playlist-error-view',
|
||||
templateUrl: './playlist-error-view.component.html',
|
||||
styleUrls: ['./playlist-error-view.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [MatButtonModule, MatIconModule, RouterLink, TranslateModule],
|
||||
})
|
||||
export class PlaylistErrorViewComponent {
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface SearchFilter {
|
||||
TranslatePipe,
|
||||
],
|
||||
templateUrl: './search-form.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
styles: [
|
||||
`
|
||||
.search-container {
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
selector: 'app-portal-rail-links',
|
||||
imports: [MatIcon, MatListModule, MatTooltip, RouterLink, RouterLinkActive],
|
||||
templateUrl: './portal-rail-links.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
styleUrl: './portal-rail-links.component.scss',
|
||||
})
|
||||
export class PortalRailLinksComponent {
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ import { createPlaybackSessionKey } from '@iptvnator/playback/util';
|
||||
selector: 'app-stalker-catalog-detail',
|
||||
imports: [StalkerSeriesViewComponent, VodDetailsComponent],
|
||||
templateUrl: './stalker-catalog-detail.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
styles: [
|
||||
`
|
||||
:host {
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ type FavoriteButtonItem = StalkerSelectedVodItem & {
|
||||
selector: 'app-favorites-button',
|
||||
templateUrl: './stalker-favorites-button.component.html',
|
||||
styleUrls: ['./stalker-favorites-button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [AsyncPipe, DetailIconButtonComponent, MatIconModule, TranslateModule],
|
||||
})
|
||||
export class FavoritesButtonComponent {
|
||||
|
||||
+2
@@ -679,6 +679,8 @@ export class StalkerLiveStreamLayoutComponent
|
||||
);
|
||||
}
|
||||
});
|
||||
// OnPush: the Map changed outside any template event.
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -155,7 +155,7 @@ interface StalkerSeriesPlaybackRequestContext {
|
||||
TranslatePipe,
|
||||
SeasonContainerComponent,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
StalkerSeriesTmdbSeasonsService,
|
||||
StalkerSeriesHeroPresenter,
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { SearchResultsComponent } from '../search-results/search-results.compone
|
||||
selector: 'app-global-search-results',
|
||||
imports: [SearchResultsComponent],
|
||||
providers: [XtreamStore],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<app-search-results/>',
|
||||
})
|
||||
export class GlobalSearchResultsComponent {}
|
||||
+50
@@ -900,6 +900,56 @@ describe('PortalChannelsListComponent', () => {
|
||||
).toBe('live:290');
|
||||
});
|
||||
|
||||
// OnPush: favorites resolve asynchronously (IPC or IndexedDB), outside
|
||||
// any template event, so the heart must follow without a zone tick.
|
||||
it('renders favorites that load after the first render', async () => {
|
||||
const favorites$ = new Subject<FavoriteItem[]>();
|
||||
favoritesService.getFavorites.mockReturnValue(favorites$);
|
||||
selectedTypeContentLoading.set(false);
|
||||
selectedChannels.set([{ title: 'Cartoon Network', xtream_id: 50 }]);
|
||||
currentPlaylist.set({
|
||||
id: 'playlist-1',
|
||||
password: 'secret',
|
||||
serverUrl: 'http://demo.example',
|
||||
username: 'demo',
|
||||
});
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
const viewport = fixture.componentInstance.viewport();
|
||||
Object.defineProperty(
|
||||
viewport?.elementRef.nativeElement,
|
||||
'clientHeight',
|
||||
{ configurable: true, value: 520 }
|
||||
);
|
||||
viewport?.checkViewportSize();
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
fixture.detectChanges();
|
||||
const row = () =>
|
||||
fixture.debugElement.query(By.directive(ChannelListItemComponent))
|
||||
.componentInstance as ChannelListItemComponent;
|
||||
expect(row().isFavorite()).toBe(false);
|
||||
|
||||
// From here the fixture renders on its own: a forced detectChanges()
|
||||
// would hide a favorites handler that does not mark the view.
|
||||
fixture.autoDetectChanges();
|
||||
favorites$.next([
|
||||
{
|
||||
content_id: 1,
|
||||
playlist_id: 'playlist-1',
|
||||
type: 'live',
|
||||
title: 'Cartoon Network',
|
||||
category_id: 7,
|
||||
xtream_id: 50,
|
||||
},
|
||||
] satisfies FavoriteItem[]);
|
||||
await fixture.whenStable();
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
|
||||
expect(row().isFavorite()).toBe(true);
|
||||
});
|
||||
|
||||
it('scrolls the virtual list to the selected live channel', () => {
|
||||
const channels = Array.from({ length: 20 }, (_, index) => ({
|
||||
title: `Channel ${index + 1}`,
|
||||
|
||||
+2
@@ -334,6 +334,7 @@ export class PortalChannelsListComponent implements AfterViewInit, OnDestroy {
|
||||
true
|
||||
);
|
||||
});
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
// A toggle in another list instance (the sidebar and the
|
||||
// fullscreen channel panel render this component side by side)
|
||||
@@ -771,6 +772,7 @@ export class PortalChannelsListComponent implements AfterViewInit, OnDestroy {
|
||||
this.epgQueueService.invalidate(streamId);
|
||||
this.epgPrograms.delete(streamId);
|
||||
this.currentProgramsProgress.delete(streamId);
|
||||
this.cdr.markForCheck();
|
||||
this.loadEpgForVisibleChannels(this.channelsToPreview());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ import { SerialDetailsDownloadAdapterService } from './serial-details-download-a
|
||||
SerialDetailsMenuService,
|
||||
SerialDetailsDownloadAdapterService,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
CastCrewRowComponent,
|
||||
DetailActionButtonComponent,
|
||||
|
||||
Reference in new issue
Block a user