mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-09 01:16:15 -08:00
feat: add dashboard settings and startup behavior options to settings component
This commit is contained in:
1 parent
a2e09dacdc
commit
4d047f89ca
11 files changed
+237
-20
No files matched your search
@@ -12,6 +12,7 @@ import { DataService } from 'services';
|
||||
import {
|
||||
Language,
|
||||
Settings,
|
||||
StartupBehavior,
|
||||
STORE_KEY,
|
||||
StreamFormat,
|
||||
Theme,
|
||||
@@ -37,6 +38,8 @@ const DEFAULT_SETTINGS: Settings = {
|
||||
streamFormat: StreamFormat.M3u8StreamFormat,
|
||||
language: Language.ENGLISH,
|
||||
showCaptions: false,
|
||||
showDashboard: true,
|
||||
startupBehavior: StartupBehavior.FirstView,
|
||||
showExternalPlaybackBar: true,
|
||||
theme: Theme.SystemTheme,
|
||||
mpvPlayerPath: '',
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
describe('app routes', () => {
|
||||
let workspaceChildren: Array<{
|
||||
canActivate?: unknown[];
|
||||
data?: Record<string, unknown>;
|
||||
loadComponent?: unknown;
|
||||
path?: string;
|
||||
redirectTo?: unknown;
|
||||
}> = [];
|
||||
|
||||
beforeAll(async () => {
|
||||
@@ -50,4 +52,20 @@ describe('app routes', () => {
|
||||
});
|
||||
expect(typeof globalRecentRoute?.loadComponent).toBe('function');
|
||||
});
|
||||
|
||||
it('uses a dynamic redirect for the default /workspace child route', async () => {
|
||||
const workspaceDefaultRoute = workspaceChildren.find(
|
||||
(route) => route.path === ''
|
||||
);
|
||||
|
||||
expect(typeof workspaceDefaultRoute?.redirectTo).toBe('function');
|
||||
});
|
||||
|
||||
it('protects the dashboard route behind a visibility guard', async () => {
|
||||
const dashboardRoute = workspaceChildren.find(
|
||||
(route) => route.path === 'dashboard'
|
||||
);
|
||||
|
||||
expect(dashboardRoute?.canActivate).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,20 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { Router, Routes } from '@angular/router';
|
||||
import { provideM3uWorkspaceRouteSession } from '@iptvnator/playlist/m3u/feature-player';
|
||||
import { WorkspaceStartupPreferencesService } from '@iptvnator/workspace/shell/util';
|
||||
|
||||
const workspaceEntryRedirect = async () =>
|
||||
inject(WorkspaceStartupPreferencesService).resolveInitialWorkspacePath();
|
||||
|
||||
const dashboardAccessGuard = async () => {
|
||||
const startupPreferences = inject(WorkspaceStartupPreferencesService);
|
||||
const router = inject(Router);
|
||||
const redirectPath = await startupPreferences.resolveDashboardPath();
|
||||
|
||||
return redirectPath === '/workspace/dashboard'
|
||||
? true
|
||||
: router.parseUrl(redirectPath);
|
||||
};
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
@@ -20,10 +35,11 @@ export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
redirectTo: 'dashboard',
|
||||
redirectTo: workspaceEntryRedirect,
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
canActivate: [dashboardAccessGuard],
|
||||
loadComponent: () =>
|
||||
import('workspace-dashboard-feature').then(
|
||||
(c) => c.WorkspaceDashboardComponent
|
||||
|
||||
@@ -119,6 +119,62 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-item__meta">
|
||||
<h4>{{ 'SETTINGS.SHOW_DASHBOARD' | translate }}</h4>
|
||||
<p>
|
||||
{{
|
||||
'SETTINGS.SHOW_DASHBOARD_DESCRIPTION'
|
||||
| translate
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="setting-item__control setting-item__toggle">
|
||||
<mat-checkbox
|
||||
formControlName="showDashboard"
|
||||
data-test-id="toggle-show-dashboard"
|
||||
></mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-item__meta">
|
||||
<h4>{{ 'SETTINGS.STARTUP_BEHAVIOR' | translate }}</h4>
|
||||
<p>
|
||||
{{
|
||||
'SETTINGS.STARTUP_BEHAVIOR_DESCRIPTION'
|
||||
| translate
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="setting-item__control">
|
||||
<mat-form-field
|
||||
appearance="outline"
|
||||
subscriptSizing="dynamic"
|
||||
>
|
||||
<mat-label>{{
|
||||
'SETTINGS.STARTUP_BEHAVIOR' | translate
|
||||
}}</mat-label>
|
||||
<mat-select
|
||||
formControlName="startupBehavior"
|
||||
data-test-id="select-startup-behavior"
|
||||
>
|
||||
@for (
|
||||
option of startupBehaviorOptions;
|
||||
track option.value
|
||||
) {
|
||||
<mat-option
|
||||
[value]="option.value"
|
||||
[attr.data-test-id]="option.value"
|
||||
>
|
||||
{{ option.labelKey | translate }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item">
|
||||
<div class="setting-item__meta">
|
||||
<h4>{{ 'SETTINGS.SHOW_CAPTIONS' | translate }}</h4>
|
||||
|
||||
@@ -28,6 +28,7 @@ import { DialogService } from 'components';
|
||||
import { DataService, PlaylistsService } from 'services';
|
||||
import {
|
||||
Language,
|
||||
StartupBehavior,
|
||||
StreamFormat,
|
||||
Theme,
|
||||
VideoPlayer,
|
||||
@@ -58,6 +59,8 @@ const DEFAULT_SETTINGS = {
|
||||
streamFormat: StreamFormat.M3u8StreamFormat,
|
||||
language: Language.ENGLISH,
|
||||
showCaptions: false,
|
||||
showDashboard: true,
|
||||
startupBehavior: StartupBehavior.FirstView,
|
||||
showExternalPlaybackBar: true,
|
||||
theme: Theme.SystemTheme,
|
||||
mpvPlayerPath: '',
|
||||
@@ -405,6 +408,18 @@ describe('SettingsComponent', () => {
|
||||
expect(component.settingsForm.dirty).toBeTruthy();
|
||||
});
|
||||
|
||||
it('renders workspace startup controls with the expected defaults', () => {
|
||||
const nativeElement = fixture.nativeElement as HTMLElement;
|
||||
|
||||
expect(
|
||||
nativeElement.querySelector('[data-test-id="toggle-show-dashboard"]')
|
||||
).not.toBeNull();
|
||||
expect(component.settingsForm.value.showDashboard).toBe(true);
|
||||
expect(component.settingsForm.value.startupBehavior).toBe(
|
||||
StartupBehavior.FirstView
|
||||
);
|
||||
});
|
||||
|
||||
it('should save settings on submit', async () => {
|
||||
const mockStore = settingsStore as unknown as MockSettingsStore;
|
||||
mockStore.updateSettings.mockResolvedValue(undefined);
|
||||
|
||||
@@ -44,6 +44,7 @@ import { DataService, PlaylistsService } from 'services';
|
||||
import {
|
||||
Language,
|
||||
Playlist,
|
||||
StartupBehavior,
|
||||
StreamFormat,
|
||||
Theme,
|
||||
VideoPlayer,
|
||||
@@ -70,6 +71,11 @@ interface ThemeOption {
|
||||
labelKey: string;
|
||||
}
|
||||
|
||||
interface StartupBehaviorOption {
|
||||
value: StartupBehavior;
|
||||
labelKey: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.scss'],
|
||||
@@ -179,6 +185,17 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
},
|
||||
];
|
||||
|
||||
readonly startupBehaviorOptions: StartupBehaviorOption[] = [
|
||||
{
|
||||
value: StartupBehavior.FirstView,
|
||||
labelKey: 'SETTINGS.STARTUP_BEHAVIOR_FIRST_VIEW',
|
||||
},
|
||||
{
|
||||
value: StartupBehavior.RestoreLastView,
|
||||
labelKey: 'SETTINGS.STARTUP_BEHAVIOR_RESTORE_LAST_VIEW',
|
||||
},
|
||||
];
|
||||
|
||||
/** Settings form object */
|
||||
settingsForm = this.formBuilder.group({
|
||||
player: [VideoPlayer.VideoJs],
|
||||
@@ -186,6 +203,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
streamFormat: StreamFormat.M3u8StreamFormat,
|
||||
language: Language.ENGLISH,
|
||||
showCaptions: false,
|
||||
showDashboard: true,
|
||||
startupBehavior: StartupBehavior.FirstView,
|
||||
showExternalPlaybackBar: true,
|
||||
theme: Theme.SystemTheme,
|
||||
mpvPlayerPath: '',
|
||||
|
||||
@@ -243,6 +243,8 @@
|
||||
"SETTINGS_SAVED": "Einstellungen wurden erfolgreich gespeichert!",
|
||||
"THEME": "Farbdesign",
|
||||
"SHOW_CAPTIONS": "Untertitel anzeigen",
|
||||
"SHOW_DASHBOARD": "Dashboard anzeigen",
|
||||
"SHOW_DASHBOARD_DESCRIPTION": "Dashboard in der Workspace-Leiste verfügbar halten. Wenn deaktiviert, wird Quellen zur ersten Workspace-Seite.",
|
||||
"STREAM_FORMAT_DESCRIPTION": "Standard-Streamformat auswählen (Xtream)",
|
||||
"REMOVE_ALL": "Playlist entfernen",
|
||||
"REMOVE_ALL_BUTTON": "Entfernen",
|
||||
@@ -274,6 +276,10 @@
|
||||
"VLC_PLAYER_PATH_LABEL": "VLC-Pfad",
|
||||
"VLC_PLAYER_PATH_DESCRIPTION": "Legen Sie den Pfad zum VLC-Player in Ihrem System fest. \nEs wird der bereitgestellte Pfad zu einer VLC-Binärdatei anstelle des Standardpfads für unser System verwendet.",
|
||||
"THEME_DESCRIPTION": "Wählen Sie das visuelle Thema der Anwendung aus",
|
||||
"STARTUP_BEHAVIOR": "Startansicht",
|
||||
"STARTUP_BEHAVIOR_DESCRIPTION": "Legen Sie fest, ob IPTVnator die erste verfügbare Workspace-Ansicht oder Ihre zuletzt geöffnete Abschnittsansicht startet. Erste Ansicht bedeutet Dashboard, wenn aktiviert, sonst Quellen.",
|
||||
"STARTUP_BEHAVIOR_FIRST_VIEW": "Erste verfügbare Ansicht",
|
||||
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Letzte Ansicht wiederherstellen",
|
||||
"EPG_NOTE": "Derzeit ist EPG nur in der Electron-basierten Version von IPTVnator verfügbar.",
|
||||
"VLC_PLAYER_PATH": "VLC-Playerpfad",
|
||||
"IMPORT_EXPORT_DATA_DESCRIPTION": "Exportieren oder importieren Sie Wiedergabelisten im JSON-Format, das in der Anwendung verwendet wird.",
|
||||
@@ -398,10 +404,18 @@
|
||||
"COPY_STREAM_URL": "Stream-URL kopieren",
|
||||
"ERROR_VIEW": {
|
||||
"DELETE": "Löschen",
|
||||
"IMPORT_CANCELLED": {
|
||||
"TITLE": "Import abgebrochen",
|
||||
"DESCRIPTION": "Der Playlist-Import wurde abgebrochen. Wiederholen Sie ihn, wenn Sie diese Quelle erneut laden möchten."
|
||||
},
|
||||
"ACCOUNT_EXPIRED": {
|
||||
"TITLE": "Konto abgelaufen",
|
||||
"DESCRIPTION": "Dieses Konto ist abgelaufen. \nBitte überprüfen Sie die Anmeldeinformationen in den Playlist-Einstellungen oder entfernen Sie sie."
|
||||
},
|
||||
"ACCOUNT_INACTIVE": {
|
||||
"TITLE": "Konto inaktiv",
|
||||
"DESCRIPTION": "Dieses Konto ist inaktiv. Bitte überprüfen Sie die Anmeldeinformationen in den Playlist-Einstellungen oder entfernen Sie es."
|
||||
},
|
||||
"HOME": "Startseite",
|
||||
"EMPTY_CATEGORY": {
|
||||
"TITLE": "Leere Kategorie",
|
||||
@@ -419,6 +433,10 @@
|
||||
"TITLE": "Portal nicht gefunden",
|
||||
"DESCRIPTION": "Bitte überprüfen Sie die Anmeldeinformationen und die Portal-URL in den Playlist-Einstellungen oder entfernen Sie sie."
|
||||
},
|
||||
"PORTAL_UNAVAILABLE": {
|
||||
"TITLE": "Portal nicht erreichbar",
|
||||
"DESCRIPTION": "Das Portal konnte nicht erreicht werden. Überprüfen Sie die Server-URL oder versuchen Sie es erneut, wenn die Quelle wieder verfügbar ist."
|
||||
},
|
||||
"UNKNOWN_ERROR": {
|
||||
"TITLE": "Etwas ist schief gelaufen",
|
||||
"DESCRIPTION": "Unbekannter Fehler, bitte versuchen Sie es später noch einmal"
|
||||
@@ -590,6 +608,7 @@
|
||||
"RAIL_DASHBOARD": "Dashboard",
|
||||
"OPEN_DASHBOARD": "Dashboard öffnen",
|
||||
"RAIL_SOURCES": "Quellen",
|
||||
"OPEN_SOURCES": "Quellen öffnen",
|
||||
"RAIL_SETTINGS": "Einstellungen",
|
||||
"OPEN_SETTINGS": "Einstellungen öffnen",
|
||||
"RAIL_LIBRARY": "Bibliothek",
|
||||
@@ -620,6 +639,7 @@
|
||||
"NO_SECTION_ACTIONS": "Keine Aktionen für diesen Abschnitt",
|
||||
"PLAYLIST_INFO": "Playlist-Info",
|
||||
"ACCOUNT_INFO": "Kontoinfo",
|
||||
"REFRESH_PLAYLIST": "Playlist aktualisieren",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Abgeschlossene Downloads löschen (alle Playlists)",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Abgeschlossene Downloads für alle Playlists löschen",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Abgeschlossene Downloads löschen (diese Playlist)",
|
||||
@@ -632,12 +652,18 @@
|
||||
"NO_SOURCES_AVAILABLE": "Keine Quellen verfügbar",
|
||||
"ONE_SOURCE_AVAILABLE": "1 Quelle verfügbar",
|
||||
"SOURCES_AVAILABLE": "{{count}} Quellen verfügbar",
|
||||
"XTREAM_IMPORT_PREPARING": "Playlist-Daten werden vorbereitet...",
|
||||
"XTREAM_IMPORT_SAVING": "Playlist-Inhalte werden gespeichert...",
|
||||
"XTREAM_IMPORT_RESTORING_FAVORITES": "Favoriten werden wiederhergestellt...",
|
||||
"XTREAM_IMPORT_RESTORING_RECENT": "Zuletzt angesehene Inhalte werden wiederhergestellt...",
|
||||
"XTREAM_IMPORT_CANCEL": "Import abbrechen",
|
||||
"XTREAM_IMPORT_CANCELLING": "Import wird abgebrochen...",
|
||||
"XTREAM_IMPORT_TITLE": "Playlist wird synchronisiert",
|
||||
"XTREAM_IMPORT_REMOTE_BADGE": "Remote-Quelle",
|
||||
"XTREAM_IMPORT_LOCAL_BADGE": "Lokale Bibliothek",
|
||||
"XTREAM_IMPORT_DETAIL_REMOTE": "Warte auf die Antwort des Providers.",
|
||||
"XTREAM_IMPORT_DETAIL_LOCAL": "Bereitet schnellere Playlist-Wechsel für den nächsten Besuch vor.",
|
||||
"XTREAM_IMPORT_PREPARING": "Lokale Bibliothek wird vorbereitet...",
|
||||
"XTREAM_IMPORT_LOADING": "Playlist-Daten werden von der Quelle geladen...",
|
||||
"XTREAM_IMPORT_SAVING": "Playlist-Daten werden lokal gespeichert...",
|
||||
"XTREAM_IMPORT_RESTORING_FAVORITES": "Favoriten werden aus der lokalen Bibliothek wiederhergestellt...",
|
||||
"XTREAM_IMPORT_RESTORING_RECENT": "Zuletzt angesehene Inhalte werden aus der lokalen Bibliothek wiederhergestellt...",
|
||||
"XTREAM_IMPORT_CANCEL": "Synchronisierung stoppen",
|
||||
"XTREAM_IMPORT_CANCELLING": "Synchronisierung wird gestoppt...",
|
||||
"COMMANDS": {
|
||||
"GLOBAL_SEARCH_LABEL": "Alle Xtream-Playlists durchsuchen",
|
||||
"GLOBAL_SEARCH_DESCRIPTION": "Globale Suchüberlagerung öffnen",
|
||||
|
||||
@@ -200,6 +200,8 @@
|
||||
"SETTINGS_SAVED": "Success! Configuration was saved.",
|
||||
"THEME": "Visual theme",
|
||||
"SHOW_CAPTIONS": "Show subtitles",
|
||||
"SHOW_DASHBOARD": "Show dashboard",
|
||||
"SHOW_DASHBOARD_DESCRIPTION": "Keep Dashboard available in the workspace rail. When disabled, Sources becomes the first workspace page.",
|
||||
"ADD_EPG_SOURCE": "Add EPG source",
|
||||
"CLEAR_EPG_DATA": "Clear EPG data",
|
||||
"CLEAR_EPG_DIALOG": {
|
||||
@@ -212,6 +214,10 @@
|
||||
"STREAM_FORMAT_DESCRIPTION": "Select default stream format (xtream)",
|
||||
"LANGUAGE_DESCRIPTION": "Select language of the application",
|
||||
"THEME_DESCRIPTION": "Select visual theme of the application",
|
||||
"STARTUP_BEHAVIOR": "Startup view",
|
||||
"STARTUP_BEHAVIOR_DESCRIPTION": "Choose whether IPTVnator opens the first available workspace view or restores your last section-level view. First view means Dashboard when enabled, otherwise Sources.",
|
||||
"STARTUP_BEHAVIOR_FIRST_VIEW": "First available view",
|
||||
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Restore last view",
|
||||
"SHOW_CAPTIONS_DESCRIPTION": "Show or hide subtitles by default",
|
||||
"SHOW_EXTERNAL_PLAYBACK_BAR": "Show now playing footer",
|
||||
"SHOW_EXTERNAL_PLAYBACK_BAR_DESCRIPTION": "Keep the external-player status bar visible at the bottom of the workspace on desktop.",
|
||||
@@ -469,10 +475,18 @@
|
||||
"ACCOUNT_INFO": "Account info"
|
||||
},
|
||||
"ERROR_VIEW": {
|
||||
"IMPORT_CANCELLED": {
|
||||
"TITLE": "Import cancelled",
|
||||
"DESCRIPTION": "The playlist import was cancelled. Retry when you want to continue loading this source."
|
||||
},
|
||||
"ACCOUNT_EXPIRED": {
|
||||
"TITLE": "Account expired",
|
||||
"DESCRIPTION": "This account has been expired. Please check the credentials in playlist settings or remove it."
|
||||
},
|
||||
"ACCOUNT_INACTIVE": {
|
||||
"TITLE": "Account inactive",
|
||||
"DESCRIPTION": "This account is inactive. Please check the credentials in playlist settings or remove it."
|
||||
},
|
||||
"UNAUTHORIZED": {
|
||||
"TITLE": "Unauthorized",
|
||||
"DESCRIPTION": "Please check the credentials in playlist settings or remove it."
|
||||
@@ -481,6 +495,10 @@
|
||||
"TITLE": "Portal not found",
|
||||
"DESCRIPTION": "Please check the credentials and portal url in playlist settings or remove it."
|
||||
},
|
||||
"PORTAL_UNAVAILABLE": {
|
||||
"TITLE": "Portal unavailable",
|
||||
"DESCRIPTION": "The portal could not be reached. Check the server URL or retry when the source is available again."
|
||||
},
|
||||
"EMPTY_CATEGORY": {
|
||||
"TITLE": "No content in this category",
|
||||
"DESCRIPTION": "Select another category or switch the content type."
|
||||
@@ -661,6 +679,7 @@
|
||||
"RAIL_DASHBOARD": "Dashboard",
|
||||
"OPEN_DASHBOARD": "Open dashboard",
|
||||
"RAIL_SOURCES": "Sources",
|
||||
"OPEN_SOURCES": "Open sources",
|
||||
"RAIL_SETTINGS": "Settings",
|
||||
"OPEN_SETTINGS": "Open settings",
|
||||
"RAIL_LIBRARY": "Library",
|
||||
@@ -691,6 +710,7 @@
|
||||
"NO_SECTION_ACTIONS": "No actions for this section",
|
||||
"PLAYLIST_INFO": "Playlist info",
|
||||
"ACCOUNT_INFO": "Account info",
|
||||
"REFRESH_PLAYLIST": "Refresh playlist",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Clear completed downloads (all playlists)",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Clear completed downloads for all playlists",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Clear completed downloads (this playlist)",
|
||||
@@ -703,12 +723,18 @@
|
||||
"NO_SOURCES_AVAILABLE": "No sources available",
|
||||
"ONE_SOURCE_AVAILABLE": "1 source available",
|
||||
"SOURCES_AVAILABLE": "{{count}} sources available",
|
||||
"XTREAM_IMPORT_PREPARING": "Preparing playlist data...",
|
||||
"XTREAM_IMPORT_SAVING": "Saving playlist content...",
|
||||
"XTREAM_IMPORT_RESTORING_FAVORITES": "Restoring favorites...",
|
||||
"XTREAM_IMPORT_RESTORING_RECENT": "Restoring recently viewed...",
|
||||
"XTREAM_IMPORT_CANCEL": "Cancel import",
|
||||
"XTREAM_IMPORT_CANCELLING": "Cancelling import...",
|
||||
"XTREAM_IMPORT_TITLE": "Syncing playlist",
|
||||
"XTREAM_IMPORT_REMOTE_BADGE": "Remote source",
|
||||
"XTREAM_IMPORT_LOCAL_BADGE": "Local library",
|
||||
"XTREAM_IMPORT_DETAIL_REMOTE": "Waiting on the provider response.",
|
||||
"XTREAM_IMPORT_DETAIL_LOCAL": "Preparing faster playlist switching for the next visit.",
|
||||
"XTREAM_IMPORT_PREPARING": "Preparing local library...",
|
||||
"XTREAM_IMPORT_LOADING": "Fetching playlist data from source...",
|
||||
"XTREAM_IMPORT_SAVING": "Saving playlist data locally...",
|
||||
"XTREAM_IMPORT_RESTORING_FAVORITES": "Restoring favorites from local library...",
|
||||
"XTREAM_IMPORT_RESTORING_RECENT": "Restoring recently viewed from local library...",
|
||||
"XTREAM_IMPORT_CANCEL": "Stop sync",
|
||||
"XTREAM_IMPORT_CANCELLING": "Stopping sync...",
|
||||
"COMMANDS": {
|
||||
"GLOBAL_SEARCH_LABEL": "Search all Xtream playlists",
|
||||
"GLOBAL_SEARCH_DESCRIPTION": "Open global search overlay",
|
||||
|
||||
@@ -181,6 +181,8 @@
|
||||
"SETTINGS_SAVED": "Новые настройки были успешно сохранены!",
|
||||
"THEME": "Тема оформления",
|
||||
"SHOW_CAPTIONS": "Отображать субтитры",
|
||||
"SHOW_DASHBOARD": "Показывать панель",
|
||||
"SHOW_DASHBOARD_DESCRIPTION": "Оставить Dashboard доступным в боковой панели рабочего пространства. Если отключить, первой страницей будет Источники.",
|
||||
"ADD_EPG_SOURCE": "Добавить источник EPG",
|
||||
"CLEAR_EPG_DATA": "Очистить данные EPG",
|
||||
"CLEAR_EPG_DIALOG": {
|
||||
@@ -193,6 +195,10 @@
|
||||
"STREAM_FORMAT_DESCRIPTION": "Выбрать формат потока по умолчанию (Xtream)",
|
||||
"LANGUAGE_DESCRIPTION": "Выбрать язык приложения",
|
||||
"THEME_DESCRIPTION": "Выбрать визуальную тему оформления",
|
||||
"STARTUP_BEHAVIOR": "Начальный экран",
|
||||
"STARTUP_BEHAVIOR_DESCRIPTION": "Выберите, должен ли IPTVnator открывать первый доступный экран рабочего пространства или восстанавливать последний экран уровня раздела. Первый экран означает Dashboard, если он включён, иначе Источники.",
|
||||
"STARTUP_BEHAVIOR_FIRST_VIEW": "Первый доступный экран",
|
||||
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Восстановить последний экран",
|
||||
"SHOW_CAPTIONS_DESCRIPTION": "Показать или скрыть субтитры по умолчанию.",
|
||||
"VERSION_DESCRIPTION": "Текущая версия приложения",
|
||||
"EPG_NOTE": "На данный момент EPG доступен только в нативной версии IPTVnator.",
|
||||
@@ -393,10 +399,18 @@
|
||||
"COPY_STREAM_URL": "Копировать URL-адрес потока",
|
||||
"ERROR_VIEW": {
|
||||
"DELETE": "Удалить",
|
||||
"IMPORT_CANCELLED": {
|
||||
"TITLE": "Импорт отменён",
|
||||
"DESCRIPTION": "Импорт плейлиста был отменён. Повторите попытку, когда захотите снова загрузить этот источник."
|
||||
},
|
||||
"ACCOUNT_EXPIRED": {
|
||||
"TITLE": "Срок действия учетной записи истек",
|
||||
"DESCRIPTION": "Срок действия этой учетной записи истек. \nПожалуйста, проверьте учетные данные в настройках плейлиста или удалите его."
|
||||
},
|
||||
"ACCOUNT_INACTIVE": {
|
||||
"TITLE": "Учётная запись неактивна",
|
||||
"DESCRIPTION": "Эта учётная запись неактивна. Проверьте учётные данные в настройках плейлиста или удалите источник."
|
||||
},
|
||||
"HOME": "На главную",
|
||||
"EMPTY_CATEGORY": {
|
||||
"TITLE": "Пустая категория",
|
||||
@@ -410,6 +424,10 @@
|
||||
"TITLE": "Портал не найден",
|
||||
"DESCRIPTION": "Пожалуйста, проверьте учетные данные и URL портала в настройках плейлиста или удалите его."
|
||||
},
|
||||
"PORTAL_UNAVAILABLE": {
|
||||
"TITLE": "Портал недоступен",
|
||||
"DESCRIPTION": "Не удалось подключиться к порталу. Проверьте URL сервера или повторите попытку позже."
|
||||
},
|
||||
"NO_CATEGORY_SELECTED": {
|
||||
"TITLE": "Категория не выбрана",
|
||||
"DESCRIPTION": "Пожалуйста, выберите категорию для просмотра содержимого"
|
||||
@@ -567,6 +585,7 @@
|
||||
"RAIL_DASHBOARD": "Панель",
|
||||
"OPEN_DASHBOARD": "Открыть панель",
|
||||
"RAIL_SOURCES": "Источники",
|
||||
"OPEN_SOURCES": "Открыть источники",
|
||||
"RAIL_SETTINGS": "Настройки",
|
||||
"OPEN_SETTINGS": "Открыть настройки",
|
||||
"RAIL_LIBRARY": "Библиотека",
|
||||
@@ -597,6 +616,7 @@
|
||||
"NO_SECTION_ACTIONS": "Для этого раздела нет действий",
|
||||
"PLAYLIST_INFO": "Информация о плейлисте",
|
||||
"ACCOUNT_INFO": "Информация об аккаунте",
|
||||
"REFRESH_PLAYLIST": "Обновить плейлист",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Очистить завершенные загрузки (все плейлисты)",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Очистить завершенные загрузки для всех плейлистов",
|
||||
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Очистить завершенные загрузки (этот плейлист)",
|
||||
@@ -609,12 +629,18 @@
|
||||
"NO_SOURCES_AVAILABLE": "Нет доступных источников",
|
||||
"ONE_SOURCE_AVAILABLE": "Доступен 1 источник",
|
||||
"SOURCES_AVAILABLE": "Доступно источников: {{count}}",
|
||||
"XTREAM_IMPORT_PREPARING": "Подготовка данных плейлиста...",
|
||||
"XTREAM_IMPORT_SAVING": "Сохранение контента плейлиста...",
|
||||
"XTREAM_IMPORT_RESTORING_FAVORITES": "Восстановление избранного...",
|
||||
"XTREAM_IMPORT_RESTORING_RECENT": "Восстановление недавно просмотренного...",
|
||||
"XTREAM_IMPORT_CANCEL": "Отменить импорт",
|
||||
"XTREAM_IMPORT_CANCELLING": "Отмена импорта...",
|
||||
"XTREAM_IMPORT_TITLE": "Синхронизация плейлиста",
|
||||
"XTREAM_IMPORT_REMOTE_BADGE": "Удалённый источник",
|
||||
"XTREAM_IMPORT_LOCAL_BADGE": "Локальная библиотека",
|
||||
"XTREAM_IMPORT_DETAIL_REMOTE": "Ожидание ответа от провайдера.",
|
||||
"XTREAM_IMPORT_DETAIL_LOCAL": "Подготавливает более быстрые переключения плейлиста при следующем открытии.",
|
||||
"XTREAM_IMPORT_PREPARING": "Подготовка локальной библиотеки...",
|
||||
"XTREAM_IMPORT_LOADING": "Получение данных плейлиста из источника...",
|
||||
"XTREAM_IMPORT_SAVING": "Сохранение данных плейлиста локально...",
|
||||
"XTREAM_IMPORT_RESTORING_FAVORITES": "Восстановление избранного из локальной библиотеки...",
|
||||
"XTREAM_IMPORT_RESTORING_RECENT": "Восстановление недавно просмотренного из локальной библиотеки...",
|
||||
"XTREAM_IMPORT_CANCEL": "Остановить синхронизацию",
|
||||
"XTREAM_IMPORT_CANCELLING": "Остановка синхронизации...",
|
||||
"COMMANDS": {
|
||||
"GLOBAL_SEARCH_LABEL": "Искать во всех плейлистах Xtream",
|
||||
"GLOBAL_SEARCH_DESCRIPTION": "Открыть глобальный поиск",
|
||||
|
||||
@@ -11,6 +11,7 @@ import { firstValueFrom } from 'rxjs';
|
||||
import {
|
||||
Language,
|
||||
Settings,
|
||||
StartupBehavior,
|
||||
STORE_KEY,
|
||||
StreamFormat,
|
||||
Theme,
|
||||
@@ -22,6 +23,8 @@ const DEFAULT_SETTINGS: Settings = {
|
||||
streamFormat: StreamFormat.M3u8StreamFormat,
|
||||
language: Language.ENGLISH,
|
||||
showCaptions: false,
|
||||
showDashboard: true,
|
||||
startupBehavior: StartupBehavior.FirstView,
|
||||
showExternalPlaybackBar: true,
|
||||
theme: Theme.SystemTheme,
|
||||
mpvPlayerPath: '',
|
||||
@@ -74,6 +77,8 @@ export const SettingsStore = signalStore(
|
||||
streamFormat: store.streamFormat(),
|
||||
language: store.language(),
|
||||
showCaptions: store.showCaptions(),
|
||||
showDashboard: store.showDashboard(),
|
||||
startupBehavior: store.startupBehavior(),
|
||||
showExternalPlaybackBar: store.showExternalPlaybackBar(),
|
||||
theme: store.theme(),
|
||||
mpvPlayerPath: store.mpvPlayerPath(),
|
||||
|
||||
@@ -13,6 +13,11 @@ export enum VideoPlayer {
|
||||
ArtPlayer = 'artplayer',
|
||||
}
|
||||
|
||||
export enum StartupBehavior {
|
||||
FirstView = 'first-view',
|
||||
RestoreLastView = 'restore-last-view',
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes all available settings options of the application
|
||||
*/
|
||||
@@ -22,6 +27,8 @@ export interface Settings {
|
||||
streamFormat: StreamFormat;
|
||||
language: Language;
|
||||
showCaptions: boolean;
|
||||
showDashboard: boolean;
|
||||
startupBehavior: StartupBehavior;
|
||||
/** Show the desktop footer bar for external playback status */
|
||||
showExternalPlaybackBar?: boolean;
|
||||
theme: Theme;
|
||||
|
||||
Reference in new issue
Block a user