diff --git a/src/app/services/dialog.service.spec.ts b/src/app/services/dialog.service.spec.ts
new file mode 100644
index 000000000..716a5fe78
--- /dev/null
+++ b/src/app/services/dialog.service.spec.ts
@@ -0,0 +1,36 @@
+import { ConfirmDialogComponent } from './../shared/components/confirm-dialog/confirm-dialog.component';
+import { MockModule, MockComponent } from 'ng-mocks';
+import { MatDialog, MatDialogModule } from '@angular/material/dialog';
+import { TestBed, inject } from '@angular/core/testing';
+import { DialogService } from './dialog.service';
+import { ConfirmDialogData } from '../shared/components/confirm-dialog/confirm-dialog.component';
+import { EMPTY } from 'rxjs';
+
+describe('Service: Dialog', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ declarations: [MockComponent(ConfirmDialogComponent)],
+ providers: [DialogService, MatDialog],
+ imports: [MockModule(MatDialogModule)],
+ });
+ });
+
+ it('should create the service', inject(
+ [DialogService],
+ (service: DialogService) => {
+ expect(service).toBeTruthy();
+ }
+ ));
+
+ it('should open a confirm dialog', inject(
+ [MatDialog, DialogService],
+ (dialog: MatDialog, service: DialogService) => {
+ spyOn(dialog, 'open').and.returnValue({ afterClosed: () => EMPTY });
+ service.openConfirmDialog({
+ title: 'Remove dialog',
+ message: 'Message',
+ } as ConfirmDialogData);
+ expect(dialog.open).toHaveBeenCalled();
+ }
+ ));
+});
diff --git a/src/app/services/dialog.service.ts b/src/app/services/dialog.service.ts
new file mode 100644
index 000000000..b77590e71
--- /dev/null
+++ b/src/app/services/dialog.service.ts
@@ -0,0 +1,25 @@
+import { ConfirmDialogComponent } from './../shared/components/confirm-dialog/confirm-dialog.component';
+import { MatDialog } from '@angular/material/dialog';
+import { Injectable } from '@angular/core';
+import { ConfirmDialogData } from '../shared/components/confirm-dialog/confirm-dialog.component';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class DialogService {
+ constructor(private dialog: MatDialog) {}
+
+ /**
+ * Opens the confirm dialog with provided data
+ * @param data dialog meta info
+ */
+ openConfirmDialog(data: ConfirmDialogData): void {
+ const dialogRef = this.dialog.open(ConfirmDialogComponent, {
+ data,
+ width: '300px',
+ });
+ dialogRef
+ .afterClosed()
+ .subscribe((result) => (result ? data.onConfirm() : null));
+ }
+}
diff --git a/src/app/shared/components/confirm-dialog/confirm-dialog.component.html b/src/app/shared/components/confirm-dialog/confirm-dialog.component.html
new file mode 100644
index 000000000..320ea3262
--- /dev/null
+++ b/src/app/shared/components/confirm-dialog/confirm-dialog.component.html
@@ -0,0 +1,14 @@
+
+ {{ dialogData?.title }}
+
+
+ {{ dialogData?.message }}
+
+
+
+
+
diff --git a/src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts b/src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts
new file mode 100644
index 000000000..b03504349
--- /dev/null
+++ b/src/app/shared/components/confirm-dialog/confirm-dialog.component.spec.ts
@@ -0,0 +1,41 @@
+import { TranslatePipe, TranslateService } from '@ngx-translate/core';
+import { MockModule, MockPipe, MockProvider } from 'ng-mocks';
+import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { ConfirmDialogComponent } from './confirm-dialog.component';
+import {
+ MatDialog,
+ MatDialogModule,
+ MAT_DIALOG_DATA,
+} from '@angular/material/dialog';
+
+describe('ConfirmDialogComponent', () => {
+ let component: ConfirmDialogComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(
+ waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ ConfirmDialogComponent,
+ MockPipe(TranslatePipe, (value) => JSON.stringify(value)),
+ ],
+ providers: [
+ MockProvider(MatDialog),
+ MockProvider(MAT_DIALOG_DATA),
+ MockProvider(TranslateService),
+ ],
+ imports: [MockModule(MatDialogModule)],
+ }).compileComponents();
+ })
+ );
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfirmDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts b/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts
new file mode 100644
index 000000000..d6d6878ce
--- /dev/null
+++ b/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts
@@ -0,0 +1,26 @@
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { Component, Inject } from '@angular/core';
+
+export interface ConfirmDialogData {
+ title: string;
+ message: string;
+ confirmLabel?: string;
+ cancelLabel?: string;
+ onConfirm: () => void;
+}
+
+@Component({
+ selector: 'app-confirm-dialog',
+ templateUrl: './confirm-dialog.component.html',
+})
+export class ConfirmDialogComponent {
+ /** Contains meta information to show in the dialog */
+ dialogData;
+
+ /** Creates an instance of ConfirmDialogComponent
+ * @param data dialog data
+ */
+ constructor(@Inject(MAT_DIALOG_DATA) data: ConfirmDialogData) {
+ this.dialogData = data;
+ }
+}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 44d85c85b..b46469701 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -7,9 +7,10 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../material.module';
import { FilterPipeModule } from 'ngx-filter-pipe';
import { MomentDatePipe } from './pipes/moment-date.pipe';
+import { ConfirmDialogComponent } from './components/confirm-dialog/confirm-dialog.component';
@NgModule({
- declarations: [HeaderComponent, MomentDatePipe],
+ declarations: [ConfirmDialogComponent, HeaderComponent, MomentDatePipe],
imports: [
CommonModule,
FilterPipeModule,
@@ -20,6 +21,7 @@ import { MomentDatePipe } from './pipes/moment-date.pipe';
TranslateModule,
],
exports: [
+ ConfirmDialogComponent,
FilterPipeModule,
FlexLayoutModule,
FormsModule,
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 486e8578e..3fce04508 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -65,7 +65,11 @@
"CUSTOM_USER_AGENT": "Einige IPTV-Anbieter benötigen einen bestimmten 'User-Agent', um ihre Playlist abspielen zu können."
},
"UPDATED": "Aktualisiert am",
- "REFRESH": "Aktualisieren"
+ "REFRESH": "Aktualisieren",
+ "REMOVE_DIALOG": {
+ "MESSAGE": "Sind Sie sicher, dass Sie diese Wiedergabeliste vollständig löschen möchten",
+ "TITLE": ""
+ }
},
"TABS": {
"FILE_UPLOAD": "Aus Dateisystem hochladen",
@@ -108,5 +112,7 @@
"OPEN_CHANNELS_LIST": "Senderliste öffnen",
"OPEN_EPG_LIST": "TV-Guide (EPG) öffnen",
"TOGGLE_FAVORITE_FLAG": "Als Favoriten hinzufügen/entfernen"
- }
+ },
+ "NO": "Nein",
+ "YES": "Ja"
}
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 32c2f9b25..67cb0fcc2 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -32,6 +32,10 @@
"AUTO_UPDATE_DESCRIPTION": "If the auto-refresh function is activated, the playlist will be updated automatically each time the app is started.",
"CUSTOM_USER_AGENT": "Some IPTV providers need a specific user-agent in order to play their playlist."
},
+ "REMOVE_DIALOG": {
+ "TITLE": "Remove playlist",
+ "MESSAGE": "Are you sure you want to delete this playlist completely?"
+ },
"UPDATED": "Updated",
"REFRESH": "Refresh playlist"
},
@@ -108,5 +112,7 @@
"ENGLISH": "English",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch"
- }
+ },
+ "YES": "Yes",
+ "NO": "No"
}
diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json
index 88876218d..12cfa760c 100644
--- a/src/assets/i18n/ru.json
+++ b/src/assets/i18n/ru.json
@@ -33,7 +33,11 @@
"CUSTOM_USER_AGENT": "Некоторые IPTV провайдеры требуют указанние определенного пользовательского агента (User Agent) для воспроизведения своего плейлиста."
},
"UPDATED": "Обновлен",
- "REFRESH": "Обновить плейлист"
+ "REFRESH": "Обновить плейлист",
+ "REMOVE_DIALOG": {
+ "MESSAGE": "Вы уверены, что хотите удалить этот плейлист?",
+ "TITLE": ""
+ }
},
"FILE_UPLOAD": {
"DRAG_DROP": "Перетащите файл в эту область",
@@ -108,5 +112,7 @@
"ENGLISH": "English",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch"
- }
+ },
+ "NO": "Нет",
+ "YES": "Да"
}