refactor(settings): add backup and reset functionality with UI updates

Entire-Checkpoint: c6e522b4276c
This commit is contained in:
4gray committed 2026-04-25 23:03:50 +02:00
1 parent e53a25f441
commit 58ee06bb2b
21 files changed
+371 -96

No files matched your search

@@ -476,7 +476,6 @@
}
<button
mat-icon-button
color="accent"
[matTooltip]="
'SETTINGS.REFRESH_EPG'
| translate
@@ -495,7 +494,6 @@
</button>
<button
mat-icon-button
color="accent"
[matTooltip]="
'SETTINGS.REMOVE_EPG_SOURCE'
| translate
@@ -517,10 +515,10 @@
<div class="inline-actions">
<button
mat-button
color="accent"
type="button"
(click)="addEpgSource()"
>
<mat-icon>add</mat-icon>
{{ 'SETTINGS.ADD_EPG_SOURCE' | translate }}
</button>
<button
@@ -752,20 +750,17 @@
<section
class="settings-group"
[class.settings-group--active]="activeSection() === 'data'"
id="data"
[class.settings-group--active]="activeSection() === 'backup'"
id="backup"
>
<header class="settings-group__header">
<div class="settings-group__header-icon">
<mat-icon>sync_alt</mat-icon>
<mat-icon>backup</mat-icon>
</div>
<div class="settings-group__header-text">
<h3>{{ 'SETTINGS.DATA' | translate }}</h3>
<h3>{{ 'SETTINGS.BACKUP' | translate }}</h3>
<p>
{{
'SETTINGS.IMPORT_EXPORT_DATA_DESCRIPTION'
| translate
}}
{{ 'SETTINGS.BACKUP_DESCRIPTION' | translate }}
</p>
</div>
</header>
@@ -829,39 +824,45 @@
</div>
</div>
<div class="setting-item danger-zone">
<div class="setting-item__meta">
<h4>{{ 'SETTINGS.REMOVE_ALL' | translate }}</h4>
<p>
{{ 'SETTINGS.REMOVE_ALL_DESCRIPTION' | translate }}
</p>
<div class="danger-zone__summary" aria-live="polite">
<span class="danger-zone__summary-pill">
{{ 'HOME.PLAYLIST_TYPES.M3U' | translate }}
<strong>{{
playlistDeleteSummary().m3u
}}</strong>
</span>
<span class="danger-zone__summary-pill">
{{ 'HOME.PLAYLIST_TYPES.XTREAM' | translate }}
<strong>{{
playlistDeleteSummary().xtream
}}</strong>
</span>
<span class="danger-zone__summary-pill">
{{ 'HOME.PLAYLIST_TYPES.STALKER' | translate }}
<strong>{{
playlistDeleteSummary().stalker
}}</strong>
</span>
</div>
@if (removeAllProgressLabel(); as progressLabel) {
<p class="danger-zone__progress">
{{ progressLabel }}
</p>
}
@if (isPwa) {
<div class="settings-note">
{{ 'SETTINGS.EPG_NOTE' | translate }}
&nbsp;<a
href="https://github.com/4gray/iptvnator/releases"
target="_blank"
rel="noreferrer"
>{{ 'SETTINGS.EPG_NOTE_URL_TEXT' | translate }}</a
>
</div>
<div class="setting-item__control">
}
</section>
<section
class="settings-group"
[class.settings-group--active]="activeSection() === 'reset'"
id="reset"
>
<header class="settings-group__header">
<div class="settings-group__header-icon">
<mat-icon>delete_sweep</mat-icon>
</div>
<div class="settings-group__header-text">
<h3>{{ 'SETTINGS.RESET' | translate }}</h3>
<p>{{ 'SETTINGS.RESET_DESCRIPTION' | translate }}</p>
</div>
</header>
<div class="setting-item danger-zone">
<div class="danger-zone__header">
<div class="setting-item__meta">
<h4>{{ 'SETTINGS.REMOVE_ALL' | translate }}</h4>
<p>
{{
'SETTINGS.REMOVE_ALL_DESCRIPTION'
| translate
}}
</p>
</div>
<button
mat-button
class="danger-zone__button"
@@ -894,19 +895,47 @@
}
</button>
</div>
</div>
@if (isPwa) {
<div class="settings-note">
{{ 'SETTINGS.EPG_NOTE' | translate }}
&nbsp;<a
href="https://github.com/4gray/iptvnator/releases"
target="_blank"
rel="noreferrer"
>{{ 'SETTINGS.EPG_NOTE_URL_TEXT' | translate }}</a
>
<div class="danger-zone__summary" aria-live="polite">
<span class="danger-zone__summary-pill">
<mat-icon class="danger-zone__summary-icon"
>folder_open</mat-icon
>
<span class="danger-zone__summary-label">{{
'HOME.PLAYLIST_TYPES.M3U' | translate
}}</span>
<span class="danger-zone__summary-count">{{
playlistDeleteSummary().m3u
}}</span>
</span>
<span class="danger-zone__summary-pill">
<mat-icon class="danger-zone__summary-icon"
>cloud</mat-icon
>
<span class="danger-zone__summary-label">{{
'HOME.PLAYLIST_TYPES.XTREAM' | translate
}}</span>
<span class="danger-zone__summary-count">{{
playlistDeleteSummary().xtream
}}</span>
</span>
<span class="danger-zone__summary-pill">
<mat-icon class="danger-zone__summary-icon"
>cast</mat-icon
>
<span class="danger-zone__summary-label">{{
'HOME.PLAYLIST_TYPES.STALKER' | translate
}}</span>
<span class="danger-zone__summary-count">{{
playlistDeleteSummary().stalker
}}</span>
</span>
</div>
}
@if (removeAllProgressLabel(); as progressLabel) {
<p class="danger-zone__progress">
{{ progressLabel }}
</p>
}
</div>
</section>
<section
@@ -1116,7 +1145,6 @@
<button
mat-button
type="button"
color="accent"
(click)="backToHome()"
data-test-id="back-to-home"
>
@@ -1126,8 +1154,8 @@
}
<button
mat-flat-button
color="accent"
type="submit"
class="settings-save-button"
[disabled]="settingsForm.pristine || !settingsForm.valid"
data-test-id="save-settings"
>
@@ -32,11 +32,10 @@
}
.settings-page-header {
padding: 14px 18px;
border: 1px solid var(--settings-page-header-border);
border-radius: 18px;
background: var(--settings-page-header-bg);
box-shadow: var(--settings-page-header-shadow);
padding: 14px 18px 8px;
background: transparent;
border: 0;
box-shadow: none;
}
.settings-page-header__text {
@@ -590,46 +589,91 @@
background: var(--settings-item-danger-bg);
border: 1px solid var(--settings-item-danger-border);
border-radius: 16px;
grid-template-columns: 1fr;
gap: 14px;
}
.danger-zone__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
.setting-item__meta {
flex: 1;
min-width: 0;
}
}
.danger-zone__summary {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
margin: 0;
}
.danger-zone__summary-pill {
display: inline-flex;
align-items: center;
gap: 8px;
min-height: 32px;
padding: 6px 10px;
border-radius: 999px;
min-height: 34px;
padding: 4px 6px 4px 12px;
border-radius: 12px;
background: color-mix(
in srgb,
var(--mat-sys-surface-container-high) 78%,
transparent
);
border: 1px solid
color-mix(in srgb, var(--settings-item-danger-border) 72%, transparent);
color-mix(in srgb, var(--settings-item-danger-border) 60%, transparent);
font-size: 0.82rem;
line-height: 1.2;
color: var(--mat-sys-on-surface);
strong {
.danger-zone__summary-icon {
font-size: 18px;
width: 18px;
height: 18px;
color: var(--mat-sys-on-surface-variant);
flex-shrink: 0;
}
.danger-zone__summary-label {
font-weight: 500;
letter-spacing: 0.01em;
}
.danger-zone__summary-count {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 26px;
height: 22px;
padding: 0 8px;
border-radius: 999px;
background: color-mix(
in srgb,
var(--mat-sys-on-surface) 10%,
transparent
);
color: var(--mat-sys-on-surface);
font-size: 0.78rem;
font-weight: 700;
font-variant-numeric: tabular-nums;
margin-left: 2px;
}
}
.danger-zone__progress {
margin-top: 12px;
margin-bottom: 0;
margin: 0;
color: var(--mat-sys-on-surface-variant);
font-size: 0.84rem;
}
.danger-zone__button {
min-width: 138px;
flex-shrink: 0;
align-self: flex-start;
}
.danger-zone__button--busy {
@@ -670,6 +714,46 @@
justify-content: space-between;
}
.settings-save-button.mat-mdc-button-base {
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
color: #fff;
font-weight: 500;
padding: 0 20px;
border-radius: 10px;
box-shadow: 0 4px 14px rgba(59, 130, 246, 0.28);
transition:
transform 0.2s ease,
box-shadow 0.2s ease,
opacity 0.2s ease;
mat-icon {
margin-right: 6px;
}
&:hover:not([disabled]) {
transform: translateY(-1px);
box-shadow: 0 6px 18px rgba(59, 130, 246, 0.38);
}
&:active:not([disabled]) {
transform: translateY(0);
}
&[disabled] {
background: color-mix(
in srgb,
var(--mat-sys-on-surface) 12%,
transparent
);
color: color-mix(
in srgb,
var(--mat-sys-on-surface) 38%,
transparent
);
box-shadow: none;
}
}
@media (max-width: 1100px) {
.settings-layout {
max-width: 100%;
@@ -55,6 +55,7 @@ import {
PlaylistsService,
} from 'services';
import {
EmbeddedMpvSupport,
Language,
StartupBehavior,
StreamFormat,
@@ -150,13 +151,25 @@ export class SettingsComponent implements OnInit, OnDestroy {
/** Flag that indicates whether the app runs in electron environment */
readonly isDesktop = !!window.electron;
readonly embeddedMpvSupport = signal<EmbeddedMpvSupport | null>(null);
readonly supportsEmbeddedMpv = computed(
() => this.isDesktop && !!this.embeddedMpvSupport()?.supported
);
isPwa = this.dataService.getAppEnvironment() === 'pwa';
private readonly settingsCtx = inject(SettingsContextService);
readonly activeSection = this.settingsCtx.activeSection;
readonly osPlayers = [
readonly osPlayers = computed(() => [
...(this.supportsEmbeddedMpv()
? [
{
id: VideoPlayer.EmbeddedMpv,
labelKey: 'SETTINGS.PLAYER_EMBEDDED_MPV',
},
]
: []),
{
id: VideoPlayer.MPV,
labelKey: 'SETTINGS.PLAYER_MPV',
@@ -165,10 +178,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
id: VideoPlayer.VLC,
labelKey: 'SETTINGS.PLAYER_VLC',
},
];
]);
/** Player options */
readonly players = [
readonly players = computed(() => [
{
id: VideoPlayer.Html5Player,
labelKey: 'SETTINGS.PLAYER_HTML5',
@@ -181,8 +194,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
id: VideoPlayer.ArtPlayer,
labelKey: 'SETTINGS.PLAYER_ARTPLAYER',
},
...(this.isDesktop ? this.osPlayers : []),
];
...(this.isDesktop ? this.osPlayers() : []),
]);
/** Current version of the app */
version: string;
@@ -296,9 +309,15 @@ export class SettingsComponent implements OnInit, OnDestroy {
visible: this.isDesktop,
},
{
id: 'data',
label: 'SETTINGS.NAV_DATA',
icon: 'swap_horiz',
id: 'backup',
label: 'SETTINGS.NAV_BACKUP',
icon: 'backup',
visible: true,
},
{
id: 'reset',
label: 'SETTINGS.NAV_RESET',
icon: 'delete_sweep',
visible: true,
},
{
@@ -418,8 +437,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
// Wait for settings to load before setting the form
await this.settingsStore.loadSettings();
this.setSettings();
void this.loadEmbeddedMpvSupport();
this.checkAppVersion();
this.fetchLocalIpAddresses();
void this.fetchLocalIpAddresses();
if (!this.isDialog) {
this.settingsCtx.setSections(this.sectionNav);
@@ -428,6 +448,41 @@ export class SettingsComponent implements OnInit, OnDestroy {
requestAnimationFrame(() => this.setupSectionObserver());
}
private async loadEmbeddedMpvSupport(): Promise<void> {
if (!this.isDesktop) {
this.embeddedMpvSupport.set({
supported: false,
platform: 'web',
reason: 'Embedded MPV requires the Electron desktop build.',
});
return;
}
if (!window.electron?.getEmbeddedMpvSupport) {
this.embeddedMpvSupport.set({
supported: false,
platform: window.electron.platform,
reason: 'Embedded MPV support is not available in this build.',
});
return;
}
try {
this.embeddedMpvSupport.set(
await window.electron.getEmbeddedMpvSupport()
);
} catch (error) {
this.embeddedMpvSupport.set({
supported: false,
platform: window.electron.platform,
reason:
error instanceof Error
? error.message
: String(error),
});
}
}
ngOnDestroy(): void {
this.cancelPendingScrollTargetClear();
this.sectionObserver?.disconnect();
+7 -1
View File
@@ -211,7 +211,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "السمة الداكنة",
+7 -1
View File
@@ -203,7 +203,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "المظهر الداكن",
+7 -1
View File
@@ -205,7 +205,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Цёмная тэма",
+7 -1
View File
@@ -378,7 +378,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Dunkel",
+7 -1
View File
@@ -256,7 +256,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Σκούρο θέμα",
+6
View File
@@ -203,12 +203,18 @@
"EPG_EMPTY_TITLE": "No EPG sources yet",
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"DATA": "Data",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"ABOUT": "About",
"NAV_GENERAL": "General",
"NAV_PLAYBACK": "Playback",
"NAV_EPG": "EPG",
"NAV_REMOTE": "Remote",
"NAV_DATA": "Data",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset",
"NAV_ABOUT": "About",
"APP_PREFERENCES": "App preferences",
"HERO_EYEBROW": "Workspace settings",
+7 -1
View File
@@ -233,7 +233,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Tema oscuro",
+7 -1
View File
@@ -224,7 +224,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Thème foncé",
+7 -1
View File
@@ -245,7 +245,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Tema scuro",
+7 -1
View File
@@ -191,7 +191,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "ダークテーマ",
+7 -1
View File
@@ -162,7 +162,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "어두운 테마",
+7 -1
View File
@@ -203,7 +203,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Donker thema",
+7 -1
View File
@@ -203,7 +203,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Ciemny motyw",
+7 -1
View File
@@ -222,7 +222,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Tema escuro",
+7 -1
View File
@@ -301,7 +301,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Тёмная тема",
+7 -1
View File
@@ -257,7 +257,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "Koyu tema",
+7 -1
View File
@@ -162,7 +162,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "暗黑模式",
+7 -1
View File
@@ -208,7 +208,13 @@
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"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."
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
"BACKUP": "Backup",
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
"RESET": "Reset",
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
"NAV_BACKUP": "Backup",
"NAV_RESET": "Reset"
},
"THEMES": {
"DARK_THEME": "深色主題",