From e53a25f4419eb43c08b8637c237181bd7fbfce1f Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 25 Apr 2026 22:39:55 +0200 Subject: [PATCH] style(settings): add EPG sources handling and UI enhancements Entire-Checkpoint: c6e522b4276c --- .../src/app/settings/settings.component.html | 168 +++++++++++------- .../src/app/settings/settings.component.scss | 34 ++++ .../app/settings/settings.component.spec.ts | 75 ++++++++ apps/web/src/assets/i18n/ar.json | 4 +- apps/web/src/assets/i18n/ary.json | 4 +- apps/web/src/assets/i18n/by.json | 4 +- apps/web/src/assets/i18n/de.json | 4 +- apps/web/src/assets/i18n/el.json | 4 +- apps/web/src/assets/i18n/en.json | 2 + apps/web/src/assets/i18n/es.json | 4 +- apps/web/src/assets/i18n/fr.json | 4 +- apps/web/src/assets/i18n/it.json | 4 +- apps/web/src/assets/i18n/ja.json | 4 +- apps/web/src/assets/i18n/ko.json | 4 +- apps/web/src/assets/i18n/nl.json | 4 +- apps/web/src/assets/i18n/pl.json | 4 +- apps/web/src/assets/i18n/pt.json | 4 +- apps/web/src/assets/i18n/ru.json | 4 +- apps/web/src/assets/i18n/tr.json | 4 +- apps/web/src/assets/i18n/zh.json | 4 +- apps/web/src/assets/i18n/zhtw.json | 4 +- 21 files changed, 265 insertions(+), 82 deletions(-) diff --git a/apps/web/src/app/settings/settings.component.html b/apps/web/src/app/settings/settings.component.html index 51743be4a..3ded4fff9 100644 --- a/apps/web/src/app/settings/settings.component.html +++ b/apps/web/src/app/settings/settings.component.html @@ -232,7 +232,7 @@ formControlName="player" data-test-id="select-video-player" > - @for (player of players; track player) { + @for (player of players(); track player.id) {
-
- @for ( - _ of epgUrl.controls; - track _; - let i = $index - ) { -
- - {{ - 'SETTINGS.EPG_URL_PLACEHOLDER' - | translate - }} - - {{ - 'SETTINGS.EPG_URL_ERROR' - | translate - }} - - @if (epgField.value) { - - } - - -
- } -
+ @if (epgUrl.length === 0) { +
+ event_busy +

+ {{ + 'SETTINGS.EPG_EMPTY_TITLE' + | translate + }} +

+

+ {{ + 'SETTINGS.EPG_EMPTY_HINT' + | translate + }} +

+
+ } @else { +
+ @for ( + _ of epgUrl.controls; + track _; + let i = $index + ) { +
+ + {{ + 'SETTINGS.EPG_URL_PLACEHOLDER' + | translate + }} + + {{ + 'SETTINGS.EPG_URL_ERROR' + | translate + }} + + @if (epgField.value) { + + } + + +
+ } +
+ }
@@ -909,6 +935,18 @@ + @if (isDesktop) { +
+ {{ + 'SETTINGS.EMBEDDED_MPV_NOTICE_TITLE' | translate + }} + {{ + 'SETTINGS.EMBEDDED_MPV_NOTICE_DESCRIPTION' + | translate + }} +
+ } +

{{ 'SETTINGS.COMMUNITY' | translate }}

diff --git a/apps/web/src/app/settings/settings.component.scss b/apps/web/src/app/settings/settings.component.scss index 637f195d9..f67446c44 100644 --- a/apps/web/src/app/settings/settings.component.scss +++ b/apps/web/src/app/settings/settings.component.scss @@ -297,6 +297,40 @@ gap: 8px; } +.epg-sources-empty { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + gap: 8px; + padding: 24px 16px 16px; + color: var(--mat-sys-on-surface-variant); + + .epg-sources-empty__icon { + font-size: 40px; + width: 40px; + height: 40px; + opacity: 0.55; + margin-bottom: 4px; + } + + .epg-sources-empty__title { + margin: 0; + font-size: 0.95rem; + font-weight: 600; + color: var(--mat-sys-on-surface); + } + + .epg-sources-empty__hint { + margin: 0; + font-size: 0.825rem; + line-height: 1.5; + max-width: 360px; + opacity: 0.75; + } +} + .epg-source-row { display: flex; align-items: center; diff --git a/apps/web/src/app/settings/settings.component.spec.ts b/apps/web/src/app/settings/settings.component.spec.ts index 58aa34d47..55aa02eb2 100644 --- a/apps/web/src/app/settings/settings.component.spec.ts +++ b/apps/web/src/app/settings/settings.component.spec.ts @@ -30,6 +30,7 @@ import { PlaylistsService, } from 'services'; import { + EmbeddedMpvSupport, Language, PlaylistMeta, StartupBehavior, @@ -400,6 +401,80 @@ describe('SettingsComponent', () => { ...settings, }); }); + + it('hides the embedded mpv option when the desktop support probe reports unsupported', async () => { + window.electron = { + ...window.electron, + getEmbeddedMpvSupport: jest.fn().mockResolvedValue({ + supported: false, + platform: 'darwin', + reason: 'hidden harness', + }), + } as unknown as typeof window.electron; + + await component.ngOnInit(); + await fixture.whenStable(); + + expect( + component.players().some( + (player) => player.id === VideoPlayer.EmbeddedMpv + ) + ).toBe(false); + }); + + it('shows the embedded mpv option when the desktop support probe reports supported', async () => { + window.electron = { + ...window.electron, + getEmbeddedMpvSupport: jest.fn().mockResolvedValue({ + supported: true, + platform: 'darwin', + }), + } as unknown as typeof window.electron; + + await component.ngOnInit(); + await fixture.whenStable(); + + expect( + component.players().some( + (player) => player.id === VideoPlayer.EmbeddedMpv + ) + ).toBe(true); + }); + + it('does not block settings initialization while embedded mpv support is pending', async () => { + let resolveSupport: (value: EmbeddedMpvSupport) => void; + window.electron = { + ...window.electron, + getEmbeddedMpvSupport: jest.fn( + () => + new Promise((resolve) => { + resolveSupport = resolve; + }) + ), + } as unknown as typeof window.electron; + + await expect(component.ngOnInit()).resolves.toBeUndefined(); + + expect(component.settingsForm.value).toEqual(DEFAULT_SETTINGS); + expect(window.electron.getEmbeddedMpvSupport).toHaveBeenCalled(); + expect( + component.players().some( + (player) => player.id === VideoPlayer.EmbeddedMpv + ) + ).toBe(false); + + resolveSupport!({ + supported: true, + platform: 'darwin', + }); + await fixture.whenStable(); + + expect( + component.players().some( + (player) => player.id === VideoPlayer.EmbeddedMpv + ) + ).toBe(true); + }); }); describe('Version check', () => { diff --git a/apps/web/src/assets/i18n/ar.json b/apps/web/src/assets/i18n/ar.json index bb3c2c536..58d0a98b8 100644 --- a/apps/web/src/assets/i18n/ar.json +++ b/apps/web/src/assets/i18n/ar.json @@ -209,7 +209,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "المنفذ المستخدم للتحكم عن بعد (الافتراضي: 8765).", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "السمة الداكنة", diff --git a/apps/web/src/assets/i18n/ary.json b/apps/web/src/assets/i18n/ary.json index 2dd867d40..b057ccaca 100644 --- a/apps/web/src/assets/i18n/ary.json +++ b/apps/web/src/assets/i18n/ary.json @@ -201,7 +201,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "المنفذ اللي كيتستعمل للتحكم عن بعد للتطبيق. المنفذ 3000 كيتستعمل افتراضياً.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "المظهر الداكن", diff --git a/apps/web/src/assets/i18n/by.json b/apps/web/src/assets/i18n/by.json index 73447695c..9dccae6be 100644 --- a/apps/web/src/assets/i18n/by.json +++ b/apps/web/src/assets/i18n/by.json @@ -203,7 +203,9 @@ "VLC_PLAYER_PATH_DESCRIPTION": "Усталюйце шлях да прайгравальніка VLC у вашай сістэме. \nЁн будзе выкарыстоўваць прадастаўлены шлях да бінарнага файла VLC замест шляху па змаўчанні.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Цёмная тэма", diff --git a/apps/web/src/assets/i18n/de.json b/apps/web/src/assets/i18n/de.json index ee8271110..ede476f1b 100644 --- a/apps/web/src/assets/i18n/de.json +++ b/apps/web/src/assets/i18n/de.json @@ -376,7 +376,9 @@ "PORT_PATTERN": "Nur Ziffern sind erlaubt", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Dunkel", diff --git a/apps/web/src/assets/i18n/el.json b/apps/web/src/assets/i18n/el.json index fb2dbcdb4..f5b8b48f6 100644 --- a/apps/web/src/assets/i18n/el.json +++ b/apps/web/src/assets/i18n/el.json @@ -254,7 +254,9 @@ "PORT_PATTERN": "Επιτρέπονται μόνο αριθμητικά ψηφία", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Σκούρο θέμα", diff --git a/apps/web/src/assets/i18n/en.json b/apps/web/src/assets/i18n/en.json index 63f7a46b9..275174aa6 100644 --- a/apps/web/src/assets/i18n/en.json +++ b/apps/web/src/assets/i18n/en.json @@ -200,6 +200,8 @@ "PLAYBACK": "Playback", "EPG_SOURCES": "EPG sources", "EPG_SOURCES_DESCRIPTION": "Add one or more URLs as EPG sources", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.", "DATA": "Data", "ABOUT": "About", "NAV_GENERAL": "General", diff --git a/apps/web/src/assets/i18n/es.json b/apps/web/src/assets/i18n/es.json index d289a2dc8..8b0ea83b4 100644 --- a/apps/web/src/assets/i18n/es.json +++ b/apps/web/src/assets/i18n/es.json @@ -231,7 +231,9 @@ "STREAM_FORMAT_DESCRIPTION": "Selecciona el formato de transmision predeterminado (Xtream)", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Tema oscuro", diff --git a/apps/web/src/assets/i18n/fr.json b/apps/web/src/assets/i18n/fr.json index 7ed22cc5a..f290eda17 100644 --- a/apps/web/src/assets/i18n/fr.json +++ b/apps/web/src/assets/i18n/fr.json @@ -222,7 +222,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "Port utilisé pour la télécommande de l'application. Le port 8765 est utilisé par défaut.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Thème foncé", diff --git a/apps/web/src/assets/i18n/it.json b/apps/web/src/assets/i18n/it.json index 65565e41e..e2d465484 100644 --- a/apps/web/src/assets/i18n/it.json +++ b/apps/web/src/assets/i18n/it.json @@ -243,7 +243,9 @@ "PORT_PATTERN": "Sono consentite solo cifre", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Tema scuro", diff --git a/apps/web/src/assets/i18n/ja.json b/apps/web/src/assets/i18n/ja.json index 304e31114..87f7651bf 100644 --- a/apps/web/src/assets/i18n/ja.json +++ b/apps/web/src/assets/i18n/ja.json @@ -189,7 +189,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "アプリケーションのリモートコントロールに使用されるポート。デフォルトではポート3000が使用されます。", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "ダークテーマ", diff --git a/apps/web/src/assets/i18n/ko.json b/apps/web/src/assets/i18n/ko.json index 2594f624b..2fce7a5aa 100644 --- a/apps/web/src/assets/i18n/ko.json +++ b/apps/web/src/assets/i18n/ko.json @@ -160,7 +160,9 @@ "REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "어두운 테마", diff --git a/apps/web/src/assets/i18n/nl.json b/apps/web/src/assets/i18n/nl.json index f7f5cb392..63275db95 100644 --- a/apps/web/src/assets/i18n/nl.json +++ b/apps/web/src/assets/i18n/nl.json @@ -201,7 +201,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "Poort voor de afstandsbediening van de applicatie. Standaard wordt poort 3000 gebruikt.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Donker thema", diff --git a/apps/web/src/assets/i18n/pl.json b/apps/web/src/assets/i18n/pl.json index 68ca2acb8..648b0cad8 100644 --- a/apps/web/src/assets/i18n/pl.json +++ b/apps/web/src/assets/i18n/pl.json @@ -201,7 +201,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "Port używany do zdalnego sterowania aplikacją. Domyślnie używany jest port 3000.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Ciemny motyw", diff --git a/apps/web/src/assets/i18n/pt.json b/apps/web/src/assets/i18n/pt.json index b69416f65..848f4937d 100644 --- a/apps/web/src/assets/i18n/pt.json +++ b/apps/web/src/assets/i18n/pt.json @@ -220,7 +220,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "Porta usada para controle remoto do aplicativo. A porta 8765 é usada por padrão.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Tema escuro", diff --git a/apps/web/src/assets/i18n/ru.json b/apps/web/src/assets/i18n/ru.json index 0ff34d62c..1bbc9d008 100644 --- a/apps/web/src/assets/i18n/ru.json +++ b/apps/web/src/assets/i18n/ru.json @@ -299,7 +299,9 @@ "PORT_PATTERN": "Разрешены только цифры", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Тёмная тема", diff --git a/apps/web/src/assets/i18n/tr.json b/apps/web/src/assets/i18n/tr.json index 0c60076c5..763494a4b 100644 --- a/apps/web/src/assets/i18n/tr.json +++ b/apps/web/src/assets/i18n/tr.json @@ -255,7 +255,9 @@ "PORT_PATTERN": "Sadece rakamlara izin verilir", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "Koyu tema", diff --git a/apps/web/src/assets/i18n/zh.json b/apps/web/src/assets/i18n/zh.json index fa00ac73d..b8a6f19b2 100644 --- a/apps/web/src/assets/i18n/zh.json +++ b/apps/web/src/assets/i18n/zh.json @@ -160,7 +160,9 @@ "REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "暗黑模式", diff --git a/apps/web/src/assets/i18n/zhtw.json b/apps/web/src/assets/i18n/zhtw.json index ec61126a3..839947369 100644 --- a/apps/web/src/assets/i18n/zhtw.json +++ b/apps/web/src/assets/i18n/zhtw.json @@ -206,7 +206,9 @@ "REMOTE_CONTROL_PORT_DESCRIPTION": "用於遠端控制應用程式的連接埠。預設使用連接埠 8765。", "REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…", "REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}", - "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again." + "PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.", + "EPG_EMPTY_TITLE": "No EPG sources yet", + "EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels." }, "THEMES": { "DARK_THEME": "深色主題",