fix(downloads): honor the global cover size

This commit is contained in:
4gray committed 2026-08-01 16:29:49 +02:00
1 parent 727ea58bd7
commit 34fa69e6f5
3 files changed
+59 -3

No files matched your search

@@ -235,7 +235,7 @@
[availablePlaylistIds]="availablePlaylistIds()"
[pendingIds]="pendingIds()"
(itemAction)="runAction($event)"
(seriesOpened)="openInLibrary($event)"
(openRequested)="openInLibrary($event)"
(episodesOpened)="openDownloadedSeries($event)"
/>
}
@@ -365,8 +365,11 @@
.downloads__skeleton-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr));
gap: clamp(12px, 1.5vw, 20px);
grid-template-columns: repeat(
auto-fill,
minmax(min(100%, var(--cover-grid-min-width, 148px)), 1fr)
);
gap: var(--cover-gap, 16px);
}
.downloads__skeleton-card {
@@ -1,3 +1,5 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { computed, signal } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialog } from '@angular/material/dialog';
@@ -288,6 +290,7 @@ describe('DownloadsComponent', () => {
URL_COPIED: 'URL copied',
URL_COPY_FAILED: 'URL copy failed',
REMOVE_FROM_MANAGER: 'Remove from manager',
PLAY: 'Play',
},
CHANNELS: { LOADING: 'Loading' },
WORKSPACE: {
@@ -358,6 +361,22 @@ describe('DownloadsComponent', () => {
).not.toBeNull();
});
it('uses the shared cover-grid sizing contract for skeleton cards', () => {
const styles = readFileSync(
join(__dirname, 'downloads.component.scss'),
'utf8'
);
const skeletonCardsRule =
styles.match(/\.downloads__skeleton-cards\s*\{([^}]*)\}/)?.[1] ??
'';
expect(skeletonCardsRule).toContain(
'var(--cover-grid-min-width, 148px)'
);
expect(skeletonCardsRule).toContain('var(--cover-gap, 16px)');
expect(skeletonCardsRule).not.toContain('150px');
});
it('derives route scope without mutating the global service signal', () => {
const globalItems = [
download(1, { status: 'downloading' }),
@@ -608,6 +627,40 @@ describe('DownloadsComponent', () => {
);
});
it('opens completed movie artwork in details while explicit Play uses the file', async () => {
const item = download(14, {
title: 'Completed movie',
filePath: '/downloads/completed-movie.mp4',
});
downloads.set([item]);
await fixture.whenStable();
const artworkButton = fixture.nativeElement.querySelector(
'.download-library__artwork-button'
) as HTMLButtonElement;
expect(artworkButton).toBeTruthy();
artworkButton.click();
await fixture.whenStable();
expect(navigation.open).toHaveBeenCalledWith(item);
expect(downloadsService.playDownload).not.toHaveBeenCalled();
jest.clearAllMocks();
const playButton = fixture.nativeElement.querySelector(
'.download-library__actions button[aria-label="Play: Completed movie"]'
) as HTMLButtonElement;
expect(playButton).toBeTruthy();
playButton.click();
await fixture.whenStable();
expect(downloadsService.playDownload).toHaveBeenCalledWith(
item.filePath
);
expect(navigation.open).not.toHaveBeenCalled();
});
it('does not navigate an item whose source playlist is missing', async () => {
const item = download(13, { playlistId: 'removed-playlist' });
navigation.canOpen.mockReturnValueOnce(false);