feat: add settings page

This commit is contained in:
4gray committed 2020-09-21 22:29:22 +02:00
1 parent 2f86e43f10
commit 1a44ecd995
16 files changed
+211 -25

No files matched your search

+5
View File
@@ -13,6 +13,11 @@ const routes: Routes = [
path: 'iptv',
component: VideoPlayerComponent,
},
{
path: 'settings',
loadChildren: () =>
import('./settings/settings.module').then((m) => m.SettingsModule),
},
{
path: '**',
component: PageNotFoundComponent,
-4
View File
@@ -3,7 +3,6 @@ import '../polyfills';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { SharedModule } from './shared/shared.module';
@@ -22,7 +21,6 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RecentPlaylistsComponent } from './recent-playlists/recent-playlists.component';
import { ChannelListContainerComponent } from './channel-list-container/channel-list-container.component';
import { FilterPipeModule } from 'ngx-filter-pipe';
import { HeaderComponent } from './playlist-uploader/header/header.component';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
@@ -33,7 +31,6 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
declarations: [
AppComponent,
ChannelListContainerComponent,
HeaderComponent,
PlaylistUploaderComponent,
VideoPlayerComponent,
RecentPlaylistsComponent,
@@ -42,7 +39,6 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
CommonModule,
BrowserAnimationsModule,
BrowserModule,
FormsModule,
HttpClientModule,
SharedModule,
AppRoutingModule,
+4
View File
@@ -6,11 +6,13 @@ import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { ScrollingModule } from '@angular/cdk/scrolling';
import { MatGridListModule } from '@angular/material/grid-list';
@NgModule({
exports: [
@@ -21,11 +23,13 @@ import { ScrollingModule } from '@angular/cdk/scrolling';
MatInputModule,
MatListModule,
MatProgressBarModule,
MatSelectModule,
MatSidenavModule,
MatSnackBarModule,
MatTabsModule,
MatToolbarModule,
ScrollingModule,
MatGridListModule,
],
})
export class MaterialModule {}
@@ -1,9 +0,0 @@
<div fxFlex="100px">
<img src="./assets/icons/icon-tv-256.png" height="100" />
</div>
<div fxFlex="100" fxLayoutAlign="start center">
<div fxLayout="column">
<div fxFlex class="title">IPTVnator</div>
<div class="subtitle">Please select a playlist from the list or add a new playlist via file upload or via url</div>
</div>
</div>
@@ -1,8 +0,0 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent {}
@@ -1,4 +1,4 @@
<app-header fxLayout="row"></app-header>
<app-header fxLayout="row" title="IPTVnator" subtitle="Please select a playlist from the list or add a new playlist via file upload or via url"></app-header>
<div fxLayout="row" fxFlexAlign="start start">
<div fxFlex="100">
<mat-tab-group [dynamicHeight]="true" color="primary" backgroundColor="primary" mat-stretch-tabs>
+35
View File
@@ -0,0 +1,35 @@
<app-header title="Settings / IPTVnator" subtitle="Change the configuration of the application"></app-header>
<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()" novalidate>
<mat-card>
<mat-card-header class="card-header">
<div mat-card-subtitle>Please adapt the options from the list below and confirm with a save button</div>
</mat-card-header>
<mat-card-content>
<mat-list>
<mat-list-item>
<div matLine fxLayout="row">
<p fxFlex>Video player</p>
<p fxFlex fxLayoutAlign="start center">
<mat-form-field appearance="fill">
<mat-label>Select an option</mat-label>
<mat-select formControlName="player">
<mat-option *ngFor="let player of players" [value]="player.id">{{player.label}}
</mat-option>
</mat-select>
</mat-form-field>
</p>
</div>
</mat-list-item>
</mat-list>
</mat-card-content>
<mat-card-actions>
<button mat-button color="primary" type="submit" [disabled]="settingsForm.pristine">
<mat-icon>save</mat-icon> Save changes
</button>
<div fxFlex></div>
<button mat-button color="primary" type="reset" (click)="backToHome()">
<mat-icon>chevron_left</mat-icon> Back to home
</button>
</mat-card-actions>
</mat-card>
</form>
+12
View File
@@ -0,0 +1,12 @@
.card-header {
margin-bottom: 15px;
}
button {
cursor: pointer !important;
text-transform: uppercase;
}
::ng-deep .mat-card {
border-radius: 0 !important;
}
+80
View File
@@ -0,0 +1,80 @@
import { Component, OnInit } from '@angular/core';
import {
FormGroup,
FormControl,
FormBuilder,
Validators,
} from '@angular/forms';
import { StorageMap } from '@ngx-pwa/local-storage';
import { Router } from '@angular/router';
import { MatSnackBar } from '@angular/material/snack-bar';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss'],
})
export class SettingsComponent implements OnInit {
/** Player options */
players = [
{
id: 'html5',
label: ' HTML5 Video Player',
},
{
id: 'videojs',
label: ' VideoJs Player',
},
];
/** Settings form object */
settingsForm: FormGroup;
/**
* Creates an instance of SettingsComponent and injects some dependencies into the component
* @param formBuilder
* @param router
* @param snackBar
* @param storage
*/
constructor(
private formBuilder: FormBuilder,
private router: Router,
private snackBar: MatSnackBar,
private storage: StorageMap
) {
this.settingsForm = this.formBuilder.group({
player: ['html5'], // default value
});
}
/**
* Reads the config object from the browsers storage (indexed db)
*/
ngOnInit(): void {
this.storage.get('settings').subscribe((settings) => {
if (settings) {
this.settingsForm.setValue(settings);
}
});
}
/**
* Triggers on form submit and saves the config object to the indexed db store
*/
onSubmit(): void {
this.storage.set('settings', this.settingsForm.value).subscribe(() => {
this.settingsForm.markAsPristine();
this.snackBar.open('Success! Configuration was saved.', null, {
duration: 2000,
});
});
}
/**
* Navigates back to the applications homepage
*/
backToHome(): void {
this.router.navigateByUrl('/', { skipLocationChange: true });
}
}
+11
View File
@@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SettingsComponent } from './settings.component';
import { SettingsRoutingModule } from './settings.routing';
import { SharedModule } from 'app/shared/shared.module';
@NgModule({
imports: [CommonModule, SettingsRoutingModule, SharedModule],
declarations: [SettingsComponent],
})
export class SettingsModule {}
+16
View File
@@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SettingsComponent } from './settings.component';
const routes: Routes = [
{
path: '',
component: SettingsComponent,
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class SettingsRoutingModule {}
@@ -0,0 +1,14 @@
<div fxFlex="100px">
<img src="./assets/icons/icon-tv-256.png" height="100" />
</div>
<div fxFlex="100" fxLayoutAlign="start center">
<div fxLayout="column">
<div fxFlex class="title">{{title}}</div>
<div class="subtitle">{{subtitle}}</div>
</div>
</div>
<div fxLayout="column" fxFlex="50px" fxLayoutAlign="center center">
<button mat-icon-button (click)="openSettings()">
<mat-icon>settings</mat-icon>
</button>
</div>
@@ -0,0 +1,26 @@
import { Component, Input } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent {
/** Title of the header */
@Input() title: string;
/** Subtitle of the header */
@Input() subtitle: string;
/** Creates an instance of SettingsComponent and injects angulars router module
* @param router angulars router
*/
constructor(private router: Router) {}
/**
* Navigates to the settings page
*/
openSettings(): void {
this.router.navigate(['/settings']);
}
}
+1
View File
@@ -1 +1,2 @@
export * from './page-not-found/page-not-found.component';
export * from './header/header.component';
+6 -3
View File
@@ -3,19 +3,20 @@ import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { PageNotFoundComponent } from './components/';
import { PageNotFoundComponent, HeaderComponent } from './components/';
import { WebviewDirective } from './directives/';
import { FormsModule } from '@angular/forms';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from 'app/material.module';
@NgModule({
declarations: [PageNotFoundComponent, WebviewDirective],
declarations: [PageNotFoundComponent, HeaderComponent, WebviewDirective],
imports: [
CommonModule,
TranslateModule,
FormsModule,
MaterialModule,
FlexLayoutModule,
ReactiveFormsModule,
],
exports: [
TranslateModule,
@@ -23,6 +24,8 @@ import { MaterialModule } from 'app/material.module';
FormsModule,
MaterialModule,
FlexLayoutModule,
HeaderComponent,
ReactiveFormsModule,
],
})
export class SharedModule {}