diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 9d1690d05..abe145e6b 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -1,89 +1,10 @@
- - - - - - list -
- {{ 'HOME.TABS.RECENTLY_ADDED' | translate }} -
-
- - - - -
- - - attach_file -
- {{ 'HOME.TABS.FILE_UPLOAD' | translate }} -
-
- - - -
- - - link -
- {{ 'HOME.TABS.URL_UPLOAD' | translate }} -
-
- - - -
- - - text_format -
- {{ 'HOME.TABS.TEXT_IMPORT' | translate }} -
-
- - - -
- - - video_library -
- {{ 'HOME.TABS.XTREME_IMPORT' | translate }} -
-
- - - -
- - - dashboard -
- {{ 'HOME.TABS.STALKER_PORTAL_IMPORT' | translate }} -
-
- - - -
-
+ -
diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts index 66a5f83b0..c42af23e5 100644 --- a/src/app/home/home.component.spec.ts +++ b/src/app/home/home.component.spec.ts @@ -3,39 +3,30 @@ import { MatIconModule } from '@angular/material/icon'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTabsModule } from '@angular/material/tabs'; -import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { Actions } from '@ngrx/effects'; import { provideMockActions } from '@ngrx/effects/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { TranslatePipe, TranslateService } from '@ngx-translate/core'; +import { + TranslateModule, + TranslatePipe, + TranslateService, +} from '@ngx-translate/core'; import { MockComponent, MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db'; -import { Observable, of } from 'rxjs'; +import { Observable } from 'rxjs'; import { FileUploadComponent } from '../home/file-upload/file-upload.component'; import { RecentPlaylistsComponent } from '../home/recent-playlists/recent-playlists.component'; import { UrlUploadComponent } from '../home/url-upload/url-upload.component'; import { DataService } from '../services/data.service'; import { ElectronServiceStub } from '../services/electron.service.stub'; import { HeaderComponent } from '../shared/components/header/header.component'; -import { PLAYLIST_PARSE_BY_URL } from './../../../shared/ipc-commands'; import { HomeComponent } from './home.component'; -class MatSnackBarStub { - open(): void {} -} - -class NgxIndexedDBServiceStub { - getAll() { - return of([] as any); - } -} - describe('HomeComponent', () => { let component: HomeComponent; let fixture: ComponentFixture; let electronService: DataService; - let router: Router; let mockStore: MockStore; const actions$ = new Observable(); @@ -56,15 +47,13 @@ describe('HomeComponent', () => { MockModule(MatSnackBarModule), MockModule(RouterTestingModule), MockModule(NgxIndexedDBModule), + MockModule(TranslateModule), ], providers: [ - { provide: MatSnackBar, useClass: MatSnackBarStub }, + MockProvider(MatSnackBar), { provide: DataService, useClass: ElectronServiceStub }, MockProvider(TranslateService), - { - provide: NgxIndexedDBService, - useClass: NgxIndexedDBServiceStub, - }, + MockProvider(NgxIndexedDBService), provideMockStore(), provideMockActions(actions$), ], @@ -79,7 +68,6 @@ describe('HomeComponent', () => { mockStore = TestBed.inject(MockStore); mockStore.setState({}); - router = TestBed.inject(Router); TestBed.inject(NgxIndexedDBService); fixture.detectChanges(); }); @@ -88,36 +76,6 @@ describe('HomeComponent', () => { expect(component).toBeTruthy(); }); - it('should send an event to the main process to get a playlist by URL', () => { - const playlistTitle = 'playlist.m3u'; - const playlistUrl = 'http://test.com/' + playlistTitle; - jest.spyOn(electronService, 'sendIpcEvent'); - component.sendPlaylistsUrl(playlistUrl); - expect(electronService.sendIpcEvent).toHaveBeenCalledWith( - PLAYLIST_PARSE_BY_URL, - { - title: playlistTitle, - url: playlistUrl, - } - ); - }); - - it('should send an event to the main process to parse a playlist', () => { - jest.spyOn(mockStore, 'dispatch'); - const title = 'my-list.m3u'; - const path = '/home/user/iptv/' + title; - const playlistContent = 'test'; - const file: File = { - path, - name: title, - } as unknown as File; - const uploadEvent: Event = { - target: { result: playlistContent }, - } as unknown as Event; - component.handlePlaylist({ file, uploadEvent }); - expect(mockStore.dispatch).toHaveBeenCalledTimes(1); - }); - it('should set IPC event listeners', () => { jest.spyOn(electronService, 'listenOn'); component.setRendererListeners(); @@ -126,12 +84,6 @@ describe('HomeComponent', () => { ); }); - it('should send notification on file reject', () => { - jest.spyOn(component, 'showNotification'); - component.rejectFile('wrong-file.txt'); - expect(component.showNotification).toHaveBeenCalledTimes(1); - }); - it('should remove all ipc listeners on destroy', () => { jest.spyOn(electronService, 'removeAllListeners'); component.ngOnDestroy(); diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 68b10018e..d7bf71a6f 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -1,16 +1,10 @@ import { Component, NgZone } from '@angular/core'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Store } from '@ngrx/store'; -import { TranslateService } from '@ngx-translate/core'; -import { - ERROR, - PLAYLIST_PARSE_BY_URL, - PLAYLIST_PARSE_RESPONSE, -} from '../../../shared/ipc-commands'; +import { ERROR, PLAYLIST_PARSE_RESPONSE } from '../../../shared/ipc-commands'; import { Playlist } from '../../../shared/playlist.interface'; -import { getFilenameFromUrl } from '../../../shared/playlist.utils'; import { DataService } from '../services/data.service'; -import { addPlaylist, parsePlaylist } from '../state/actions'; +import { addPlaylist } from '../state/actions'; @Component({ selector: 'app-home', @@ -35,7 +29,10 @@ export class HomeComponent { }, { id: ERROR, - execute: () => (this.isLoading = false), + execute: (error: { message: string; status: string }) => { + //this.isLoading = false; + this.showNotification('Error2: ' + error.message); + }, }, ]; @@ -45,8 +42,7 @@ export class HomeComponent { private dataService: DataService, private ngZone: NgZone, private snackBar: MatSnackBar, - private readonly store: Store, - private translateService: TranslateService + private readonly store: Store ) { this.setRendererListeners(); } @@ -72,65 +68,6 @@ export class HomeComponent { }); } - /** - * Shows the filename of rejected file - * @param filename name of the uploaded file - */ - rejectFile(filename: string): void { - this.showNotification( - this.translateService.instant('HOME.FILE_UPLOAD.REJECTED', { - filename, - }) - ); - this.isLoading = false; - } - - /** - * Parse and store uploaded playlist - * @param payload - */ - handlePlaylist(payload: { uploadEvent: Event; file: File }): void { - this.isLoading = true; - const playlist = (payload.uploadEvent.target as FileReader) - .result as string; - - this.store.dispatch( - parsePlaylist({ - uploadType: 'FILE', - playlist, - title: payload.file.name, - path: payload.file.path, - }) - ); - } - - /** - * Sends url of the playlist to the renderer process - * @param playlistUrl url of the added playlist - */ - sendPlaylistsUrl(playlistUrl: string): void { - this.isLoading = true; - this.dataService.sendIpcEvent(PLAYLIST_PARSE_BY_URL, { - title: getFilenameFromUrl(playlistUrl), - url: playlistUrl, - }); - } - - /** - * Sends IPC event to the renderer process to parse playlist - * @param text playlist as string - */ - uploadAsText(playlist: string): void { - this.isLoading = true; - this.store.dispatch( - parsePlaylist({ - uploadType: 'TEXT', - playlist, - title: 'Imported as text', - }) - ); - } - /** * Shows snack bar notification with a given message * @param message message to show diff --git a/src/app/home/home.module.ts b/src/app/home/home.module.ts index 15028718c..95f5a8227 100644 --- a/src/app/home/home.module.ts +++ b/src/app/home/home.module.ts @@ -1,20 +1,13 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { HeaderComponent } from '../shared/components/header/header.component'; import { SharedModule } from '../shared/shared.module'; import { DragDropFileUploadDirective } from './file-upload/drag-drop-file-upload.directive'; import { HomeComponent } from './home.component'; import { HomeRoutingModule } from './home.routing'; -import { StalkerPortalImportComponent } from './stalker-portal-import/stalker-portal-import.component'; -import { XtreamCodeImportComponent } from './xtream-code-import/xtream-code-import.component'; @NgModule({ - imports: [ - CommonModule, - HomeRoutingModule, - SharedModule, - XtreamCodeImportComponent, - StalkerPortalImportComponent, - ], + imports: [CommonModule, HeaderComponent, HomeRoutingModule, SharedModule], declarations: [DragDropFileUploadDirective, HomeComponent], }) export class HomeModule {} diff --git a/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts b/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts index c06520a4a..a217e2806 100644 --- a/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts +++ b/src/app/home/recent-playlists/playlist-info/playlist-info.component.spec.ts @@ -9,10 +9,11 @@ import { } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { Actions } from '@ngrx/effects'; import { provideMockActions } from '@ngrx/effects/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { TranslateModule } from '@ngx-translate/core'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { MockModule, MockPipe, MockProvider } from 'ng-mocks'; import { NgxIndexedDBService } from 'ngx-indexed-db'; import { Observable } from 'rxjs'; @@ -27,29 +28,30 @@ describe('PlaylistInfoComponent', () => { let mockStore: MockStore; const actions$ = new Observable(); - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ - FormsModule, - MockModule(MatDialogModule), - MockModule(MatCheckboxModule), - MockModule(MatFormFieldModule), - MockModule(TranslateModule), - ReactiveFormsModule, - ], - declarations: [PlaylistInfoComponent, MockPipe(DatePipe)], - providers: [ - { provide: MAT_DIALOG_DATA, useValue: {} }, - { provide: DataService, useClass: ElectronServiceStub }, - UntypedFormBuilder, - provideMockStore(), - provideMockActions(actions$), - MockProvider(NgxIndexedDBService), - ], - }).compileComponents(); - }) - ); + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ + FormsModule, + MockModule(MatDialogModule), + MockModule(MatCheckboxModule), + MockModule(MatFormFieldModule), + MockModule(TranslateModule), + MockModule(MatSnackBarModule), + ReactiveFormsModule, + ], + declarations: [PlaylistInfoComponent, MockPipe(DatePipe)], + providers: [ + MockProvider(MatSnackBar), + { provide: MAT_DIALOG_DATA, useValue: {} }, + { provide: DataService, useClass: ElectronServiceStub }, + UntypedFormBuilder, + provideMockStore(), + provideMockActions(actions$), + MockProvider(NgxIndexedDBService), + MockProvider(TranslateService), + ], + }).compileComponents(); + })); beforeEach(() => { fixture = TestBed.createComponent(PlaylistInfoComponent); diff --git a/src/app/home/recent-playlists/playlist-item/playlist-item.component.html b/src/app/home/recent-playlists/playlist-item/playlist-item.component.html index e2a785b91..95abd21cc 100644 --- a/src/app/home/recent-playlists/playlist-item/playlist-item.component.html +++ b/src/app/home/recent-playlists/playlist-item/playlist-item.component.html @@ -56,8 +56,12 @@ > - Xtream/Stalker Playlist + + @if (item?.macAddress) { + Stalker Portal + } @else { + Xtream Code Playlist + } | {{ 'HOME.PLAYLISTS.ADDED' | translate }}: {{ item.importDate | date }} diff --git a/src/app/home/recent-playlists/recent-playlists.component.html b/src/app/home/recent-playlists/recent-playlists.component.html index bdb043a40..3055f6882 100644 --- a/src/app/home/recent-playlists/recent-playlists.component.html +++ b/src/app/home/recent-playlists/recent-playlists.component.html @@ -1,4 +1,4 @@ - +@if (allPlaylistsLoaded()) { - - - - search -
- {{ 'HOME.PLAYLISTS.NO_PLAYLISTS' | translate }} -
-
- {{ 'HOME.PLAYLISTS.ADD_FIRST' | translate }} -
-
- - - + @defer { + + starsearch
- {{ 'HOME.PLAYLISTS.GLOBAL_FAVORITES' | translate }} + {{ 'HOME.PLAYLISTS.NO_PLAYLISTS' | translate }}
- {{ - 'HOME.PLAYLISTS.GLOBAL_FAVORITES_DESCRIPTION' - | translate - }} + {{ 'HOME.PLAYLISTS.ADD_FIRST' | translate }}
- - + + + star +
+ {{ 'HOME.PLAYLISTS.GLOBAL_FAVORITES' | translate }} +
+
+ {{ + 'HOME.PLAYLISTS.GLOBAL_FAVORITES_DESCRIPTION' + | translate + }} +
+
+ -
-

{{ migrationMessage }}

-   - -
-
-
-
+ - -
-
- -
+
+

{{ migrationMessage }}

+   + +
+ + + } @placeholder { +
+
- -
-
- +
+ + +
+
+ +
-
- + } +} diff --git a/src/app/home/recent-playlists/recent-playlists.component.ts b/src/app/home/recent-playlists/recent-playlists.component.ts index 0c89ef9fd..5fc9e1af0 100644 --- a/src/app/home/recent-playlists/recent-playlists.component.ts +++ b/src/app/home/recent-playlists/recent-playlists.component.ts @@ -58,7 +58,7 @@ export class RecentPlaylistsComponent implements OnDestroy { ) ); - allPlaylistsLoaded$ = this.store.select(selectPlaylistsLoadingFlag); + allPlaylistsLoaded = this.store.selectSignal(selectPlaylistsLoadingFlag); @Input() sidebarMode = false; diff --git a/src/app/home/text-import/text-import.component.spec.ts b/src/app/home/text-import/text-import.component.spec.ts index dd3ae8a47..8fdf9db9b 100644 --- a/src/app/home/text-import/text-import.component.spec.ts +++ b/src/app/home/text-import/text-import.component.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; -import { TranslatePipe } from '@ngx-translate/core'; +import { TranslateModule, TranslatePipe } from '@ngx-translate/core'; import { MockModule, MockPipe } from 'ng-mocks'; import { TextImportComponent } from './text-import.component'; @@ -10,18 +10,17 @@ describe('TextImportComponent', () => { let component: TextImportComponent; let fixture: ComponentFixture; - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [TextImportComponent, MockPipe(TranslatePipe)], - imports: [ - MockModule(MatInputModule), - MockModule(FormsModule), - MockModule(ReactiveFormsModule), - ], - }).compileComponents(); - }) - ); + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [TextImportComponent, MockPipe(TranslatePipe)], + imports: [ + MockModule(MatInputModule), + MockModule(FormsModule), + MockModule(ReactiveFormsModule), + MockModule(TranslateModule), + ], + }).compileComponents(); + })); beforeEach(() => { fixture = TestBed.createComponent(TextImportComponent); diff --git a/src/app/home/url-upload/url-upload.component.spec.ts b/src/app/home/url-upload/url-upload.component.spec.ts index 99083e0c5..0950e01d0 100644 --- a/src/app/home/url-upload/url-upload.component.spec.ts +++ b/src/app/home/url-upload/url-upload.component.spec.ts @@ -4,7 +4,7 @@ import { MatCardModule } from '@angular/material/card'; import { MatInputModule } from '@angular/material/input'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { TranslatePipe } from '@ngx-translate/core'; +import { TranslateModule, TranslatePipe } from '@ngx-translate/core'; import { MockModule, MockPipe } from 'ng-mocks'; import { DataService } from '../../services/data.service'; import { ElectronServiceStub } from '../../services/electron.service.stub'; @@ -14,26 +14,25 @@ describe('UrlUploadComponent', () => { let component: UrlUploadComponent; let fixture: ComponentFixture; - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [UrlUploadComponent, MockPipe(TranslatePipe)], - imports: [ - MockModule(MatInputModule), - MockModule(MatCardModule), - FormsModule, - ReactiveFormsModule, - NoopAnimationsModule, - ], - providers: [ - { - provide: DataService, - useClass: ElectronServiceStub, - }, - ], - }).compileComponents(); - }) - ); + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [UrlUploadComponent, MockPipe(TranslatePipe)], + imports: [ + MockModule(MatInputModule), + MockModule(MatCardModule), + MockModule(TranslateModule), + MockModule(FormsModule), + MockModule(ReactiveFormsModule), + NoopAnimationsModule, + ], + providers: [ + { + provide: DataService, + useClass: ElectronServiceStub, + }, + ], + }).compileComponents(); + })); beforeEach(() => { fixture = TestBed.createComponent(UrlUploadComponent); @@ -45,31 +44,27 @@ describe('UrlUploadComponent', () => { expect(component).toBeTruthy(); }); - it( - 'submit form with playlist url', - waitForAsync(() => { - jest.spyOn(component.urlAdded, 'emit'); - const TEST_URL = 'http://example.org/playlist.m3u'; - const submitButton = - fixture.debugElement.nativeElement.querySelector('button'); + it('submit form with playlist url', waitForAsync(() => { + jest.spyOn(component.urlAdded, 'emit'); + const TEST_URL = 'http://example.org/playlist.m3u'; + const submitButton = + fixture.debugElement.nativeElement.querySelector('button'); - // test input field validation - expect(submitButton.disabled).toBeTruthy(); - component.form.setValue({ playlistUrl: 'wrong url here' }); - fixture.detectChanges(); - expect(submitButton.disabled).toBeTruthy(); - component.form.setValue({ playlistUrl: TEST_URL + '8' }); - fixture.detectChanges(); - expect(submitButton.disabled).toBeFalsy(); - component.form.setValue({ playlistUrl: TEST_URL }); - fixture.detectChanges(); - expect(submitButton.disabled).toBeFalsy(); + // test input field validation + expect(submitButton.disabled).toBeTruthy(); + component.form.setValue({ playlistUrl: 'wrong url here' }); + fixture.detectChanges(); + expect(submitButton.disabled).toBeTruthy(); + component.form.setValue({ playlistUrl: TEST_URL + '8' }); + fixture.detectChanges(); + expect(submitButton.disabled).toBeFalsy(); + component.form.setValue({ playlistUrl: TEST_URL }); + fixture.detectChanges(); + expect(submitButton.disabled).toBeFalsy(); - const form = fixture.debugElement.query(By.css('form')); - form.triggerEventHandler('ngSubmit', null); + const form = fixture.debugElement.query(By.css('form')); + form.triggerEventHandler('ngSubmit', null); - // eslint-disable-next-line @typescript-eslint/unbound-method - expect(component.urlAdded.emit).toHaveBeenCalledWith(TEST_URL); - }) - ); + expect(component.urlAdded.emit).toHaveBeenCalledWith(TEST_URL); + })); }); diff --git a/src/app/player/components/channel-list-container/channel-list-container.component.html b/src/app/player/components/channel-list-container/channel-list-container.component.html index 6cd745e44..96f420498 100644 --- a/src/app/player/components/channel-list-container/channel-list-container.component.html +++ b/src/app/player/components/channel-list-container/channel-list-container.component.html @@ -1,108 +1,27 @@ - - - - list -
- {{ 'CHANNELS.ALL_CHANNELS' | translate }} +@if (_channelList) { + + + + list +
+ {{ 'CHANNELS.ALL_CHANNELS' | translate }} +
+
+
+
- -
- -
- - - - -
- - - - category -
- {{ 'CHANNELS.GROUPS' | translate }} -
-
- - - - - - {{ - groups.key || ('CHANNELS.UNGROUPED' | translate) - | titlecase - }} - ({{ groups.value.length }}) - - - - - - - - - - -
- - - - star -
- {{ 'CHANNELS.FAVORITES' | translate }} -
-
- - + + - - - {{ - 'CHANNELS.NO_FAVORITES' | translate - }} - - {{ - 'CHANNELS.USE_STAR_TO_FAVORITE' | translate - }} + +
+ + + + category +
+ {{ 'CHANNELS.GROUPS' | translate }} +
- -
-
+ + + + + + {{ + groups.key || + ('CHANNELS.UNGROUPED' | translate) + | titlecase + }} + ({{ groups.value.length }}) + + + + + + + + + + + + + + + star +
+ {{ 'CHANNELS.FAVORITES' | translate }} +
+
+ + + + + + {{ + 'CHANNELS.NO_FAVORITES' | translate + }} + + {{ + 'CHANNELS.USE_STAR_TO_FAVORITE' | translate + }} + + +
+ +} @else { + No channels there +} diff --git a/src/app/player/components/channel-list-container/channel-list-container.component.ts b/src/app/player/components/channel-list-container/channel-list-container.component.ts index a87b35b1c..6ff3cfcb3 100644 --- a/src/app/player/components/channel-list-container/channel-list-container.component.ts +++ b/src/app/player/components/channel-list-container/channel-list-container.component.ts @@ -70,17 +70,18 @@ export class ChannelListContainerComponent { ); /** List with favorites */ - favorites$ = this.store - .select(selectFavorites) - .pipe( - map((favoriteChannelIds) => + favorites$ = this.store.select(selectFavorites).pipe( + map( + ( + favoriteChannelIds // TODO: move to selector + ) => favoriteChannelIds.map((favoriteChannelId) => this.channelList.find( (channel) => channel.id === favoriteChannelId ) ) - ) - ); + ) + ); constructor( private readonly store: Store, @@ -129,4 +130,8 @@ export class ChannelListContainerComponent { }) ); } + + ngOnDestroy() { + this.store.dispatch(PlaylistActions.setChannels({ channels: [] })); + } } diff --git a/src/app/player/components/video-player/sidebar/sidebar.component.html b/src/app/player/components/video-player/sidebar/sidebar.component.html index d4ffa73bb..d39c634bc 100644 --- a/src/app/player/components/video-player/sidebar/sidebar.component.html +++ b/src/app/player/components/video-player/sidebar/sidebar.component.html @@ -17,7 +17,7 @@
{{ sidebarView === 'CHANNELS' - ? channels.length + + ? channels?.length + ' ' + ('HOME.PLAYLISTS.CHANNELS' | translate) : ('HOME.PLAYLISTS.MY_PLAYLISTS_SUBTITLE' | translate) @@ -38,16 +38,13 @@
- - - +@if (sidebarView === 'CHANNELS') { + +} @else { - + /> +} diff --git a/src/app/player/components/video-player/video-player.component.html b/src/app/player/components/video-player/video-player.component.html index 965c49074..01dfe26ce 100644 --- a/src/app/player/components/video-player/video-player.component.html +++ b/src/app/player/components/video-player/video-player.component.html @@ -1,16 +1,13 @@ - - No channels
-
+ @defer { + + } @loading { +

Loading...

+ } @placeholder { +

Loading...

+ }
diff --git a/src/app/settings/settings.component.ts b/src/app/settings/settings.component.ts index 173591291..e48d72de1 100644 --- a/src/app/settings/settings.component.ts +++ b/src/app/settings/settings.component.ts @@ -4,12 +4,21 @@ import { FormArray, FormBuilder, FormControl, + FormsModule, + ReactiveFormsModule, Validators, } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { MatSnackBar } from '@angular/material/snack-bar'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; -import { TranslateService } from '@ngx-translate/core'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { take } from 'rxjs'; import * as semver from 'semver'; import { @@ -22,8 +31,8 @@ import { DataService } from '../services/data.service'; import { DialogService } from '../services/dialog.service'; import { EpgService } from '../services/epg.service'; import { PlaylistsService } from '../services/playlists.service'; +import { HeaderComponent } from '../shared/components/header/header.component'; import { STORE_KEY } from '../shared/enums/store-keys.enum'; -import { SharedModule } from '../shared/shared.module'; import * as PlaylistActions from '../state/actions'; import { selectIsEpgAvailable } from '../state/selectors'; import { SettingsService } from './../services/settings.service'; @@ -35,7 +44,20 @@ import { Theme } from './theme.enum'; templateUrl: './settings.component.html', styleUrls: ['./settings.component.scss'], standalone: true, - imports: [CommonModule, SharedModule], + imports: [ + CommonModule, + FormsModule, + HeaderComponent, + MatButtonModule, + MatCheckboxModule, + MatDividerModule, + MatIconModule, + MatInputModule, + MatSelectModule, + MatTooltipModule, + ReactiveFormsModule, + TranslateModule, + ], }) export class SettingsComponent implements OnInit { /** List with available languages as enum */ diff --git a/src/app/shared/components/header/header.component.html b/src/app/shared/components/header/header.component.html index 69c96c9d3..9fc126b14 100644 --- a/src/app/shared/components/header/header.component.html +++ b/src/app/shared/components/header/header.component.html @@ -6,14 +6,82 @@
{{ subtitle }}
diff --git a/src/app/shared/components/header/header.component.scss b/src/app/shared/components/header/header.component.scss index d8b49f342..0f918438f 100644 --- a/src/app/shared/components/header/header.component.scss +++ b/src/app/shared/components/header/header.component.scss @@ -32,7 +32,15 @@ .menu { place-content: center; align-self: center; - min-width: 50px; - max-width: 50px; display: flex; } + +.add-playlist-btn { + background-color: #3f51b5; +} + +@media (max-width: 500px) { + .main { + display: none; + } +} diff --git a/src/app/shared/components/header/header.component.ts b/src/app/shared/components/header/header.component.ts index 2fcfd6460..cff313f24 100644 --- a/src/app/shared/components/header/header.component.ts +++ b/src/app/shared/components/header/header.component.ts @@ -1,15 +1,40 @@ +import { AsyncPipe, NgFor, NgIf } from '@angular/common'; import { Component, Input, OnInit } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; +import { MatDividerModule } from '@angular/material/divider'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { NgxWhatsNewModule } from 'ngx-whats-new'; import { HomeComponent } from '../../../home/home.component'; import { DataService } from '../../../services/data.service'; import { WhatsNewService } from '../../../services/whats-new.service'; import { AboutDialogComponent } from '../about-dialog/about-dialog.component'; +import { + AddPlaylistDialogComponent, + PlaylistType, +} from '../add-playlist/add-playlist-dialog.component'; @Component({ + standalone: true, selector: 'app-header', templateUrl: './header.component.html', styleUrls: ['./header.component.scss'], + imports: [ + AsyncPipe, + NgIf, + NgFor, + MatButtonModule, + MatIconModule, + MatMenuModule, + MatDividerModule, + MatTooltipModule, + NgxWhatsNewModule, + TranslateModule, + ], }) export class HeaderComponent implements OnInit { /** Title of the header */ @@ -82,4 +107,14 @@ export class HeaderComponent implements OnInit { data: this.dataService.getAppVersion(), }); } + + opedAddPlaylistDialog(type: PlaylistType) { + this.dialog.open( + AddPlaylistDialogComponent, + { + width: '600px', + data: { type }, + } + ); + } } diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 39d35d99b..b6a42b7c3 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -8,13 +8,11 @@ import { NgxWhatsNewModule } from 'ngx-whats-new'; import { PlaylistItemComponent } from '../home/recent-playlists/playlist-item/playlist-item.component'; import { RecentPlaylistsComponent } from '../home/recent-playlists/recent-playlists.component'; import { MaterialModule } from '../material.module'; -import { HeaderComponent } from './components/'; import { FilterPipe } from './pipes/filter.pipe'; import { MomentDatePipe } from './pipes/moment-date.pipe'; @NgModule({ declarations: [ - HeaderComponent, MomentDatePipe, RecentPlaylistsComponent, PlaylistItemComponent, @@ -37,7 +35,6 @@ import { MomentDatePipe } from './pipes/moment-date.pipe'; DragDropModule, FilterPipe, FormsModule, - HeaderComponent, MaterialModule, NgxWhatsNewModule, MomentDatePipe, diff --git a/src/styles.scss b/src/styles.scss index 2da578339..0399646c5 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -87,7 +87,7 @@ textarea, } .recent-playlists { - height: calc(100vh - 152px - 28px) !important; + height: calc(100vh - 106px - 28px) !important; } #groups-list,