mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
fix(downloads): keep renderer download state global
This commit is contained in:
1 parent
505face7e4
commit
117bd75f01
11 files changed
+102
-23
No files matched your search
+9
@@ -121,6 +121,15 @@
|
||||
<span class="download-activity-bar__fill"></span>
|
||||
</span>
|
||||
}
|
||||
@if (activeDownloadsCount() > 0) {
|
||||
<span
|
||||
class="download-count-badge"
|
||||
data-test-id="global-download-count"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{{ activeDownloadsCount() }}
|
||||
</span>
|
||||
}
|
||||
<button
|
||||
type="button"
|
||||
class="header-shortcut"
|
||||
|
||||
+22
@@ -214,6 +214,28 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.download-count-badge {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
right: -4px;
|
||||
z-index: 11;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
padding: 0 5px;
|
||||
border: 1px solid var(--mat-sys-surface-container-low);
|
||||
border-radius: 999px;
|
||||
color: var(--app-selection-on-color, var(--mat-sys-on-primary));
|
||||
background: var(--app-selection-color, var(--mat-sys-primary));
|
||||
box-shadow: 0 2px 8px var(--app-selection-glow);
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.download-activity-bar {
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
|
||||
+28
@@ -172,4 +172,32 @@ describe('WorkspaceShellHeaderComponent', () => {
|
||||
|
||||
expect(chips).toEqual(['Movies / All Items', 'Loaded channels only']);
|
||||
});
|
||||
|
||||
it('renders the global active download count without duplicating the button name', () => {
|
||||
fixture.componentRef.setInput('isElectron', true);
|
||||
fixture.componentRef.setInput('activeDownloadsCount', 3);
|
||||
fixture.detectChanges();
|
||||
|
||||
const badge: HTMLElement | null = fixture.nativeElement.querySelector(
|
||||
'[data-test-id="global-download-count"]'
|
||||
);
|
||||
|
||||
expect(badge?.textContent?.trim()).toBe('3');
|
||||
expect(badge?.getAttribute('aria-hidden')).toBe('true');
|
||||
expect(
|
||||
fixture.nativeElement.querySelector('.download-activity-bar')
|
||||
).not.toBeNull();
|
||||
});
|
||||
|
||||
it('does not render a global download badge when no downloads are active', () => {
|
||||
fixture.componentRef.setInput('isElectron', true);
|
||||
fixture.componentRef.setInput('activeDownloadsCount', 0);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(
|
||||
fixture.nativeElement.querySelector(
|
||||
'[data-test-id="global-download-count"]'
|
||||
)
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
+5
-1
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
ElementRef,
|
||||
input,
|
||||
output,
|
||||
@@ -52,7 +53,10 @@ export class WorkspaceShellHeaderComponent {
|
||||
readonly isElectron = input(false);
|
||||
readonly hasNoPlaylists = input(false);
|
||||
readonly isDownloadsView = input(false);
|
||||
readonly hasActiveDownloads = input(false);
|
||||
readonly activeDownloadsCount = input(0);
|
||||
readonly hasActiveDownloads = computed(
|
||||
() => this.activeDownloadsCount() > 0
|
||||
);
|
||||
/**
|
||||
* When true the playlist switcher + the "+ Add source" / refresh /
|
||||
* bulk-action buttons are hidden — those controls scope to a
|
||||
|
||||
+15
@@ -376,6 +376,21 @@ describe('WorkspaceShellFacade', () => {
|
||||
expect(facade.isMacOS).toBe(false);
|
||||
});
|
||||
|
||||
it('exposes the global active download count and derives activity when supported', () => {
|
||||
downloadsActiveCountSignal.set(3);
|
||||
|
||||
expect(facade.activeDownloadsCount()).toBe(3);
|
||||
expect(facade.hasActiveDownloads()).toBe(true);
|
||||
});
|
||||
|
||||
it('hides the active download count when downloads are unsupported', () => {
|
||||
runtime.supportsDownloads = false;
|
||||
downloadsActiveCountSignal.set(3);
|
||||
|
||||
expect(facade.activeDownloadsCount()).toBe(0);
|
||||
expect(facade.hasActiveDownloads()).toBe(false);
|
||||
});
|
||||
|
||||
it('routes dashboard search Enter into the active Xtream playlist search', () => {
|
||||
const xtreamStore = TestBed.inject(
|
||||
XtreamStore
|
||||
|
||||
+4
-1
@@ -112,8 +112,11 @@ export class WorkspaceShellFacade {
|
||||
readonly isRefreshingPlaylist = this.header.isRefreshingPlaylist;
|
||||
readonly headerBulkAction = this.header.headerBulkAction;
|
||||
readonly playlistSubtitle = this.header.playlistSubtitle;
|
||||
readonly activeDownloadsCount = computed(() =>
|
||||
this.supportsDownloads ? this.downloadsService.activeCount() : 0
|
||||
);
|
||||
readonly hasActiveDownloads = computed(
|
||||
() => this.supportsDownloads && this.downloadsService.activeCount() > 0
|
||||
() => this.activeDownloadsCount() > 0
|
||||
);
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
[isElectron]="facade.isElectron"
|
||||
[hasNoPlaylists]="facade.hasNoPlaylists()"
|
||||
[isDownloadsView]="facade.isDownloadsView()"
|
||||
[hasActiveDownloads]="facade.hasActiveDownloads()"
|
||||
[activeDownloadsCount]="facade.activeDownloadsCount()"
|
||||
[isSettingsRoute]="facade.isSettingsRoute()"
|
||||
(refreshPlaylistRequested)="facade.refreshCurrentPlaylist()"
|
||||
(searchChanged)="facade.onSearchInput($event)"
|
||||
|
||||
+6
-2
@@ -58,7 +58,7 @@ class MockWorkspaceShellHeaderComponent {
|
||||
readonly isElectron = input(false);
|
||||
readonly hasNoPlaylists = input(false);
|
||||
readonly isDownloadsView = input(false);
|
||||
readonly hasActiveDownloads = input(false);
|
||||
readonly activeDownloadsCount = input(0);
|
||||
readonly isSettingsRoute = input(false);
|
||||
readonly headerBulkAction = input<WorkspaceHeaderBulkAction | null>(null);
|
||||
readonly searchChanged = output<string>();
|
||||
@@ -154,7 +154,7 @@ class MockWorkspaceShellFacade {
|
||||
readonly isRefreshingPlaylist = signal(false);
|
||||
readonly hasNoPlaylists = signal(false);
|
||||
readonly isDownloadsView = signal(false);
|
||||
readonly hasActiveDownloads = signal(false);
|
||||
readonly activeDownloadsCount = signal(3);
|
||||
readonly headerBulkAction = signal<WorkspaceHeaderBulkAction | null>(null);
|
||||
readonly showContextPanel = signal(true);
|
||||
readonly contextPanel = signal<WorkspaceShellContextPanel>('settings');
|
||||
@@ -246,6 +246,10 @@ describe('WorkspaceShellComponent', () => {
|
||||
expect(
|
||||
fixture.nativeElement.querySelector('app-workspace-shell-header')
|
||||
).not.toBeNull();
|
||||
const header = fixture.debugElement.query(
|
||||
By.directive(MockWorkspaceShellHeaderComponent)
|
||||
).componentInstance as MockWorkspaceShellHeaderComponent;
|
||||
expect(header.activeDownloadsCount()).toBe(3);
|
||||
expect(
|
||||
fixture.nativeElement.querySelector(
|
||||
'app-workspace-shell-context-sidebar'
|
||||
|
||||
Reference in new issue
Block a user