mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-14 05:06:16 -08:00
fix(dashboard): keep the hero skeleton until every hero source has loaded
The hero dropped its skeleton as soon as the history load resolved empty and came back moments later with an Xtream recently-added slide (that query waits for the favorites), moving every rail below by 316 px twice. On J1 this read renderer.layoutShiftScoreSettled 0.235 on every macOS iteration and was a race on the Linux runner. The hero now stays in its skeleton while it has no slide and any of its sources (history, favorites, Xtream recently added) is on its first load. DashboardDataService no longer settles xtreamRecentlyAddedLoading before the playlist inventory has loaded, where "no Xtream playlists" was decided on a still empty inventory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
adb4889b0f
commit
9128a90cfd
8 files changed
+170
-41
No files matched your search
@@ -167,6 +167,35 @@ describe('DashboardDataService', () => {
|
||||
clearPlaybackPosition: jest.fn().mockResolvedValue(undefined),
|
||||
};
|
||||
|
||||
const createTestingModuleProviders = () => ({
|
||||
providers: [
|
||||
DashboardDataService,
|
||||
{ provide: Store, useValue: storeMock },
|
||||
{ provide: DatabaseService, useValue: dbServiceMock },
|
||||
{
|
||||
provide: XTREAM_DATA_SOURCE,
|
||||
useValue: xtreamDataSourceMock,
|
||||
},
|
||||
{
|
||||
provide: PlaylistsService,
|
||||
useValue: playlistsServiceMock,
|
||||
},
|
||||
{
|
||||
provide: TranslateService,
|
||||
useValue: {
|
||||
instant: (key: string) => key,
|
||||
onLangChange: of(null),
|
||||
currentLang: 'en',
|
||||
defaultLang: 'en',
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: PORTAL_PLAYBACK_POSITIONS,
|
||||
useValue: playbackPositionsMock,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(window, 'electron', {
|
||||
value: {
|
||||
@@ -225,34 +254,7 @@ describe('DashboardDataService', () => {
|
||||
playbackPositionsMock.getAllPlaybackPositions.mockClear();
|
||||
playbackPositionsMock.getAllPlaybackPositions.mockResolvedValue([]);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
DashboardDataService,
|
||||
{ provide: Store, useValue: storeMock },
|
||||
{ provide: DatabaseService, useValue: dbServiceMock },
|
||||
{
|
||||
provide: XTREAM_DATA_SOURCE,
|
||||
useValue: xtreamDataSourceMock,
|
||||
},
|
||||
{
|
||||
provide: PlaylistsService,
|
||||
useValue: playlistsServiceMock,
|
||||
},
|
||||
{
|
||||
provide: TranslateService,
|
||||
useValue: {
|
||||
instant: (key: string) => key,
|
||||
onLangChange: of(null),
|
||||
currentLang: 'en',
|
||||
defaultLang: 'en',
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: PORTAL_PLAYBACK_POSITIONS,
|
||||
useValue: playbackPositionsMock,
|
||||
},
|
||||
],
|
||||
});
|
||||
TestBed.configureTestingModule(createTestingModuleProviders());
|
||||
service = TestBed.inject(DashboardDataService);
|
||||
});
|
||||
|
||||
@@ -303,6 +305,43 @@ describe('DashboardDataService', () => {
|
||||
expect(service.dashboardReady()).toBe(true);
|
||||
});
|
||||
|
||||
it('keeps xtream recently added loading until the playlist inventory has loaded', async () => {
|
||||
// Startup: the dashboard exists before the inventory, which is empty
|
||||
// until it loads, so "no Xtream playlists" is not known yet.
|
||||
TestBed.resetTestingModule();
|
||||
playlistsLoadedSignal.set(false);
|
||||
playlistsSignal.set([]);
|
||||
TestBed.configureTestingModule(createTestingModuleProviders());
|
||||
service = TestBed.inject(DashboardDataService);
|
||||
TestBed.tick();
|
||||
expect(service.xtreamRecentlyAddedLoading()).toBe(true);
|
||||
expect(service.xtreamRecentlyAddedLoaded()).toBe(false);
|
||||
|
||||
playlistsSignal.set(createDefaultPlaylists());
|
||||
playlistsLoadedSignal.set(true);
|
||||
TestBed.tick();
|
||||
expect(service.xtreamRecentlyAddedLoading()).toBe(true);
|
||||
|
||||
await service.reloadXtreamRecentlyAddedItems();
|
||||
expect(service.xtreamRecentlyAddedLoading()).toBe(false);
|
||||
expect(service.xtreamRecentlyAddedLoaded()).toBe(true);
|
||||
});
|
||||
|
||||
it('settles xtream recently added once the loaded inventory has no xtream playlists', () => {
|
||||
TestBed.resetTestingModule();
|
||||
playlistsLoadedSignal.set(false);
|
||||
playlistsSignal.set([]);
|
||||
TestBed.configureTestingModule(createTestingModuleProviders());
|
||||
service = TestBed.inject(DashboardDataService);
|
||||
TestBed.tick();
|
||||
expect(service.xtreamRecentlyAddedLoading()).toBe(true);
|
||||
|
||||
playlistsLoadedSignal.set(true);
|
||||
TestBed.tick();
|
||||
expect(service.xtreamRecentlyAddedLoading()).toBe(false);
|
||||
expect(service.xtreamRecentlyAddedLoaded()).toBe(true);
|
||||
});
|
||||
|
||||
it('includes M3U favorites in global favorite items', async () => {
|
||||
await service.reloadGlobalFavorites();
|
||||
|
||||
|
||||
@@ -452,8 +452,10 @@ export class DashboardDataService {
|
||||
this.finishInitialGlobalFavoritesLoadIfReady();
|
||||
});
|
||||
|
||||
// Before the inventory has loaded "no Xtream playlists" is not known
|
||||
// yet; settling here would end the first load before it started.
|
||||
effect(() => {
|
||||
if (this.hasXtreamPlaylists()) {
|
||||
if (!this.playlistsLoaded() || this.hasXtreamPlaylists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user