refactor(external-playback): improve session handling and remove dismiss functionality

This commit is contained in:
4gray committed 2026-03-14 11:55:26 +01:00
1 parent ec84eea924
commit c42e35b48d
8 files changed
+77 -27

No files matched your search

@@ -94,22 +94,57 @@ describe('ExternalPlaybackService', () => {
contentType: 'vod',
})
).toBeNull();
expect(service.visibleSession()).toBeNull();
});
it('delegates close requests for closable sessions', async () => {
const session = createSession({ status: 'opened' });
listener?.(session);
closeExternalPlayerSession.mockResolvedValue(
createSession({
...session,
status: 'closed',
canClose: false,
updatedAt: '2026-03-07T10:00:10.000Z',
})
);
await service.closeActiveSession();
expect(closeExternalPlayerSession).toHaveBeenCalledWith(session.id);
expect(service.visibleSession()).toBeNull();
});
it('can close a specific session directly', async () => {
const session = createSession({ id: 'session-2', status: 'playing' });
closeExternalPlayerSession.mockResolvedValue(
createSession({
...session,
status: 'closed',
canClose: false,
updatedAt: '2026-03-07T10:00:12.000Z',
})
);
await service.closeSession(session);
expect(closeExternalPlayerSession).toHaveBeenCalledWith('session-2');
});
it('hides terminal sessions from the dock', () => {
listener?.(createSession({ status: 'closed', canClose: false }));
expect(service.visibleSession()).toBeNull();
listener?.(
createSession({
id: 'session-3',
status: 'error',
error: 'Launch failed',
canClose: false,
})
);
expect(service.visibleSession()).toBeNull();
});
});
@@ -10,7 +10,11 @@ export class ExternalPlaybackService {
readonly visibleSession = computed(() => {
const session = this.activeSession();
if (!session || session.status === 'closed') {
if (
!session ||
session.status === 'closed' ||
session.status === 'error'
) {
return null;
}
@@ -43,11 +47,43 @@ export class ExternalPlaybackService {
async closeSession(
session: ExternalPlayerSession | null | undefined
): Promise<void> {
if (!session?.canClose || !window.electron?.closeExternalPlayerSession) {
if (!session) {
return;
}
await window.electron.closeExternalPlayerSession(session.id);
if (!session.canClose || !window.electron?.closeExternalPlayerSession) {
this.dismissedSessionId.set(session.id);
return;
}
const previousDismissedSessionId = this.dismissedSessionId();
this.dismissedSessionId.set(session.id);
try {
const updatedSession = await window.electron.closeExternalPlayerSession(
session.id
);
if (updatedSession) {
this.handleSessionUpdate(updatedSession);
return;
}
this.activeSession.update((current) =>
current?.id === session.id
? {
...current,
status: 'closed',
canClose: false,
updatedAt: new Date().toISOString(),
}
: current
);
} catch (error) {
if (this.dismissedSessionId() === session.id) {
this.dismissedSessionId.set(previousDismissedSessionId);
}
throw error;
}
}
findMatchingSession(
@@ -53,14 +53,5 @@
}
</button>
}
<button
type="button"
mat-icon-button
class="external-playback-dock__dismiss"
(click)="dismissClicked.emit()"
aria-label="Dismiss now playing panel"
>
<mat-icon>close</mat-icon>
</button>
</div>
</section>
@@ -150,10 +150,7 @@
.external-playback-dock__button {
border-radius: 999px;
}
.external-playback-dock__dismiss {
color: var(--mat-sys-on-surface-variant);
white-space: nowrap;
}
@media (max-width: 720px) {
@@ -36,17 +36,14 @@ describe('ExternalPlaybackDockComponent', () => {
expect(text).toContain('Close player');
});
it('emits close and dismiss actions', () => {
it('emits a single close action', () => {
const closeSpy = jest.fn();
const dismissSpy = jest.fn();
component.closeClicked.subscribe(closeSpy);
component.dismissClicked.subscribe(dismissSpy);
const buttons = fixture.debugElement.queryAll(By.css('button'));
buttons[0].nativeElement.click();
buttons[1].nativeElement.click();
expect(closeSpy).toHaveBeenCalled();
expect(dismissSpy).toHaveBeenCalled();
expect(buttons).toHaveLength(1);
});
});
@@ -22,7 +22,6 @@ export class ExternalPlaybackDockComponent {
readonly compact = input(false);
readonly closeClicked = output<void>();
readonly dismissClicked = output<void>();
readonly playerLabel = computed(() => this.session().player.toUpperCase());
readonly statusLabel = computed(() => {
@@ -261,7 +261,6 @@
<app-external-playback-dock
[session]="session"
(closeClicked)="closeActiveExternalSession()"
(dismissClicked)="dismissActiveExternalSession()"
/>
</footer>
}
@@ -312,10 +312,6 @@ export class WorkspaceShellComponent {
this.externalPlayback.activeSession()
);
}
dismissActiveExternalSession(): void {
this.externalPlayback.dismissActiveSession();
}
readonly searchPlaceholder = computed(() => {
this.languageTick();