feat(settings): add shared web player controls toggle (#1198)

* docs(playback): design shared controls setting

* docs(playback): plan shared controls setting

* feat(settings): persist shared web controls preference

* test(settings): harden shared controls normalization coverage

* feat(settings): expose shared web controls toggle

* fix(settings): label shared controls toggle

* feat(playback): resolve shared controls from settings

* test(playback): cover shared controls setting

* docs(playback): document shared controls preference

* fix(playback): await settings before host creation

* fix(settings): normalize shared controls updates
This commit is contained in:
4gray authored and GitHub committed 2026-07-17 13:38:06 +02:00
1 parent 48e3736460
commit beb62db314
38 files changed
+1863 -300

No files matched your search

@@ -84,6 +84,7 @@ export class MockRouter {
const DEFAULT_SETTINGS = {
player: VideoPlayer.VideoJs,
webPlayerSharedControls: false,
streamFormat: StreamFormat.AutoStreamFormat,
openStreamOnDoubleClick: false,
language: Language.ENGLISH,
@@ -661,6 +662,19 @@ describe('SettingsComponent', () => {
});
});
it('hydrates the shared web controls setting from the settings store', () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
mockStore._setSettings({
webPlayerSharedControls: true,
});
component.setSettings();
expect(
component.settingsForm.get('webPlayerSharedControls')?.value
).toBe(true);
});
it('hides the embedded mpv option when the desktop support probe reports unsupported', async () => {
window.electron = {
...window.electron,
@@ -1301,9 +1315,7 @@ describe('SettingsComponent', () => {
it('updates the EPG view mode through the epg section output', () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
const listButton = (
fixture.nativeElement as HTMLElement
).querySelector(
const listButton = (fixture.nativeElement as HTMLElement).querySelector(
'[data-test-id="epg-view-mode-list"]'
) as HTMLButtonElement;
@@ -1398,6 +1410,21 @@ describe('SettingsComponent', () => {
});
});
it('saves the shared web controls setting on submit', async () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
mockStore.updateSettings.mockResolvedValue(undefined);
component.settingsForm.get('webPlayerSharedControls')?.setValue(true);
component.onSubmit();
await fixture.whenStable();
expect(mockStore.updateSettings).toHaveBeenCalledWith(
expect.objectContaining({
webPlayerSharedControls: true,
})
);
});
it('clears external player paths in Electron when saved as empty', async () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
mockStore.updateSettings.mockResolvedValue(undefined);