Update dependencies

This commit is contained in:
Daniel Martin 2022-12-21 16:27:47 +00:00 committed by Raoul Snyman
parent cde10571a7
commit cec351f2fa
33 changed files with 8266 additions and 8930 deletions

92
.eslintrc.json Normal file
View File

@ -0,0 +1,92 @@
{
"root": true,
"ignorePatterns": [
"projects/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"tsconfig.json",
"e2e/tsconfig.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@typescript-eslint/consistent-type-definitions": "error",
"@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-member-accessibility": [
"off",
{
"accessibility": "explicit"
}
],
"@typescript-eslint/member-ordering": [
"error",
{
"default": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": ["app", "openlp"],
"style": "kebab-case"
}
],
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": ["app", "openlp"],
"style": "camelCase"
}
],
"@typescript-eslint/naming-convention": [
"error",
{
"selector": ["variable"],
"modifiers": ["readonly"],
"format": ["UPPER_CASE"]
}
],
"jsdoc/no-types": [
"off"
],
"prefer-arrow/prefer-arrow-functions": [
"off"
],
"brace-style": "off",
"@typescript-eslint/brace-style": [
"off"
],
"id-blacklist": "off",
"id-match": "off",
"no-underscore-dangle": "off"
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {}
}
]
}

1
.gitignore vendored
View File

@ -33,6 +33,7 @@ npm-debug.log
yarn-error.log
testem.log
/typings
/.angular/cache
# System Files
.DS_Store

View File

@ -9,9 +9,9 @@
"sourceRoot": "src",
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
"@schematics/angular:component": {
"style": "scss"
}
},
"architect": {
"build": {
@ -86,14 +86,11 @@
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"builder": "@angular-eslint/builder:lint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
@ -111,16 +108,15 @@
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"builder": "@angular-eslint/builder:lint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
"lintFilePatterns": [
"src/**/*.ts",
"src/**/*.html"
]
}
}
}
}
},
"defaultProject": "@openlp/web-remote"
}
}

View File

@ -24,44 +24,52 @@
"e2e": "ng e2e"
},
"dependencies": {
"@angular/animations": "^11.0.5",
"@angular/cdk": "^11.0.3",
"@angular/common": "^11.0.5",
"@angular/compiler": "^11.0.5",
"@angular/core": "^11.0.5",
"@angular/flex-layout": "^11.0.0-beta.33",
"@angular/forms": "^11.0.5",
"@angular/material": "^11.0.3",
"@angular/platform-browser": "^11.0.5",
"@angular/platform-browser-dynamic": "^11.0.5",
"@angular/router": "^11.0.5",
"@fontsource/roboto": "^4.4.5",
"core-js": "^3.8.1",
"@angular/animations": "^15.0.2",
"@angular/cdk": "^15.0.2",
"@angular/common": "^15.0.2",
"@angular/compiler": "^15.0.2",
"@angular/core": "^15.0.2",
"@angular/forms": "^15.0.2",
"@angular/material": "^15.0.2",
"@angular/platform-browser": "^15.0.2",
"@angular/platform-browser-dynamic": "^15.0.2",
"@angular/router": "^15.0.2",
"@fontsource/roboto": "^4.5.8",
"core-js": "^3.26.1",
"hammerjs": "^2.0.8",
"material-icons": "^1.12.1",
"rxjs": "^6.6.3",
"zone.js": "^0.10.3"
"material-icons": "^1.13.1",
"rxjs": "^7.6.0",
"zone.js": "^0.12.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1100.5",
"@angular/cli": "~11.0.5",
"@angular/compiler-cli": "^11.0.5",
"@angular/language-service": "^11.0.5",
"@types/jasmine": "~3.6.2",
"@types/jasminewd2": "~2.0.8",
"@types/node": "~14.14.16",
"codelyzer": "~6.0.1",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~6.0.0",
"karma": "~5.2.3",
"karma-chrome-launcher": "~3.1.0",
"@angular-devkit/build-angular": "^15.0.3",
"@angular-eslint/builder": "^15.0.3",
"@angular-eslint/eslint-plugin": "^15.1.0",
"@angular-eslint/eslint-plugin-template": "^15.1.0",
"@angular-eslint/schematics": "^15.1.0",
"@angular-eslint/template-parser": "^15.1.0",
"@angular/cli": "~15.0.2",
"@angular/compiler-cli": "^15.0.2",
"@angular/language-service": "^15.0.2",
"@types/jasmine": "~4.3.1",
"@types/jasminewd2": "~2.0.10",
"@types/node": "~18.11.13",
"@typescript-eslint/eslint-plugin": "5.44.0",
"@typescript-eslint/parser": "5.44.0",
"eslint": "^8.28.0",
"eslint-plugin-import": "~2.26.0",
"eslint-plugin-jsdoc": "~39.6.4",
"eslint-plugin-prefer-arrow": "~1.2.3",
"jasmine-core": "~4.5.0",
"jasmine-spec-reporter": "~7.0.0",
"karma": "~6.4.1",
"karma-chrome-launcher": "~3.1.1",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.5.4",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"protractor": "~7.0.0",
"ts-node": "~9.1.1",
"tslint": "~6.1.3",
"typescript": "~4.0.5"
"ts-node": "~10.9.1",
"typescript": "~4.8.2"
},
"private": true
}

View File

@ -40,28 +40,34 @@
<mat-toolbar *ngIf="fastSwitching" class="toolbar-padding"></mat-toolbar>
<footer>
<mat-toolbar class="footer">
<button mat-icon-button (click)="previousItem()" matTooltip="Previous item">
<button mat-icon-button (click)="previousItem()" matTooltip="Previous item" matTooltipPosition="above">
<mat-icon>first_page</mat-icon>
</button>
<button mat-icon-button (click)="nextItem()" matTooltip="Next item">
<button mat-icon-button (click)="nextItem()" matTooltip="Next item" matTooltipPosition="above">
<mat-icon>last_page</mat-icon>
</button>
<button mat-icon-button (click)="previousSlide()" matTooltip="Previous slide">
<button mat-icon-button (click)="previousSlide()" matTooltip="Previous slide" matTooltipPosition="above">
<mat-icon>navigate_before</mat-icon>
</button>
<button mat-icon-button (click)="nextSlide()" matTooltip="Next slide">
<button mat-icon-button (click)="nextSlide()" matTooltip="Next slide" matTooltipPosition="above">
<mat-icon>navigate_next</mat-icon>
</button>
<button mat-icon-button (click)="blankDisplay()" class="displayButton" [class.active]="state.blank" [disabled]="state.blank" matTooltip="Show black">
<button mat-icon-button #squashedDisplayButton (click)="openDisplayModeSelector()" class="squashed-display-button" matTooltip="Change Display Mode" matTooltipPosition="above">
<mat-icon *ngIf="state.blank">videocam_off</mat-icon>
<mat-icon *ngIf="state.theme">wallpaper</mat-icon>
<mat-icon *ngIf="state.display">desktop_windows</mat-icon>
<mat-icon *ngIf="state.live()">videocam</mat-icon>
</button>
<button mat-icon-button (click)="blankDisplay()" class="displayButton" [class.active]="state.blank" [disabled]="state.blank" matTooltip="Show black" matTooltipPosition="above">
<mat-icon>videocam_off</mat-icon>
</button>
<button mat-icon-button (click)="themeDisplay()" class="displayButton" [class.active]="state.theme" [disabled]="state.theme" matTooltip="Show background">
<button mat-icon-button (click)="themeDisplay()" class="displayButton" [class.active]="state.theme" [disabled]="state.theme" matTooltip="Show background" matTooltipPosition="above">
<mat-icon>wallpaper</mat-icon>
</button>
<button mat-icon-button (click)="desktopDisplay()" class="displayButton" [class.active]="state.display" [disabled]="state.display" matTooltip="Show Desktop">
<button mat-icon-button (click)="desktopDisplay()" class="displayButton" [class.active]="state.display" [disabled]="state.display" matTooltip="Show Desktop" matTooltipPosition="above">
<mat-icon>desktop_windows</mat-icon>
</button>
<button mat-icon-button (click)="showDisplay()" class="displayButton" [class.active]="state.display" [disabled]="state.live()" matTooltip="Show Presentation">
<button mat-icon-button (click)="showDisplay()" class="displayButton" [class.active]="state.display" [disabled]="state.live()" matTooltip="Show Presentation" matTooltipPosition="above">
<mat-icon>videocam</mat-icon>
</button>
</mat-toolbar>

View File

@ -1,3 +1,5 @@
$small-toolbar-breakpoint: 500px;
// To allow the inner overlay (and other items) to use z-indexes greater than 1
.mat-sidenav {
&-container, &-content {
@ -10,6 +12,11 @@ mat-toolbar {
position: sticky;
top: 0;
z-index: 1020;
/* Fix icon button alignment on some firefox configurations */
[mat-icon-button] {
line-height: 1;
}
}
mat-divider {
@ -32,7 +39,12 @@ mat-sidenav-container {
flex: 1;
}
mat-slide-toggle {
/* Align icons with text */
mat-sidenav-container .mat-icon {
vertical-align: text-top;
}
.mat-mdc-slide-toggle {
margin-top: 0.8rem;
margin-left: 1rem;
font-size: 80%;
@ -50,7 +62,7 @@ mat-slide-toggle {
background-color: whitesmoke;
}
.fast-switcher a.mat-tab-link > span.text {
.fast-switcher a.mat-mdc-tab-link > span.text {
margin-left: 0.3rem;
}
@ -60,6 +72,19 @@ mat-slide-toggle {
justify-content: space-evenly;
}
.displayButton {
display: none;
}
@media screen and (min-width: $small-toolbar-breakpoint) {
.squashed-display-button {
display: none;
}
.displayButton {
display: block;
}
}
/*
* Make the Component injected by Router Outlet full height:
*/

View File

@ -1,14 +1,16 @@
import { Component, HostListener, OnInit } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatSlideToggleChange } from '@angular/material/slide-toggle';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { State } from './responses';
import { State, DisplayMode } from './responses';
import { OpenLPService, WebSocketStatus } from './openlp.service';
import { WindowRef } from './window-ref.service';
import { PageTitleService } from './page-title.service';
import { LoginComponent } from './components/login/login.component';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { DisplayModeSelectorComponent } from './components/display-mode-selector/display-mode-selector.component';
// import { version } from '../../package.json';
@Component({
@ -17,6 +19,9 @@ import { debounceTime } from 'rxjs/operators';
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
// Make DisplayMode enum visible to html code
DisplayMode = DisplayMode;
private _fastSwitching = false;
state = new State();
showLogin = false;
@ -25,7 +30,7 @@ export class AppComponent implements OnInit {
webSocketOpen = false;
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService,
private dialog: MatDialog, private windowRef: WindowRef) {
private dialog: MatDialog, private bottomSheet: MatBottomSheet, private windowRef: WindowRef) {
pageTitleService.pageTitleChanged$.subscribe(pageTitle => this.pageTitle = pageTitle);
openlpService.stateChanged$.subscribe(item => this.state = item);
openlpService.webSocketStateChanged$.subscribe(status => this.webSocketOpen = status === WebSocketStatus.Open);
@ -54,6 +59,16 @@ export class AppComponent implements OnInit {
localStorage.setItem('OpenLP-fastSwitching', JSON.stringify(value));
}
openDisplayModeSelector(): void {
const selectorRef = this.bottomSheet.open(DisplayModeSelectorComponent, {data: this.state.displayMode});
selectorRef.afterDismissed().subscribe(result => {
if (result === DisplayMode.Blank) {this.blankDisplay();}
else if (result === DisplayMode.Desktop) {this.desktopDisplay();}
else if (result === DisplayMode.Theme) {this.themeDisplay();}
else if (result === DisplayMode.Presentation) {this.showDisplay();}
});
}
login() {
const dialogRef = this.dialog.open(LoginComponent, {
width: '250px'

View File

@ -4,7 +4,6 @@ import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatDialogModule } from '@angular/material/dialog';
@ -21,6 +20,7 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { AppComponent } from './app.component';
import { PageTitleService } from './page-title.service';
@ -43,6 +43,7 @@ import { SlideListComponent } from './components/slides/slide-list/slide-list.co
import { SlideItemComponent } from './components/slides/slide-item/slide-item.component';
import { ServiceItemComponent } from './components/service/service-item/service-item.component';
import { ServiceListComponent } from './components/service/service-list/service-list.component';
import { DisplayModeSelectorComponent } from './components/display-mode-selector/display-mode-selector.component';
@NgModule({
@ -63,7 +64,8 @@ import { ServiceListComponent } from './components/service/service-list/service-
SlidesComponent,
SlideListComponent,
SlideItemComponent,
ThemesComponent
ThemesComponent,
DisplayModeSelectorComponent
],
imports: [
BrowserModule,
@ -87,7 +89,7 @@ import { ServiceListComponent } from './components/service/service-list/service-
MatTabsModule,
MatToolbarModule,
MatTooltipModule,
FlexLayoutModule
MatBottomSheetModule
],
providers: [
PageTitleService,

View File

@ -4,7 +4,7 @@
<span *ngFor="let tag of tags" [class.active]="tag.active">{{ tag.text }}</span>
</div>
<div class="container">
<div class="slide currentSlide song mat-display-3" [innerHTML]="chordproFormatted(currentSlides[activeSlide])|chordpro"></div>
<div class="slide currentSlide song mat-headline-2" [innerHTML]="chordproFormatted(currentSlides[activeSlide])|chordpro"></div>
<div class="nextSlides">
<div
class="slide song"

View File

@ -62,6 +62,7 @@ export class ChordProPipe implements PipeTransform {
/**
* Pipe transformation for ChordPro-formatted song texts.
*
* @param {string} song
* @param {number} nHalfSteps
* @returns {string}
@ -108,15 +109,16 @@ export class ChordProPipe implements PipeTransform {
/**
* Transpose the given chord the given (positive or negative) number of half steps.
*
* @param {string} chordRoot
* @param {number} nHalfSteps
* @returns {string}
*/
transposeChord(chordRoot, nHalfSteps) {
let pos = -1;
for (let i = 0; i < this.keys.length; i++) {
if (this.keys[i].name === chordRoot) {
pos = this.keys[i].value;
for (const key of this.keys) {
if (key.name === chordRoot) {
pos = key.value;
break;
}
}
@ -128,9 +130,9 @@ export class ChordProPipe implements PipeTransform {
else if (pos > this.MAX_HALF_STEPS) {
pos -= this.MAX_HALF_STEPS + 1;
}
for (let i = 0; i < this.keys.length; i++) {
if (this.keys[i].value === pos) {
return this.keys[i].name;
for (const key of this.keys) {
if (key.value === pos) {
return key.name;
}
}
}
@ -225,7 +227,13 @@ export class ChordProPipe implements PipeTransform {
chord += ' ';
}
return `<span data-chord="${chord}" class="${chordClass}"><span class="chord">${chord}</span><span class="text ${fillHtml ? 'with-fill' : ''}"><span class="first-letter">${textFirstLetter}</span>${fillHtml}</span></span>${textRest}`;
return `<span data-chord="${chord}" class="${chordClass}">` +
`<span class="chord">${chord}</span>` +
`<span class="text ${fillHtml ? 'with-fill' : ''}">` +
`<span class="first-letter">${textFirstLetter}</span>` +
`${fillHtml}` +
`</span>` +
`</span>${textRest}`;
} else {
return `${lastPart}`;
}

View File

@ -0,0 +1,19 @@
<mat-action-list>
<button mat-list-item (click)="setMode(DisplayMode.Blank)" class="display-button" [disabled]="displayMode === DisplayMode.Blank">
<mat-icon>videocam_off</mat-icon>
Show black
</button>
<button mat-list-item (click)="setMode(DisplayMode.Theme)" class="display-button" [disabled]="displayMode === DisplayMode.Theme">
<mat-icon>wallpaper</mat-icon>
Show background
</button>
<button mat-list-item (click)="setMode(DisplayMode.Desktop)" class="display-button" [disabled]="displayMode === DisplayMode.Desktop">
<mat-icon>desktop_windows</mat-icon>
Show Desktop
</button>
<button mat-list-item (click)="setMode(DisplayMode.Presentation)" class="display-button" [disabled]="displayMode === DisplayMode.Presentation">
<mat-icon>videocam</mat-icon>
Show Presentation
</button>
</mat-action-list>

View File

@ -0,0 +1,4 @@
.mat-icon {
vertical-align: text-top;
padding-right: 10px;
}

View File

@ -0,0 +1,22 @@
import { Component, Inject } from '@angular/core';
import { MatBottomSheetRef, MAT_BOTTOM_SHEET_DATA } from '@angular/material/bottom-sheet';
import { DisplayMode } from 'src/app/responses';
@Component({
selector: 'openlp-display-mode-sheet',
templateUrl: 'display-mode-selector.component.html',
styleUrls: ['./display-mode-selector.component.scss']
})
export class DisplayModeSelectorComponent {
// Make DisplayMode enum visible to html code
DisplayMode = DisplayMode;
constructor(private bottomSheetRef: MatBottomSheetRef<DisplayModeSelectorComponent>,
@Inject(MAT_BOTTOM_SHEET_DATA) public displayMode: DisplayMode) {}
setMode(mode: DisplayMode): void {
this.bottomSheetRef.dismiss(mode);
event.preventDefault();
}
}

View File

@ -12,7 +12,7 @@ export class SearchOptionsComponent {
public selectedPlugin: string;
public searchOptions: Array<string>;
public selectedSearchOption: string;
public searchOptionsTitle: String = '';
public searchOptionsTitle = '';
constructor(private openlpService: OpenLPService) {}

View File

@ -17,7 +17,7 @@ export class SearchComponent implements OnInit, AfterViewInit {
public searchResults = null;
public selectedPlugin: string;
public currentPlugin: string;
public displaySearchOptions: Boolean = false;
public displaySearchOptions = false;
@ViewChild(SearchOptionsComponent, {static: false}) searchOptions: SearchOptionsComponent;
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService,

View File

@ -1,3 +1,5 @@
<mat-card (click)="onItemSelected(item)" class="service-item no-select" [class.selected]="selected">
<mat-icon>{{ getIcon(item) }}</mat-icon> {{ item.title }}
<mat-card-content>
<mat-icon>{{ getIcon(item) }}</mat-icon> {{ item.title }}
</mat-card-content>
</mat-card>

View File

@ -0,0 +1,9 @@
.selected {
background-color: rgb(235, 235, 235);
font-weight: 700;
}
/* Align icons with text */
.mat-icon {
line-height: inherit !important;
}

View File

@ -12,10 +12,10 @@ import { ServiceItem } from '../../../responses';
export class ServiceItemComponent {
@Input() item: ServiceItem;
@Input() selected = false;
@Output() select = new EventEmitter<ServiceItem>();
@Output() selectItem = new EventEmitter<ServiceItem>();
onItemSelected(item: ServiceItem) {
this.select.emit(item);
this.selectItem.emit(item);
}
getIcon(item: ServiceItem): string {

View File

@ -2,6 +2,6 @@
*ngFor="let item of items"
[item]="item"
[selected]="item.selected"
(select)="onItemSelected($event)"
(selectItem)="onItemSelected($event)"
[tabindex]="item.id"
></openlp-service-item>

View File

@ -1,13 +1,15 @@
<mat-card class="slide no-select" mat-list-item (click)="onSlideSelected(slide)" [class.selected]="selected">
<div class="verse-tag">{{ slide?.tag }}</div>
<div *ngIf="slide?.img; else onlySlideText" class="verse-img-container">
<img src="{{ slide?.img }}" />
<div class="img-verse-text">
{{ slide?.text }}
<mat-card-content>
<div class="verse-tag">{{ slide?.tag }}</div>
<div *ngIf="slide?.img; else onlySlideText" class="verse-img-container">
<img src="{{ slide?.img }}" />
<div class="img-verse-text">
{{ slide?.text }}
</div>
</div>
</div>
<ng-template #onlySlideText>
<div class="verse-text">{{ slide?.text }}</div>
</ng-template>
<ng-template #onlySlideText>
<div class="verse-text">{{ slide?.text }}</div>
</ng-template>
</mat-card-content>
</mat-card>

View File

@ -1,4 +1,4 @@
mat-card {
.slide {
cursor: pointer;
}

View File

@ -11,10 +11,10 @@ import { Slide } from '../../../responses';
export class SlideItemComponent {
@Input() slide: Slide;
@Input() selected = false;
@Output() select = new EventEmitter<Slide>();
@Output() selectSlide = new EventEmitter<Slide>();
onSlideSelected(slide: Slide) {
this.select.emit(slide);
this.selectSlide.emit(slide);
}
}

View File

@ -1 +1 @@
<openlp-slide-item *ngFor="let slide of slides; let index = index" [slide]="slide" [tabindex]="counter" [selected]="slide.selected" (select)="onSlideSelected($event, index)"></openlp-slide-item>
<openlp-slide-item *ngFor="let slide of slides; let index = index" [slide]="slide" [tabindex]="counter" [selected]="slide.selected" (selectSlide)="onSlideSelected($event, index)"></openlp-slide-item>

View File

@ -4,7 +4,7 @@
<span *ngFor="let tag of tags" [class.active]="tag.active">{{ tag.text }}</span>
</div>
<div class="container">
<div class="slide currentSlide mat-display-3">
<div class="slide currentSlide mat-headline-2">
<div *ngIf="currentSlides[activeSlide]?.img; else elseActiveSlideText">
<img src="{{currentSlides[activeSlide]?.img}}" class="active-slide-img" />
<div class="active-slide-img-text">{{ currentSlides[activeSlide]?.text }}</div>
@ -14,7 +14,7 @@
</ng-template>
</div>
<div class="nextSlides">
<div class="slide mat-display-1" [class.first]="slide.first_slide_of_tag" *ngFor="let slide of nextSlides">
<div class="slide mat-headline-4" [class.first]="slide.first_slide_of_tag" *ngFor="let slide of nextSlides">
<div *ngIf="slide.img; else elseNextSlidesText">
<img src="{{slide.img}}" class="next-slides-img" />
<div class="next-slides-text">{{ slide.text }}</div>

View File

@ -15,10 +15,12 @@
<div class="theme-container content" *ngIf="isThemeLevelSupported()">
<div *ngFor="let theme of themeList;">
<mat-card class="theme-card" (click)='setTheme(theme.name)' [class.selected]="theme.selected">
<img [src]="theme.thumbnail"/>
<div class="theme-title">{{ theme.name }}</div>
<mat-card-content>
<img [src]="theme.thumbnail"/>
<div class="theme-title">{{ theme.name }}</div>
</mat-card-content>
</mat-card>
</div>
</div>
<mat-error *ngIf="!isThemeLevelSupported()">Song level theme changing not yet supported. Change your theme level to Global or Service</mat-error>
<mat-error *ngIf="!isThemeLevelSupported()">Song level theme changing not supported. Change your theme level to Global or Service</mat-error>
</form>

View File

@ -1,17 +1,4 @@
mat-card {
cursor: pointer;
justify-content: center;
}
mat-divider {
border-color: #afafaf;
}
mat-button-toggle-group {
margin-left: 10px;
}
mat-slide-toggle {
margin-left: auto;
padding: 0 40px;
}
img {
width: 100%;
}
@ -29,7 +16,8 @@ img {
}
.theme-card {
cursor: pointer;
justify-content: center;
}
.theme-title {

View File

@ -98,7 +98,7 @@ export class OpenLPService {
}
setSearchOption(plugin, option, value): Observable<any> {
return this.doPost(`${this.apiURL}/plugins/${plugin}/search-options`, {'option': option, 'value': value});
return this.doPost(`${this.apiURL}/plugins/${plugin}/search-options`, {option, value});
}
getServiceItems(): Observable<ServiceItem[]> {
@ -106,15 +106,15 @@ export class OpenLPService {
}
setServiceItem(id: any): Observable<any> {
return this.doPost(`${this.apiURL}/service/show`, {'id': id});
return this.doPost(`${this.apiURL}/service/show`, {id});
}
nextItem(): Observable<any> {
return this.doPost(`${this.apiURL}/service/progress`, {'action': 'next'});
return this.doPost(`${this.apiURL}/service/progress`, {action: 'next'});
}
previousItem(): Observable<any> {
return this.doPost(`${this.apiURL}/service/progress`, {'action': 'previous'});
return this.doPost(`${this.apiURL}/service/progress`, {action: 'previous'});
}
getServiceItem(): Observable<any> {
@ -126,15 +126,15 @@ export class OpenLPService {
}
setSlide(id: any): Observable<any> {
return this.doPost(`${this.apiURL}/controller/show`, {'id': id});
return this.doPost(`${this.apiURL}/controller/show`, {id});
}
nextSlide(): Observable<any> {
return this.doPost(`${this.apiURL}/controller/progress`, {'action': 'next'});
return this.doPost(`${this.apiURL}/controller/progress`, {action: 'next'});
}
previousSlide(): Observable<any> {
return this.doPost(`${this.apiURL}/controller/progress`, {'action': 'previous'});
return this.doPost(`${this.apiURL}/controller/progress`, {action: 'previous'});
}
getThemeLevel(): Observable<any> {
@ -146,7 +146,7 @@ export class OpenLPService {
}
setThemeLevel(level): Observable<any> {
return this.doPost(`${this.apiURL}/controller/theme-level`, {'level': level});
return this.doPost(`${this.apiURL}/controller/theme-level`, {level});
}
getTheme(): Observable<any> {
@ -154,35 +154,35 @@ export class OpenLPService {
}
setTheme(theme: string): Observable<any> {
return this.doPost(`${this.apiURL}/controller/theme`, {'theme': theme});
return this.doPost(`${this.apiURL}/controller/theme`, {theme});
}
blankDisplay(): Observable<any> {
return this.doPost(`${this.apiURL}/core/display`, {'display': 'blank'});
return this.doPost(`${this.apiURL}/core/display`, {display: 'blank'});
}
themeDisplay(): Observable<any> {
return this.doPost(`${this.apiURL}/core/display`, {'display': 'theme'});
return this.doPost(`${this.apiURL}/core/display`, {display: 'theme'});
}
desktopDisplay(): Observable<any> {
return this.doPost(`${this.apiURL}/core/display`, {'display': 'desktop'});
return this.doPost(`${this.apiURL}/core/display`, {display: 'desktop'});
}
showDisplay(): Observable<any> {
return this.doPost(`${this.apiURL}/core/display`, {'display': 'show'});
return this.doPost(`${this.apiURL}/core/display`, {display: 'show'});
}
showAlert(text): Observable<any> {
return this.doPost(`${this.apiURL}/plugins/alerts`, {'text': text});
return this.doPost(`${this.apiURL}/plugins/alerts`, {text});
}
sendItemLive(plugin, id): Observable<any> {
return this.doPost(`${this.apiURL}/plugins/${plugin}/live`, {'id': id});
return this.doPost(`${this.apiURL}/plugins/${plugin}/live`, {id});
}
addItemToService(plugin, id): Observable<any> {
return this.doPost(`${this.apiURL}/plugins/${plugin}/add`, {'id': id});
return this.doPost(`${this.apiURL}/plugins/${plugin}/add`, {id});
}
transposeSong(transpose_value): Observable<any> {
@ -257,7 +257,7 @@ export class OpenLPService {
this.webSocketTimeoutHandle = setTimeout(() => {
this.createWebSocket();
}, WEBSOCKET_RECONNECT_TIMEOUT);
}
};
private clearWebSocketTimeoutHandle() {
if (this.webSocketTimeoutHandle) {
@ -272,7 +272,7 @@ export class OpenLPService {
this.handleStateChange(state);
};
reader.readAsText(event.data);
}
};
handleStateChange(state: State) {
this.isTwelveHourTime = state.twelve;

View File

@ -14,6 +14,25 @@ export class State {
theme: boolean;
live = () => !(this.blank || this.display || this.theme);
get displayMode() {
if (this.blank) {
return DisplayMode.Blank;
} else if (this.display) {
return DisplayMode.Desktop;
} else if (this.theme) {
return DisplayMode.Theme;
} else {
return DisplayMode.Presentation;
}
}
}
export enum DisplayMode {
Blank,
Theme,
Desktop,
Presentation
}
export interface Slide {

View File

@ -1,5 +1,5 @@
/* You can add global styles to this file, and also import other style files */
@import '~@angular/material/theming';
@import '@angular/material/theming';
@include mat-core();
$primary: mat-palette($mat-indigo);
@ -36,12 +36,12 @@ mat-sidenav {
width: 12rem;
}
mat-card {
.mat-mdc-card {
margin-bottom: 1rem;
}
mat-card.service-item,
mat-card.slide {
.mat-mdc-card.service-item,
.mat-mdc-card.slide {
cursor: pointer;
}
@ -103,3 +103,7 @@ footer {
.no-select {
user-select: none;
}
.mat-mdc-tooltip {
font-size: 1rem;
}

View File

@ -7,14 +7,8 @@ import {
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);

View File

@ -1,17 +0,0 @@
{
"extends": "../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
["app", "openlp"],
"camelCase"
],
"component-selector": [
true,
"element",
["app", "openlp"],
"kebab-case"
]
}
}

View File

@ -1,127 +0,0 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-misused-new": true,
"no-non-null-assertion": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"no-output-on-prefix": true,
"no-inputs-metadata-property": true,
"no-outputs-metadata-property": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-output-rename": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true
}
}

16554
yarn.lock

File diff suppressed because it is too large Load Diff