Compare commits

...

13 Commits

Author SHA1 Message Date
Raoul Snyman af0787450d Don't install dev dependencies when building
- Use npm to install ng
- Temporarily add npm manually until runner image is updated
2024-04-25 22:36:57 -07:00
Chris Witterholt f657a24e99 Merge branch 'refactor-tests' into 'master'
Refactor tests.

See merge request openlp/web-remote!108
2024-04-25 19:35:14 +00:00
Chris Witterholt 037d0ccb40
Refactor tests. 2024-04-25 21:31:35 +02:00
Chris Witterholt ff8c01c874 Merge branch 'update-angular' into 'master'
Update Angular.

See merge request openlp/web-remote!107
2024-04-25 19:11:35 +00:00
Chris Witterholt 86d85870e9
Update Angular. 2024-04-25 21:07:48 +02:00
Chris Witterholt a6b4ea23c8 Merge branch 'refactor-login-component' into 'master'
Refactor login component.

See merge request openlp/web-remote!106
2024-04-25 18:55:52 +00:00
Chris Witterholt 75c11d4543
Refactor login component. 2024-04-25 20:52:04 +02:00
Chris Witterholt ece665dbf2 Merge branch 'fix-live-button' into 'master'
Fix the live button.

See merge request openlp/web-remote!105
2024-04-25 18:32:58 +00:00
Chris Witterholt b62f21bae0
Fix the live button. 2024-04-25 20:28:53 +02:00
Chris Witterholt 18ba69088b Merge branch 'add-missing-translations' into 'master'
Add missing translations.

See merge request openlp/web-remote!104
2024-04-25 04:06:46 +00:00
Chris Witterholt 89c908ef4a Add missing translations. 2024-04-25 04:06:46 +00:00
Chris Witterholt ee9392cc01 Merge branch 'use-angular17-template-syntax' into 'master'
Use the new Angular 17 template syntax and property 'styleUrl'

See merge request openlp/web-remote!102
2024-04-24 16:44:06 +00:00
Chris Witterholt ea39bbc3d7 Use the new Angular 17 template syntax and property 'styleUrl' 2024-04-24 16:44:06 +00:00
77 changed files with 1445 additions and 925 deletions

View File

@ -33,7 +33,10 @@ test:
build-branch:
stage: build
script:
- yarn install
# Temporarily install npm manually until we get it added to the runner image
- apk add npm
- yarn install --production
- npm install @angular/cli
- yarn build --no-progress --configuration production --aot
- export APP_VERSION=`git describe --dirty --tags --long --match '*[0-9]*'`
- 'echo "window.appVersion = \"$APP_VERSION\";" > dist/web-remote/assets/version.js'
@ -46,7 +49,10 @@ build-branch:
build-tag:
stage: build
script:
- yarn install
# Temporarily install npm manually until we get it added to the runner image
- apk add npm
- yarn install --production
- npm install @angular/cli
- yarn build --no-progress --configuration production --aot
- 'echo "window.appVersion = \"$CI_COMMIT_TAG\";" > dist/web-remote/assets/version.js'
artifacts:

View File

@ -25,17 +25,17 @@
"tx": "node scripts/tx.js"
},
"dependencies": {
"@angular/animations": "^17.3.5",
"@angular/cdk": "^17.3.5",
"@angular/common": "^17.3.5",
"@angular/compiler": "^17.3.5",
"@angular/core": "^17.3.5",
"@angular/forms": "^17.3.5",
"@angular/material": "^17.3.5",
"@angular/platform-browser": "^17.3.5",
"@angular/platform-browser-dynamic": "^17.3.5",
"@angular/router": "^17.3.5",
"@fontsource/roboto": "^5.0.12",
"@angular/animations": "^17.3.6",
"@angular/cdk": "^17.3.6",
"@angular/common": "^17.3.6",
"@angular/compiler": "^17.3.6",
"@angular/core": "^17.3.6",
"@angular/forms": "^17.3.6",
"@angular/material": "^17.3.6",
"@angular/platform-browser": "^17.3.6",
"@angular/platform-browser-dynamic": "^17.3.6",
"@angular/router": "^17.3.6",
"@fontsource/roboto": "^5.0.13",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
"core-js": "^3.37.0",
@ -44,22 +44,23 @@
"zone.js": "^0.14.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^17.3.5",
"@angular-devkit/build-angular": "^17.3.6",
"@angular-eslint/builder": "^17.3.0",
"@angular-eslint/eslint-plugin": "^17.3.0",
"@angular-eslint/eslint-plugin-template": "^17.3.0",
"@angular-eslint/schematics": "^17.3.0",
"@angular-eslint/template-parser": "^17.3.0",
"@angular/cli": "~17.3.5",
"@angular/compiler-cli": "^17.3.5",
"@angular/language-service": "^17.3.5",
"@angular/cli": "~17.3.6",
"@angular/compiler-cli": "^17.3.6",
"@angular/language-service": "^17.3.6",
"@chiragrupani/karma-chromium-edge-launcher": "^2.3.1",
"@transifex/api": "^7.1.0",
"@types/jasmine": "~5.1.4",
"@types/jasminewd2": "~2.0.13",
"@types/jest": "^29.5.12",
"@types/node": "~20.12.7",
"@typescript-eslint/eslint-plugin": "7.7.0",
"@typescript-eslint/parser": "7.7.0",
"@typescript-eslint/eslint-plugin": "7.7.1",
"@typescript-eslint/parser": "7.7.1",
"axios": "^1.6.8",
"browserslist": "^4.23.0",
"browserslist-useragent-regexp": "^4.1.3",

View File

@ -1,23 +1,35 @@
<mat-toolbar color="primary">
<mat-toolbar-row>
<button mat-icon-button (click)="menu.toggle()"><mat-icon>menu</mat-icon></button>
<button mat-icon-button (click)="menu.toggle()">
<mat-icon>menu</mat-icon>
</button>
<span class="page-title">{{ pageTitle | translate }}</span>
<span class="spacer"></span>
<button *ngIf="showLogin" mat-button (click)="login()">{{ 'LOGIN' | translate }}</button>
<button *ngIf="webSocketOpen"
mat-icon-button
(click)="forceWebSocketReconnection()"
class="connection-status"
matTooltip="{{ 'CONNECTED_TO_OPENLP' | translate }}">
<mat-icon *ngIf="webSocketOpen">link</mat-icon>
</button>
<button *ngIf="!webSocketOpen"
mat-icon-button
(click)="forceWebSocketReconnection()"
class="connection-status"
matTooltip="{{ 'DISCONNECTED' | translate }}">
<mat-icon *ngIf="!webSocketOpen">link_off</mat-icon>
</button>
@if (showLogin) {
<button
mat-button
(click)="login()">
{{ 'LOGIN' | translate }}
</button>
}
@if (webSocketOpen) {
<button
mat-icon-button
(click)="forceWebSocketReconnection()"
class="connection-status"
matTooltip="{{ 'CONNECTED_TO_OPENLP' | translate }}">
<mat-icon>link</mat-icon>
</button>
}
@else {
<button
mat-icon-button
(click)="forceWebSocketReconnection()"
class="connection-status"
matTooltip="{{ 'DISCONNECTED' | translate }}">
<mat-icon>link_off</mat-icon>
</button>
}
<span class="app-version">v{{appVersion}}</span>
</mat-toolbar-row>
</mat-toolbar>
@ -92,188 +104,214 @@
</main>
<!-- These two toolbars are for padding the content so the real toolbars do not block content when scrolled down -->
<mat-toolbar class="toolbar-padding"></mat-toolbar>
<mat-toolbar *ngIf="fastSwitching" class="toolbar-padding"></mat-toolbar>
@if (fastSwitching) {
<mat-toolbar class="toolbar-padding"></mat-toolbar>
}
<footer>
<mat-toolbar class="footer">
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="previousItem()"
matTooltip="{{ 'PREVIOUS_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>first_page</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="previousItem()"
matTooltip="{{ 'PREVIOUS_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>first_page</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="nextItem()"
matTooltip="{{ 'NEXT_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>last_page</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="nextItem()"
matTooltip="{{ 'NEXT_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>last_page</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="previousSlide()"
matTooltip="{{ 'PREVIOUS_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_before</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="previousSlide()"
matTooltip="{{ 'PREVIOUS_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_before</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="nextSlide()"
matTooltip="{{ 'NEXT_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_next</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="nextSlide()"
matTooltip="{{ 'NEXT_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_next</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
#squashedDisplayButton
(click)="openDisplayModeSelector()"
class="squashed-display-button"
matTooltip="{{ 'CHANGE_DISPLAY_MODE' | translate }}"
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 *ngIf="!bigDisplayButtons"
mat-icon-button
#squashedDisplayButton
(click)="openDisplayModeSelector()"
class="squashed-display-button"
matTooltip="{{ 'CHANGE_DISPLAY_MODE' | translate }}"
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 *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="blankDisplay()"
class="displayButton"
[class.active]="state.blank"
[disabled]="state.blank"
matTooltip="{{ 'SHOW_BLACK' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam_off</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="blankDisplay()"
class="displayButton"
[class.active]="state.blank"
[disabled]="state.blank"
matTooltip="{{ 'SHOW_BLACK' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam_off</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="themeDisplay()"
class="displayButton"
[class.active]="state.theme"
[disabled]="state.theme"
matTooltip="{{ 'SHOW_BACKGROUND' | translate }}"
matTooltipPosition="above">
<mat-icon>wallpaper</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button
(click)="themeDisplay()"
class="displayButton"
[class.active]="state.theme"
[disabled]="state.theme"
matTooltip="{{ 'SHOW_BACKGROUND' | translate }}"
matTooltipPosition="above">
<mat-icon>wallpaper</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="desktopDisplay()"
class="displayButton"
[class.active]="state.display"
[disabled]="state.display"
matTooltip="{{ 'SHOW_DESKTOP' | translate }}"
matTooltipPosition="above">
<mat-icon>desktop_windows</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="desktopDisplay()"
class="displayButton"
[class.active]="state.display"
[disabled]="state.display"
matTooltip="{{ 'SHOW_DESKTOP' | translate }}"
matTooltipPosition="above">
<mat-icon>desktop_windows</mat-icon>
</button>
<button *ngIf="bigDisplayButtons"
mat-fab color="primary"
(click)="showDisplay()"
class="displayButton"
[class.active]="state.display"
[disabled]="state.live()"
matTooltip="{{ 'SHOW_PRESENTATION' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam</mat-icon>
</button>
<button *ngIf="!bigDisplayButtons"
mat-icon-button (click)="showDisplay()"
class="displayButton"
[class.active]="state.display"
[disabled]="state.live()"
matTooltip="{{ 'SHOW_PRESENTATION' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam</mat-icon>
</button>
@if (bigDisplayButtons) {
<button
mat-fab color="primary"
(click)="previousItem()"
matTooltip="{{ 'PREVIOUS_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>first_page</mat-icon>
</button>
<button
mat-fab color="primary"
(click)="nextItem()"
matTooltip="{{ 'NEXT_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>last_page</mat-icon>
</button>
<button
mat-fab color="primary"
(click)="previousSlide()"
matTooltip="{{ 'PREVIOUS_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_before</mat-icon>
</button>
<button
mat-fab color="primary"
(click)="nextSlide()"
matTooltip="{{ 'NEXT_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_next</mat-icon>
</button>
<button
mat-fab color="primary"
#squashedDisplayButton
(click)="openDisplayModeSelector()"
class="squashed-display-button"
matTooltip="{{ 'CHANGE_DISPLAY_MODE' | translate }}"
matTooltipPosition="above">
@if (state.blank) {
<mat-icon>videocam_off</mat-icon>
}
@else if (state.theme) {
<mat-icon>wallpaper</mat-icon>
}
@else if (state.display) {
<mat-icon>desktop_windows</mat-icon>
}
@else if (state.live()) {
<mat-icon>videocam</mat-icon>
}
</button>
<button
mat-fab color="primary"
(click)="blankDisplay()"
class="displayButton"
[class.active]="state.blank"
[disabled]="state.blank"
matTooltip="{{ 'SHOW_BLACK' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam_off</mat-icon>
</button>
<button
mat-fab color="primary"
(click)="themeDisplay()"
class="displayButton"
[class.active]="state.theme"
[disabled]="state.theme"
matTooltip="{{ 'SHOW_BACKGROUND' | translate }}"
matTooltipPosition="above">
<mat-icon>wallpaper</mat-icon>
</button>
<button
mat-fab color="primary"
(click)="desktopDisplay()"
class="displayButton"
[class.active]="state.display"
[disabled]="state.display"
matTooltip="{{ 'SHOW_DESKTOP' | translate }}"
matTooltipPosition="above">
<mat-icon>desktop_windows</mat-icon>
</button>
<button
mat-fab color="primary"
(click)="showDisplay()"
class="displayButton"
[class.active]="state.display"
[disabled]="state.live()"
matTooltip="{{ 'SHOW_PRESENTATION' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam</mat-icon>
</button>
}
@else {
<button
mat-icon-button
(click)="previousItem()"
matTooltip="{{ 'PREVIOUS_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>first_page</mat-icon>
</button>
<button
mat-icon-button
(click)="nextItem()"
matTooltip="{{ 'NEXT_ITEM' | translate }}"
matTooltipPosition="above">
<mat-icon>last_page</mat-icon>
</button>
<button
mat-icon-button (click)="previousSlide()"
matTooltip="{{ 'PREVIOUS_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_before</mat-icon>
</button>
<button
mat-icon-button (click)="nextSlide()"
matTooltip="{{ 'NEXT_SLIDE' | translate }}"
matTooltipPosition="above">
<mat-icon>navigate_next</mat-icon>
</button>
<button
mat-icon-button
#squashedDisplayButton
(click)="openDisplayModeSelector()"
class="squashed-display-button"
matTooltip="{{ 'CHANGE_DISPLAY_MODE' | translate }}"
matTooltipPosition="above">
@if (state.blank) {
<mat-icon>videocam_off</mat-icon>
}
@else if (state.theme) {
<mat-icon>wallpaper</mat-icon>
}
@else if (state.display) {
<mat-icon>desktop_windows</mat-icon>
}
@else if (state.live()) {
<mat-icon>videocam</mat-icon>
}
</button>
<button
mat-icon-button (click)="blankDisplay()"
class="displayButton"
[class.active]="state.blank"
[disabled]="state.blank"
matTooltip="{{ 'SHOW_BLACK' | translate }}"
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' | translate }}"
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' | translate }}"
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' | translate }}"
matTooltipPosition="above">
<mat-icon>videocam</mat-icon>
</button>
}
</mat-toolbar>
<nav *ngIf="fastSwitching"
mat-tab-nav-bar mat-stretch-tabs
class="fast-switcher"
[tabPanel]="tabPanel">
<a mat-tab-link
routerLink="/service"
routerLinkActive #serviceRoute="routerLinkActive"
[active]="serviceRoute.isActive"><mat-icon>list</mat-icon></a>
<a mat-tab-link
routerLink="/slides"
routerLinkActive #slidesRoute="routerLinkActive"
[active]="slidesRoute.isActive"><mat-icon>collections</mat-icon></a>
<a mat-tab-link
routerLink="/alerts"
routerLinkActive #alertsRoute="routerLinkActive"
[active]="alertsRoute.isActive"><mat-icon>error</mat-icon></a>
<a mat-tab-link
routerLink="/search"
routerLinkActive #searchRoute="routerLinkActive"
[active]="searchRoute.isActive"><mat-icon>search</mat-icon></a>
<a mat-tab-link
routerLink="/themes"
routerLinkActive #themesRoute="routerLinkActive"
[active]="themesRoute.isActive"><mat-icon>image</mat-icon></a>
</nav>
@if (fastSwitching) {
<nav
mat-tab-nav-bar mat-stretch-tabs
class="fast-switcher"
[tabPanel]="tabPanel">
<a mat-tab-link
routerLink="/service"
routerLinkActive #serviceRoute="routerLinkActive"
[active]="serviceRoute.isActive"><mat-icon>list</mat-icon></a>
<a mat-tab-link
routerLink="/slides"
routerLinkActive #slidesRoute="routerLinkActive"
[active]="slidesRoute.isActive"><mat-icon>collections</mat-icon></a>
<a mat-tab-link
routerLink="/alerts"
routerLinkActive #alertsRoute="routerLinkActive"
[active]="alertsRoute.isActive"><mat-icon>error</mat-icon></a>
<a mat-tab-link
routerLink="/search"
routerLinkActive #searchRoute="routerLinkActive"
[active]="searchRoute.isActive"><mat-icon>search</mat-icon></a>
<a mat-tab-link
routerLink="/themes"
routerLinkActive #themesRoute="routerLinkActive"
[active]="themesRoute.isActive"><mat-icon>image</mat-icon></a>
</nav>
}
</footer>
</mat-sidenav-content>
</mat-sidenav-container>

View File

@ -1,5 +1,5 @@
describe('AppComponent', () => {
it('has a dummy test', () => {
expect().nothing();
expect(null).toBe(null);
});
});

View File

@ -20,7 +20,7 @@ import * as supportedBrowsers from '../assets/supportedBrowsers';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
styleUrl: './app.component.scss'
})
export class AppComponent implements OnInit {
// Make DisplayMode enum visible to html code
@ -39,7 +39,7 @@ export class AppComponent implements OnInit {
constructor(private translateService: TranslateService, private pageTitleService: PageTitleService,
private openlpService: OpenLPService, private dialog: MatDialog, private bottomSheet: MatBottomSheet,
private windowRef: WindowRef, private shortcutsService: ShortcutsService, private settingsService: SettingsService) {
this.pageTitleService.pageTitleChanged$.subscribe(pageTitle => this.pageTitle = pageTitle.toUpperCase());
this.pageTitleService.pageTitleChanged$.subscribe(pageTitle => this.pageTitle = pageTitle);
this.openlpService.stateChanged$.subscribe(item => this.state = item);
this.openlpService.webSocketStateChanged$.subscribe(status => this.webSocketOpen = status === WebSocketStatus.Open);
this.shortcutsService.shortcutsChanged$.subscribe(shortcuts => this.addShortcuts(shortcuts));

View File

@ -1,14 +1,16 @@
<h3>{{ 'SEND_AN_ALERT' | translate }}</h3>
<form #alertForm="ngForm">
<mat-form-field>
<input matInput
<input
matInput
[(ngModel)]="alert"
type="text"
name="alert"
placeholder="{{ 'ALERT' | translate }}"
required>
</mat-form-field>
<button mat-raised-button color="primary"
<button
mat-raised-button color="primary"
id="sendButton"
[disabled]="!alertForm.form.valid"
(click)="onSubmit(); alertForm.reset()">

View File

@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { TranslateService } from '@ngx-translate/core';
import { PageTitleService } from '../../page-title.service';
import { OpenLPService } from '../../openlp.service';
@ -7,20 +8,31 @@ import { OpenLPService } from '../../openlp.service';
@Component({
selector: 'openlp-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.scss'],
styleUrl: './alert.component.scss',
providers: [OpenLPService]
})
export class AlertComponent {
public alert: string;
public alertMessage: string;
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService,
private snackBar: MatSnackBar) {
pageTitleService.changePageTitle('Alerts');
constructor(
private pageTitleService: PageTitleService,
private openlpService: OpenLPService,
private snackBar: MatSnackBar,
private translateService: TranslateService) {
this.translateService.stream('ALERTS').subscribe(res => {
this.pageTitleService.changePageTitle(res);
});
this.translateService.stream('ALERT_SUBMITTED').subscribe(res => {
this.alertMessage = res;
});
}
onSubmit() {
this.openlpService.showAlert(this.alert).subscribe(() => this.snackBar.open('Alert submitted', '', {duration: 2000}));
this.openlpService.showAlert(this.alert).subscribe(
() => this.snackBar.open(this.alertMessage, '', { duration: 2000 })
);
}
}

View File

@ -1,7 +1,7 @@
<div
class="slide song"
[class.currentSlide]="active"
[class.mat-headline-2]="active"
[class.first]="!active && slide.first_slide_of_tag"
[innerHTML]="chordproFormatted(slide)|chordpro">
</div>
class="slide song"
[class.currentSlide]="active"
[class.mat-headline-2]="active"
[class.first]="!active && slide.first_slide_of_tag"
[innerHTML]="chordproFormatted(slide)|chordpro">
</div>

View File

@ -1,53 +1,74 @@
<div
class="overlay"
[class.embedded]="embedded"
[style.--openlp-stage-font-scale]="fontScale"
>
[style.--openlp-stage-font-scale]="fontScale">
<div class="overlay-content">
<div class="tags">
<span *ngFor="let tag of tags" [class.active]="tag.active">{{ tag.text }}</span>
@for (tag of tags; track tag) {
<span [class.active]="tag.active">{{ tag.text }}</span>
}
</div>
<div class="container">
<app-chord-view-item
[slide]="currentSlides[activeSlide]"
[active]="true"
*ngIf="currentSlides[activeSlide]?.chords; else elseSlideNoChords"
></app-chord-view-item>
<ng-template #elseSlideNoChords>
<app-stage-view-item [slide]="currentSlides[activeSlide]" [active]="true"></app-stage-view-item>
</ng-template>
@if (currentSlides[activeSlide]?.chords) {
<app-chord-view-item
[slide]="currentSlides[activeSlide]"
[active]="true">
</app-chord-view-item>
}
@else {
<app-stage-view-item
[slide]="currentSlides[activeSlide]"
[active]="true">
</app-stage-view-item>
}
<div class="nextSlides">
<ng-container *ngFor="let slide of nextSlides; trackBy: trackByIndex">
<app-chord-view-item [slide]="slide" *ngIf="slide?.chords; else elseNextSlideNoChords"></app-chord-view-item>
<ng-template #elseNextSlideNoChords>
<app-stage-view-item [slide]="slide"></app-stage-view-item>
</ng-template>
</ng-container>
@for (slide of nextSlides; track trackByIndex) {
<ng-container>
@if (slide?.chords) {
<app-chord-view-item
[slide]="slide">
</app-chord-view-item>
}
@else {
<app-stage-view-item
[slide]="slide">
</app-stage-view-item>
}
</ng-container>
}
</div>
</div>
</div>
<div class="toolbar">
<a *ngIf="!embedded"
mat-mini-fab color=""
class="back-button"
routerLink="/"
matTooltip="{{ 'GO_BACK_TO_CONTROLLER' | translate }}">
<mat-icon>arrow_back</mat-icon>
</a>
@if (!embedded) {
<a
mat-mini-fab color=""
class="back-button"
routerLink="/"
matTooltip="{{ 'GO_BACK_TO_CONTROLLER' | translate }}">
<mat-icon>arrow_back</mat-icon>
</a>
}
<div class="transpose">
<button mat-icon-button (click)="transposeDown()">
<button
mat-icon-button
(click)="transposeDown()">
<mat-icon>keyboard_arrow_down</mat-icon>
</button>
<span>{{ transposeLevel }}</span>
<button mat-icon-button (click)="transposeUp()">
<button
mat-icon-button
(click)="transposeUp()">
<mat-icon>keyboard_arrow_up</mat-icon>
</button>
</div>
<div *ngIf="!embedded && activeSlide+1 === currentSlides.length"
class="next-service-item"
matTooltip="{{ 'NEXT_ITEM' | translate }}">
{{ nextServiceItemTitle }}
</div>
@if (!embedded && activeSlide+1 === currentSlides.length) {
<div
class="next-service-item"
matTooltip="{{ 'NEXT_ITEM' | translate }}">
{{ nextServiceItemTitle }}
</div>
}
<div class="time">{{ (openlpService.getIsTwelveHourTime()) ? (time|date:'h:mm a') : (time|date:'HH:mm') }}</div>
</div>
</div>

View File

@ -1,84 +1,98 @@
<mat-action-list *ngIf="!display.bigDisplayButtons">
<button mat-list-item
aria-labelledby="caption-blank"
class="display-button"
(click)="setMode(DisplayMode.Blank)"
[disabled]="displayMode === DisplayMode.Blank">
<mat-icon class="small-icon">videocam_off</mat-icon>
<span id="caption-blank" class="caption">{{ 'SHOW_BLACK' | translate }}</span>
</button>
<button mat-list-item
aria-labelledby="caption-theme"
class="display-button"
(click)="setMode(DisplayMode.Theme)"
[disabled]="displayMode === DisplayMode.Theme">
<mat-icon class="small-icon">wallpaper</mat-icon>
<span id="caption-theme" class="caption">{{ 'SHOW_BACKGROUND' | translate }}</span>
</button>
<button mat-list-item
aria-labelledby="caption-desktop"
class="display-button"
(click)="setMode(DisplayMode.Desktop)"
[disabled]="displayMode === DisplayMode.Desktop">
<mat-icon class="small-icon">desktop_windows</mat-icon>
<span id="caption-desktop" class="caption">{{ 'SHOW_DESKTOP' | translate }}</span>
</button>
<button mat-list-item
aria-labelledby="caption-presentation"
class="display-button"
(click)="setMode(DisplayMode.Presentation)"
[disabled]="displayMode === DisplayMode.Presentation">
<mat-icon class="small-icon">videocam</mat-icon>
<span id="caption-presentation" class="caption">{{ 'SHOW_PRESENTATION' | translate }}</span>
</button>
</mat-action-list>
<mat-grid-list *ngIf="display.bigDisplayButtons" cols="2" rowHeight="2:1">
<mat-grid-tile>
<button mat-fab color="primary"
@if (display.bigDisplayButtons) {
<mat-grid-list
cols="2"
rowHeight="2:1">
<mat-grid-tile>
<button
mat-fab color="primary"
aria-labelledby="caption-blank"
class="display-button"
(click)="setMode(displayMode.Blank)"
[disabled]="display.displayMode === displayMode.Blank">
<mat-icon class="big-icon">videocam_off</mat-icon>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-blank" class="caption">{{ 'SHOW_BLACK' | translate }}</div>
</mat-grid-tile>
<mat-grid-tile>
<button
mat-fab color="primary"
aria-labelledby="caption-theme"
class="display-button"
(click)="setMode(displayMode.Theme)"
[disabled]="display.displayMode === displayMode.Theme">
<mat-icon class="big-icon">wallpaper</mat-icon>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-theme" class="caption">{{ 'SHOW_BACKGROUND' | translate }}</div>
</mat-grid-tile>
<mat-grid-tile>
<button
mat-fab color="primary"
aria-labelledby="caption-desktop"
class="display-button"
(click)="setMode(displayMode.Desktop)"
[disabled]="display.displayMode === displayMode.Desktop">
<mat-icon class="big-icon">desktop_windows</mat-icon>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-desktop" class="caption">{{ 'SHOW_DESKTOP' | translate }}</div>
</mat-grid-tile>
<mat-grid-tile>
<button
mat-fab color="primary"
aria-labelledby="caption-presentation"
class="display-button"
(click)="setMode(displayMode.Presentation)"
[disabled]="display.displayMode === displayMode.Presentation">
<mat-icon class="big-icon">videocam</mat-icon>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-presentation" class="caption">{{ 'SHOW_PRESENTATION' | translate }}</div>
</mat-grid-tile>
</mat-grid-list>
}
@else {
<mat-action-list>
<button
mat-list-item
aria-labelledby="caption-blank"
class="display-button"
(click)="setMode(DisplayMode.Blank)"
[disabled]="displayMode === DisplayMode.Blank">
<mat-icon class="big-icon">videocam_off</mat-icon>
(click)="setMode(displayMode.Blank)"
[disabled]="display.displayMode === displayMode.Blank">
<mat-icon class="small-icon">videocam_off</mat-icon>
<span id="caption-blank" class="caption">{{ 'SHOW_BLACK' | translate }}</span>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-blank" class="caption">{{ 'SHOW_BLACK' | translate }}</div>
</mat-grid-tile>
<mat-grid-tile>
<button mat-fab color="primary"
<button
mat-list-item
aria-labelledby="caption-theme"
class="display-button"
(click)="setMode(DisplayMode.Theme)"
[disabled]="displayMode === DisplayMode.Theme">
<mat-icon class="big-icon">wallpaper</mat-icon>
(click)="setMode(displayMode.Theme)"
[disabled]="display.displayMode === displayMode.Theme">
<mat-icon class="small-icon">wallpaper</mat-icon>
<span id="caption-theme" class="caption">{{ 'SHOW_BACKGROUND' | translate }}</span>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-theme" class="caption">{{ 'SHOW_BACKGROUND' | translate }}</div>
</mat-grid-tile>
<mat-grid-tile>
<button mat-fab color="primary"
<button
mat-list-item
aria-labelledby="caption-desktop"
class="display-button"
(click)="setMode(DisplayMode.Desktop)"
[disabled]="displayMode === DisplayMode.Desktop">
<mat-icon class="big-icon">desktop_windows</mat-icon>
(click)="setMode(displayMode.Desktop)"
[disabled]="display.displayMode === displayMode.Desktop">
<mat-icon class="small-icon">desktop_windows</mat-icon>
<span id="caption-desktop" class="caption">{{ 'SHOW_DESKTOP' | translate }}</span>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-desktop" class="caption">{{ 'SHOW_DESKTOP' | translate }}</div>
</mat-grid-tile>
<mat-grid-tile>
<button mat-fab color="primary"
<button
mat-list-item
aria-labelledby="caption-presentation"
class="display-button"
(click)="setMode(DisplayMode.Presentation)"
[disabled]="displayMode === DisplayMode.Presentation">
<mat-icon class="big-icon">videocam</mat-icon>
(click)="setMode(displayMode.Presentation)"
[disabled]="display.displayMode === displayMode.Presentation">
<mat-icon class="small-icon">videocam</mat-icon>
<span id="caption-presentation" class="caption">{{ 'SHOW_PRESENTATION' | translate }}</span>
</button>
</mat-grid-tile>
<mat-grid-tile>
<div id="caption-presentation" class="caption">{{ 'SHOW_PRESENTATION' | translate }}</div>
</mat-grid-tile>
</mat-grid-list>
</mat-action-list>
}

View File

@ -5,11 +5,11 @@ import { Display, DisplayMode } from 'src/app/responses';
@Component({
selector: 'openlp-display-mode-sheet',
templateUrl: 'display-mode-selector.component.html',
styleUrls: ['./display-mode-selector.component.scss']
styleUrl: './display-mode-selector.component.scss'
})
export class DisplayModeSelectorComponent {
// Make DisplayMode enum visible in HTML template.
DisplayMode = DisplayMode;
displayMode = DisplayMode;
constructor(
private bottomSheetRef: MatBottomSheetRef<DisplayModeSelectorComponent>,

View File

@ -3,14 +3,16 @@
<form #loginForm="ngForm">
<div mat-dialog-content>
<mat-form-field>
<input matInput
<input
matInput
placeholder="{{ 'USER_NAME' | translate }}"
[(ngModel)]="username"
name="username"
required>
</mat-form-field>
<mat-form-field>
<input matInput
<input
matInput
placeholder="{{ 'PASSWORD' | translate }}"
type="password"
[(ngModel)]="password"

View File

@ -1,30 +1,41 @@
import { Component, OnInit } from '@angular/core';
import { Component } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { TranslateService } from '@ngx-translate/core';
import { OpenLPService } from '../../openlp.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
styleUrl: './login.component.scss'
})
export class LoginComponent implements OnInit {
export class LoginComponent {
username: string;
password: string;
constructor(private dialogRef: MatDialogRef<LoginComponent>, private openlpService: OpenLPService,
private snackBar: MatSnackBar) { }
ngOnInit() {
// Do nothing
loginSucceededMessage: string;
loginFailedMessage: string;
constructor(
private dialogRef: MatDialogRef<LoginComponent>,
private openlpService: OpenLPService,
private snackBar: MatSnackBar,
private translateService: TranslateService) {
this.translateService.stream('LOGIN_SUCCEEDED').subscribe(res => {
this.loginSucceededMessage = res;
});
this.translateService.stream('LOGIN_FAILED').subscribe(res => {
this.loginFailedMessage = res;
});
}
performLogin() {
this.openlpService.login({username: this.username, password: this.password}).subscribe(
result => {
this.snackBar.open('Successfully logged in', '', {duration: 2000});
this.openlpService.login({ username: this.username, password: this.password }).subscribe({
next: result => {
this.snackBar.open(this.loginSucceededMessage, '', { duration: 2000 });
this.dialogRef.close(result);
},
() => this.snackBar.open('Login failed', '', {duration: 2000})
);
error: () => this.snackBar.open(this.loginFailedMessage, '', { duration: 2000 })
});
}
}

View File

@ -1,6 +1,9 @@
<div class="lower-third">
<div class="slide">
<div class="slide-item" [style.font-size]="fontSize" [style.font-family]="fontFamily">
<div
class="slide-item"
[style.font-size]="fontSize"
[style.font-family]="fontFamily">
{{currentSlides[activeSlide]?.text}}
</div>
</div>

View File

@ -8,7 +8,7 @@ import { ServiceItem, Slide } from '../../responses';
@Component({
selector: 'app-lower-third',
templateUrl: './lower-third.component.html',
styleUrls: ['./lower-third.component.scss'],
styleUrl: './lower-third.component.scss',
encapsulation: ViewEncapsulation.None
})
export class LowerThirdComponent implements OnInit, OnDestroy {

View File

@ -1,8 +1,16 @@
<mat-form-field >
<mat-select [(ngModel)]="selectedSearchOption" (selectionChange)="setSearchOption($event)" name="selectedSearchOption" [placeholder]="searchOptionsTitle">
<mat-option *ngFor="let option of searchOptions" name="searchOptions" [value]="option">
{{option}}
</mat-option>
<mat-select
[(ngModel)]="selectedSearchOption"
(selectionChange)="setSearchOption($event)"
name="selectedSearchOption"
[placeholder]="searchOptionsTitle">
@for (option of searchOptions; track option) {
<mat-option
name="searchOptions"
[value]="option">
{{ option }}
</mat-option>
}
</mat-select>
</mat-form-field>
<br>

View File

@ -1,26 +1,31 @@
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { OpenLPService } from '../../../openlp.service';
@Component({
selector: 'openlp-search-options',
templateUrl: './search-options.component.html',
styleUrls: ['./search-options.component.scss'],
styleUrl: './search-options.component.scss',
providers: [OpenLPService]
})
export class SearchOptionsComponent {
public selectedPlugin: string;
public searchOptions: Array<string>;
public selectedSearchOption: string;
public searchOptionsTitle = '';
public searchOptionsTitle: string;
constructor(private openlpService: OpenLPService) {}
constructor(
private openlpService: OpenLPService,
private translateService: TranslateService) { }
// Used to display search-options for certain plugins
onPluginChange(plugin) {
this.selectedPlugin = plugin;
if (this.selectedPlugin === 'bibles') {
this.searchOptionsTitle = 'Bible version:';
this.translateService.stream('BIBLE_VERSION').subscribe(res => {
this.searchOptionsTitle = res + ':';
});
this.getSearchOptions();
}
}

View File

@ -1,10 +1,18 @@
<h3>Search</h3>
<h3>{{ 'SEARCH' | translate }}</h3>
<form #searchForm="ngForm">
<mat-form-field>
<mat-select [(ngModel)]="selectedPlugin" (selectionChange)="onPluginChange()" name="selectedPlugin" placeholder="Search for:">
<mat-option *ngFor="let plugin of searchPlugins" name="searchPlugins" [value]="plugin.key">
{{plugin.name}}
</mat-option>
<mat-select
[(ngModel)]="selectedPlugin"
(selectionChange)="onPluginChange()"
name="selectedPlugin"
placeholder="Search for:">
@for (plugin of searchPlugins; track plugin.name) {
<mat-option
name="searchPlugins"
[value]="plugin.key">
{{ plugin.name }}
</mat-option>
}
</mat-select>
</mat-form-field>
<br>
@ -12,36 +20,53 @@
<openlp-search-options></openlp-search-options>
</div>
<mat-form-field>
<input matInput [(ngModel)]="searchText" name="searchText" placeholder="{{ 'SEARCH_TEXT' | translate }}" required>
<input
matInput
[(ngModel)]="searchText"
name="searchText"
placeholder="{{ 'SEARCH_TEXT' | translate }}"
required>
</mat-form-field>
<br>
<button mat-raised-button id="searchButton"
<button
mat-raised-button
id="searchButton"
color="primary"
[disabled]="!searchForm.form.valid"
(click)="onSubmit()">
{{ 'SEARCH' | translate }}
</button>
</form>
<div *ngIf="searchResults">
<h3>{{ 'SEARCH_RESULTS' | translate }}:</h3>
<div *ngIf="!searchResults.length">
{{ 'NO_SEARCH_RESULTS' | translate }}...
@if (searchResults) {
<div>
<h3>{{ 'SEARCH_RESULTS' | translate }}:</h3>
@if (searchResults.length) {
<table>
@for (item of searchResults; track item) {
<tr>
<td>{{ item[1] }}</td>
<td>
<button
mat-button color="primary"
(click)="addToService(item[0])">
{{ 'ADD_TO_SERVICE' | translate }}
</button>
</td>
<td>
<button
mat-button color="accent"
(click)="sendLive(item[0])">
{{ 'SEND_LIVE' | translate }}
</button>
</td>
</tr>
}
</table>
}
@else {
<div>
{{ 'NO_SEARCH_RESULTS' | translate }}...
</div>
}
</div>
<table *ngIf="searchResults.length">
<tr *ngFor="let item of searchResults">
<td>{{item[1]}}</td>
<td>
<button mat-button color="primary"
(click)="addToService(item[0])">
{{ 'ADD_TO_SERVICE' | translate }}
</button>
</td>
<td>
<button mat-button color="accent"
(click)="sendLive(item[0])">
{{ 'SEND_LIVE' | translate }}
</button>
</td>
</tr>
</table>
</div>
}

View File

@ -1,4 +1,5 @@
import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { OpenLPService } from '../../openlp.service';
import { PageTitleService } from '../../page-title.service';
@ -8,7 +9,7 @@ import { SearchOptionsComponent } from './search-options/search-options.componen
@Component({
selector: 'openlp-search',
templateUrl: './search.component.html',
styleUrls: ['./search.component.scss'],
styleUrl: './search.component.scss',
providers: [OpenLPService]
})
export class SearchComponent implements OnInit, AfterViewInit {
@ -20,9 +21,14 @@ export class SearchComponent implements OnInit, AfterViewInit {
public displaySearchOptions = false;
@ViewChild(SearchOptionsComponent, {static: false}) searchOptions: SearchOptionsComponent;
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService,
private cdr: ChangeDetectorRef) {
pageTitleService.changePageTitle('Search');
constructor(
private pageTitleService: PageTitleService,
private openlpService: OpenLPService,
private cdr: ChangeDetectorRef,
private translateService: TranslateService) {
this.translateService.stream('SEARCH').subscribe(res => {
this.pageTitleService.changePageTitle(res);
});
}
onSubmit() {

View File

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

View File

@ -5,7 +5,7 @@ import { ServiceItem } from '../../../responses';
@Component({
selector: 'openlp-service-item',
templateUrl: './service-item.component.html',
styleUrls: ['./service-item.component.scss'],
styleUrl: './service-item.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})

View File

@ -1,22 +1,29 @@
<ng-container *ngIf="items?.length; else noServiceItems">
<openlp-service-item
*ngFor="let item of items"
[item]="item"
[selected]="item.selected"
(selectItem)="onItemSelected($event)"
[tabindex]="item.id"></openlp-service-item>
</ng-container>
<ng-template #noServiceItems>
<div class="no-items" *ngIf="!loading">
@if (items?.length) {
<ng-container>
@for (item of items; track item) {
<openlp-service-item
[item]="item"
[selected]="item.selected"
(selectItem)="onItemSelected($event)"
[tabindex]="item.id">
</openlp-service-item>
}
</ng-container>
}
@else if (!loading) {
<div class="no-items">
<div class="no-items-title">
<span class="material-icons icon">info</span>
{{ 'NO_SERVICE_ITEMS' | translate }}.
</div>
<div class="no-items-actions">
<a routerLink="/search" mat-stroked-button color="primary" size="small">
<a
routerLink="/search"
mat-stroked-button color="primary"
size="small">
<span class="material-icons">add</span>
{{ 'ADD_ITEM' | translate }}
</a>
</div>
</div>
</ng-template>
}

View File

@ -1 +1,3 @@
<openlp-service-list (itemSelected)="this.onItemSelected($event)"></openlp-service-list>
<openlp-service-list
(itemSelected)="this.onItemSelected($event)">
</openlp-service-list>

View File

@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { OpenLPService } from '../../openlp.service';
import { PageTitleService } from '../../page-title.service';
@ -8,7 +9,7 @@ import { ServiceItem } from '../../responses';
@Component({
selector: 'openlp-service',
templateUrl: './service.component.html',
styleUrls: ['./service.component.scss'],
styleUrl: './service.component.scss',
})
export class ServiceComponent {
@ -19,8 +20,13 @@ export class ServiceComponent {
}
}
constructor(protected pageTitleService: PageTitleService, protected openlpService: OpenLPService,
protected router: Router) {
pageTitleService.changePageTitle('Service');
constructor(
protected pageTitleService: PageTitleService,
protected openlpService: OpenLPService,
protected router: Router,
private translateService: TranslateService) {
this.translateService.stream('SERVICE').subscribe(res => {
this.pageTitleService.changePageTitle(res);
});
}
}

View File

@ -1,64 +1,70 @@
<div class="settings-panel">
<mat-card>
<mat-card-header>
{{ 'USER_INTERFACE' | translate }}
</mat-card-header>
<mat-card-content>
<div class="settings-item">
<mat-slide-toggle
color="primary"
[checked]="settings.fastSwitching"
(change)="setSetting('fastSwitching', $event.checked)">
{{ 'ENABLE_FAST_SWITCHING_PANEL' | translate }}
</mat-slide-toggle>
</div>
<div class="settings-item">
<mat-slide-toggle
color="primary"
[checked]="settings.bigDisplayButtons"
(change)="setSetting('bigDisplayButtons', $event.checked)">
{{ 'ENABLE_BIG_DISPLAY_BUTTONS' | translate }}
</mat-slide-toggle>
</div>
</mat-card-content>
<mat-card>
<mat-card-header>
{{ 'USER_INTERFACE' | translate }}
</mat-card-header>
<mat-card-content>
<div class="settings-item">
<mat-slide-toggle
color="primary"
[checked]="settings.fastSwitching"
(change)="setSetting('fastSwitching', $event.checked)">
{{ 'ENABLE_FAST_SWITCHING_PANEL' | translate }}
</mat-slide-toggle>
</div>
<div class="settings-item">
<mat-slide-toggle
color="primary"
[checked]="settings.bigDisplayButtons"
(change)="setSetting('bigDisplayButtons', $event.checked)">
{{ 'ENABLE_BIG_DISPLAY_BUTTONS' | translate }}
</mat-slide-toggle>
</div>
</mat-card-content>
</mat-card>
<mat-card>
<mat-card-header>
{{ 'STAGE_AND_CHORDS_APPEARANCE' | translate }}
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab label="{{ 'STAGE' | translate }}">
<ng-template matTabContent>
<ng-container>
<openlp-stage-chord-preview stageType="stage"></openlp-stage-chord-preview>
<ng-container *ngTemplateOutlet="stageSettings; context: {prefix: 'stage'}"></ng-container>
</ng-container>
</ng-template>
</mat-tab>
<mat-tab label="{{ 'CHORDS' | translate }}">
<ng-template matTabContent>
<openlp-stage-chord-preview stageType="chords"></openlp-stage-chord-preview>
<ng-container *ngTemplateOutlet="stageSettings; context: {prefix: 'chords'}"></ng-container>
</ng-template>
</mat-tab>
</mat-tab-group>
</mat-card-content>
<mat-card-header>
{{ 'STAGE_AND_CHORDS_APPEARANCE' | translate }}
</mat-card-header>
<mat-card-content>
<mat-tab-group>
<mat-tab label="{{ 'STAGE' | translate }}">
<ng-template matTabContent>
<ng-container>
<openlp-stage-chord-preview stageType="stage">
</openlp-stage-chord-preview>
<ng-container *ngTemplateOutlet="stageSettings; context: {prefix: 'stage'}">
</ng-container>
</ng-container>
</ng-template>
</mat-tab>
<mat-tab label="{{ 'CHORDS' | translate }}">
<ng-template matTabContent>
<openlp-stage-chord-preview stageType="chords">
</openlp-stage-chord-preview>
<ng-container *ngTemplateOutlet="stageSettings; context: {prefix: 'chords'}">
</ng-container>
</ng-template>
</mat-tab>
</mat-tab-group>
</mat-card-content>
</mat-card>
</div>
<ng-template #stageSettings let-prefix="prefix">
<div class="stage-settings">
<div class="settings-item">
<label>{{ 'FONT_SCALE' | translate }}: {{settings[prefix + 'FontScale'] ?? 100}}%</label>
<mat-slider
min="25"
max="200"
step="6.25">
<input
matSliderThumb
[value]="settings[prefix + 'FontScale']"
(valueChange)="setSetting(prefix + 'FontScale', $event)">
</mat-slider>
</div>
<ng-template
#stageSettings
let-prefix="prefix">
<div class="stage-settings">
<div class="settings-item">
<label>{{ 'FONT_SCALE' | translate }}: {{settings[prefix + 'FontScale'] ?? 100}}%</label>
<mat-slider
min="25"
max="200"
step="6.25">
<input
matSliderThumb
[value]="settings[prefix + 'FontScale']"
(valueChange)="setSetting(prefix + 'FontScale', $event)">
</mat-slider>
</div>
</div>
</ng-template>

View File

@ -1,4 +1,5 @@
import { Component, OnDestroy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
import { OpenLPService } from '../../openlp.service';
import { PageTitleService } from '../../page-title.service';
@ -6,17 +7,19 @@ import { SettingsProperties, SettingsPropertiesItem, SettingsService } from '../
@Component({
selector: 'openlp-settings',
templateUrl: `./settings.component.html`,
styleUrls: [`./settings.component.scss`]
templateUrl: './settings.component.html',
styleUrl: './settings.component.scss'
})
export class SettingsComponent implements OnDestroy {
constructor(
protected pageTitleService: PageTitleService,
protected openlpService: OpenLPService,
protected settingsService: SettingsService,
) {
private translateService: TranslateService) {
this.settingsSubscription$ = settingsService.settingChanged$.subscribe(this._settingChanged);
pageTitleService.changePageTitle('Settings');
this.translateService.stream('SETTINGS').subscribe(res => {
this.pageTitleService.changePageTitle(res);
});
}
protected settingsSubscription$: Subscription;
@ -36,5 +39,4 @@ export class SettingsComponent implements OnDestroy {
ngOnDestroy(): void {
this.settingsSubscription$.unsubscribe();
}
}

View File

@ -1,14 +1,18 @@
<div class="stage-preview-container" #stageViewContainer>
<div
class="stage-preview-container"
#stageViewContainer>
@if (stageType === 'stage') {
<app-stage-view
#stageView
*ngIf="stageType === 'stage'"
[embedded]="true"
[style.--openlp-stage-font-scale]="fontScale"
></app-stage-view>
#stageView
[embedded]="true"
[style.--openlp-stage-font-scale]="fontScale">
</app-stage-view>
}
@else if (stageType === 'chords') {
<app-chord-view
#chordsView
*ngIf="stageType === 'chords'"
[embedded]="true"
[style.--openlp-stage-font-scale]="fontScale"
></app-chord-view>
#chordsView
[embedded]="true"
[style.--openlp-stage-font-scale]="fontScale">
</app-chord-view>
}
</div>

View File

@ -17,7 +17,7 @@ import { SettingsProperties, SettingsService } from 'src/app/settings.service';
@Component({
selector: 'openlp-stage-chord-preview',
templateUrl: './stage-chord-preview.component.html',
styleUrls: ['./stage-chord-preview.component.scss'],
styleUrl: './stage-chord-preview.component.scss',
})
export class StageChordPreviewComponent implements OnInit, AfterViewInit, OnDestroy, OnChanges {
constructor(

View File

@ -1,14 +1,20 @@
<mat-card class="slide no-select" mat-list-item (click)="onSlideSelected(slide)" [class.selected]="selected">
<mat-card
class="slide no-select"
mat-list-item
(click)="onSlideSelected(slide)"
[class.selected]="selected">
<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 }}
@if (slide?.img) {
<div class="verse-img-container">
<img src="{{ slide?.img }}" />
<div class="img-verse-text">
{{ slide?.text }}
</div>
</div>
</div>
<ng-template #onlySlideText>
}
@else {
<div class="verse-text">{{ slide?.text }}</div>
</ng-template>
}
</mat-card-content>
</mat-card>

View File

@ -4,7 +4,7 @@ import { Slide } from '../../../responses';
@Component({
selector: 'openlp-slide-item',
templateUrl: './slide-item.component.html',
styleUrls: ['./slide-item.component.scss'],
styleUrl: './slide-item.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush
})

View File

@ -1,23 +1,32 @@
<ng-container *ngIf="slides?.length; else noSlideItems">
<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>
</ng-container>
<ng-template #noSlideItems>
<div class="no-items" *ngIf="!loading">
<div class="no-items-title">
<span class="material-icons icon">info</span>
{{ 'NO_SLIDE_ITEMS' | translate }}.
@if (slides?.length) {
<ng-container>
@for (slide of slides; track slide; let index = $index) {
<openlp-slide-item
[slide]="slide"
[tabindex]="index"
[selected]="slide.selected"
(selectSlide)="onSlideSelected($event, index)">
</openlp-slide-item>
}
</ng-container>
}
@else {
@if (!loading) {
<div class="no-items">
<div class="no-items-title">
<span class="material-icons icon">info</span>
{{ 'NO_SLIDE_ITEMS' | translate }}.
</div>
<div class="no-items-actions">
<a
routerLink="/search"
mat-stroked-button
color="primary"
size="small">
<span class="material-icons">add</span>
{{ 'ADD_ITEM_TO_SERVICE' | translate }}
</a>
</div>
</div>
<div class="no-items-actions">
<a routerLink="/search" mat-stroked-button color="primary" size="small">
<span class="material-icons">add</span>
{{ 'ADD_ITEM_TO_SERVICE' | translate }}
</a>
</div>
</div>
</ng-template>
}
}

View File

@ -1 +1,2 @@
<openlp-slide-list (slideSelected)="onSlideSelected($event)"></openlp-slide-list>
<openlp-slide-list (slideSelected)="onSlideSelected($event)">
</openlp-slide-list>

View File

@ -1,4 +1,5 @@
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { OpenLPService } from '../../openlp.service';
import { PageTitleService } from '../../page-title.service';
@ -7,12 +8,17 @@ import { SlideListItem } from './slide-list/slide-list.component';
@Component({
selector: 'openlp-slides',
templateUrl: './slides.component.html',
styleUrls: ['./slides.component.scss'],
styleUrl: './slides.component.scss',
})
export class SlidesComponent {
constructor(protected pageTitleService: PageTitleService, protected openlpService: OpenLPService) {
pageTitleService.changePageTitle('Slides');
constructor(
protected pageTitleService: PageTitleService,
protected openlpService: OpenLPService,
private translateService: TranslateService) {
this.translateService.stream('SLIDES').subscribe(res => {
this.pageTitleService.changePageTitle(res);
});
}
onSlideSelected(item: SlideListItem) {

View File

@ -1,14 +1,21 @@
<div
class="slide"
[class.mat-headline-2]="active"
[class.currentSlide]="active"
[class.mat-headline-4]="!active"
[class.first]="!active && slide.first_slide_of_tag">
<ng-container *ngIf="!(slide?.img); else elseImage">
{{slide?.text}}
class="slide"
[class.mat-headline-2]="active"
[class.currentSlide]="active"
[class.mat-headline-4]="!active"
[class.first]="!active && slide.first_slide_of_tag">
@if (slide?.img) {
<img
src="{{slide?.img}}"
[class.active-slide-img]="active"
[class.next-slides-img]="!active"/>
<div
[class.active-slide-img-text]="active"
[class.next-slides-text]="!active">{{ slide?.text }}</div>
}
@else {
<ng-container>
{{ slide?.text }}
</ng-container>
<ng-template #elseImage>
<img src="{{slide?.img}}" [class.active-slide-img]="active" [class.next-slides-img]="!active"/>
<div [class.active-slide-img-text]="active" [class.next-slides-text]="!active">{{ slide?.text }}</div>
</ng-template>
}
</div>

View File

@ -4,49 +4,67 @@
[style.--openlp-stage-font-scale]="fontScale">
<div class="overlay-content">
<div class="tags">
<span *ngFor="let tag of tags" [class.active]="tag.active">{{ tag.text }}</span>
@for (tag of tags; track tag) {
<span [class.active]="tag.active">{{ tag.text }}</span>
}
</div>
<div class="container">
<app-stage-view-item [slide]="currentSlides[activeSlide]" [active]="true"></app-stage-view-item>
<app-stage-view-item
[slide]="currentSlides[activeSlide]"
[active]="true">
</app-stage-view-item>
<div class="nextSlides">
<app-stage-view-item [slide]="slide" *ngFor="let slide of nextSlides; trackBy: trackByIndex"></app-stage-view-item>
@for (slide of nextSlides; track trackByIndex) {
<app-stage-view-item [slide]="slide">
</app-stage-view-item>
}
</div>
</div>
</div>
<div class="toolbar">
<a *ngIf="!embedded"
class="back-button"
mat-mini-fab color=""
routerLink="/"
matTooltip="{{ 'GO_BACK_TO_CONTROLLER' | translate }}">
<mat-icon>arrow_back</mat-icon>
</a>
<button *ngIf="showNotes"
mat-mini-fab
class="show-notes"
matTooltip="{{ 'HIDE_NOTES' | translate }}"
[color]="primary"
[class.show-notes-disabled]="false"
(click)="showNotes = false">
<mat-icon>sticky_note_2</mat-icon>
</button>
<button *ngIf="!showNotes"
mat-mini-fab
class="show-notes"
matTooltip="{{ 'SHOW_NOTES' | translate }}"
[color]=""
[class.show-notes-disabled]="true"
(click)="showNotes = true">
<mat-icon>sticky_note_2</mat-icon>
</button>
<div *ngIf="!embedded && activeSlide+1 === currentSlides.length"
class="next-service-item"
matTooltip="{{ 'NEXT_ITEM' | translate }}">
{{ nextServiceItemTitle }}
</div>
@if (!embedded) {
<a
class="back-button"
mat-mini-fab color=""
routerLink="/"
matTooltip="{{ 'GO_BACK_TO_CONTROLLER' | translate }}">
<mat-icon>arrow_back</mat-icon>
</a>
}
@if (showNotes) {
<button
mat-mini-fab
class="show-notes"
matTooltip="{{ 'HIDE_NOTES' | translate }}"
color="primary"
[class.show-notes-disabled]="false"
(click)="showNotes = false">
<mat-icon>sticky_note_2</mat-icon>
</button>
}
@else {
<button
mat-mini-fab
class="show-notes"
matTooltip="{{ 'SHOW_NOTES' | translate }}"
color=""
[class.show-notes-disabled]="true"
(click)="showNotes = true">
<mat-icon>sticky_note_2</mat-icon>
</button>
}
@if (!embedded && activeSlide+1 === currentSlides.length) {
<div
class="next-service-item"
matTooltip="{{ 'NEXT_ITEM' | translate }}">
{{ nextServiceItemTitle }}
</div>
}
<div class="time">{{ (openlpService.getIsTwelveHourTime()) ? (time|date:'h:mm a') : (time|date:'HH:mm') }}</div>
</div>
<div class="sidebar" *ngIf="(showNotes || embedded) && notes">
<div class="notes" [innerHTML]="notes|nl2br"></div>
</div>
@if ((showNotes || embedded) && notes) {
<div class="sidebar">
<div class="notes" [innerHTML]="notes|nl2br"></div>
</div>
}
</div>

View File

@ -97,7 +97,7 @@ export class StageViewComponent implements OnInit, OnDestroy {
}
setNewSlides(slides: Slide[], _currentSlide: number): void { /* eslint-disable-line @typescript-eslint/no-unused-vars */
if (slides.length === 0) {
if ((slides?.length ?? 0) === 0) {
return;
}
this.currentSlides = slides;

View File

@ -10,17 +10,26 @@
</mat-select>
</mat-form-field>
</div>
<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">
<mat-card-content>
<img [src]="theme.thumbnail"/>
<div class="theme-title">{{ theme.name }}</div>
</mat-card-content>
</mat-card>
@if (isThemeLevelSupported()) {
<div class="theme-container content">
@for (theme of themeList; track theme) {
<div>
<mat-card
class="theme-card"
(click)='setTheme(theme.name)'
[class.selected]="theme.selected">
<mat-card-content>
<img [src]="theme.thumbnail"/>
<div class="theme-title">{{ theme.name }}</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
<mat-error *ngIf="!isThemeLevelSupported()">
{{ 'SONG_LEVEL_THEME_CHANGING_NOT_SUPPORTED' | translate }}
</mat-error>
}
@else {
<mat-error>
{{ 'SONG_LEVEL_THEME_CHANGING_NOT_SUPPORTED' | translate }}
</mat-error>
}
</form>

View File

@ -1,11 +1,14 @@
import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { OpenLPService } from '../../openlp.service';
import { PageTitleService } from '../../page-title.service';
import { Theme } from '../../responses';
@Component({
selector: 'openlp-themes',
templateUrl: './themes.component.html',
styleUrls: ['./themes.component.scss'],
styleUrl: './themes.component.scss',
providers: [OpenLPService]
})
export class ThemesComponent implements OnInit {
@ -13,8 +16,13 @@ export class ThemesComponent implements OnInit {
private _themeList = [];
private _themeLevel = null;
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService) {
pageTitleService.changePageTitle('Themes');
constructor(
private pageTitleService: PageTitleService,
private openlpService: OpenLPService,
private translateService: TranslateService) {
this.translateService.stream('THEMES').subscribe(res => {
this.pageTitleService.changePageTitle(res);
});
}
ngOnInit() {
@ -22,7 +30,7 @@ export class ThemesComponent implements OnInit {
this.getThemes();
}
get themeList(): Array<string> {
get themeList(): Array<Theme> {
return this._themeList;
}

View File

@ -63,8 +63,9 @@ export interface ServiceItem {
}
export interface Theme {
selected: boolean;
name: string;
selected: boolean;
thumbnail: object;
}
export interface Language {

View File

@ -1,5 +1,4 @@
import { TestBed } from '@angular/core/testing';
import { WindowRef} from './window-ref.service';
describe('WindowRef', () => {

View File

@ -4,7 +4,9 @@
"ADD_ITEM_TO_SERVICE": "Add Item to Service",
"ADD_TO_SERVICE": "Add to Service",
"ALERT": "Alert",
"ALERT_SUBMITTED": "Alert Submitted",
"ALERTS": "Alerts",
"BIBLE_VERSION": "Bible version",
"CHANGE_DISPLAY_MODE": "Change Display Mode",
"CHORD_VIEW": "Chord View",
"CHORDS": "Chords",
@ -17,6 +19,8 @@
"GO_BACK_TO_CONTROLLER": "Go Back to Controller",
"HIDE_NOTES": "Hide Notes",
"LOGIN": "Login",
"LOGIN_FAILED": "Login failed",
"LOGIN_SUCCEEDED": "Successfully logged in",
"MAIN_VIEW": "Main View",
"NEXT_ITEM": "Next Item",
"NEXT_SLIDE": "Next Slide",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Voeg Item By Diens",
"ADD_TO_SERVICE": "Voeg By Diens",
"ALERT": "Waarskuwing",
"ALERT_SUBMITTED": "Waarskuwing Ingedien",
"ALERTS": "Waarskuwings",
"BIBLE_VERSION": "Bybel weergawe",
"CHANGE_DISPLAY_MODE": "Verander Vertoonmodus",
"CHORD_VIEW": "Akkoordaansig",
"CHORDS": "Akkoorde",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Gaan Terug na Kontroleerder",
"HIDE_NOTES": "Versteek Notas",
"LOGIN": "Teken In",
"LOGIN_FAILED": "Aanmelding het misluk",
"LOGIN_SUCCEEDED": "Suksesvol aangemeld",
"MAIN_VIEW": "Hoofaansig",
"NEXT_ITEM": "Volgende Item",
"NEXT_SLIDE": "Volgende Skyfie",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Добави елемент към услугата",
"ADD_TO_SERVICE": "Добави към услугата",
"ALERT": "Предупреждение",
"ALERT_SUBMITTED": "Подадено предупреждение",
"ALERTS": "Предупреждения",
"BIBLE_VERSION": "Библейска версия",
"CHANGE_DISPLAY_MODE": "Промени режима на дисплея",
"CHORD_VIEW": "Преглед на акорди",
"CHORDS": "Акорди",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Върни се към контролера",
"HIDE_NOTES": "Скрий бележките",
"LOGIN": "Вход",
"LOGIN_FAILED": "Неуспешно влизане",
"LOGIN_SUCCEEDED": "Успешно влизане",
"MAIN_VIEW": "Основен изглед",
"NEXT_ITEM": "Следващ елемент",
"NEXT_SLIDE": "Следващ слайд",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Přidat Položku do Služby",
"ADD_TO_SERVICE": "Přidat do Služby",
"ALERT": "Upozornění",
"ALERT_SUBMITTED": "Výstraha Odeslána",
"ALERTS": "Upozornění",
"BIBLE_VERSION": "Biblická verze",
"CHANGE_DISPLAY_MODE": "Změnit Režim Zobrazení",
"CHORD_VIEW": "Zobrazení Akordů",
"CHORDS": "Akordy",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Vrátit se Zpět k Ovladači",
"HIDE_NOTES": "Skrýt Poznámky",
"LOGIN": "Přihlásit Se",
"LOGIN_FAILED": "Přihlášení se nezdařilo",
"LOGIN_SUCCEEDED": "Úspěšně přihlášeno",
"MAIN_VIEW": "Hlavní Zobrazení",
"NEXT_ITEM": "Další Položka",
"NEXT_SLIDE": "Další Snímek",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Tilføj Emne til Tjeneste",
"ADD_TO_SERVICE": "Tilføj til Tjeneste",
"ALERT": "Advarsel",
"ALERT_SUBMITTED": "Advarsel Indsendt",
"ALERTS": "Advarsler",
"BIBLE_VERSION": "Bibelsk udgave",
"CHANGE_DISPLAY_MODE": "Skift Visningstilstand",
"CHORD_VIEW": "Akkordvisning",
"CHORDS": "Akkorder",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Gå Tilbage til Controller",
"HIDE_NOTES": "Skjul Noter",
"LOGIN": "Log Ind",
"LOGIN_FAILED": "Login mislykkedes",
"LOGIN_SUCCEEDED": "Logget ind",
"MAIN_VIEW": "Hovedvisning",
"NEXT_ITEM": "Næste Emne",
"NEXT_SLIDE": "Næste Dias",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Element zum Ablauf Hinzufügen",
"ADD_TO_SERVICE": "Zum Ablauf Hinzufügen",
"ALERT": "Hinweise",
"ALERT_SUBMITTED": "Hinweise Übermittelt",
"ALERTS": "Hinweisen",
"BIBLE_VERSION": "Bibelübersetzung",
"CHANGE_DISPLAY_MODE": "Anzeigemodus Ändern",
"CHORD_VIEW": "Akkordansicht",
"CHORDS": "Akkorde",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Zurück zum Controller",
"HIDE_NOTES": "Notizen Ausblenden",
"LOGIN": "Anmelden",
"LOGIN_FAILED": "Anmeldung fehlgeschlagen",
"LOGIN_SUCCEEDED": "Erfolgreich eingeloggt",
"MAIN_VIEW": "Hauptansicht",
"NEXT_ITEM": "Nächstes Element",
"NEXT_SLIDE": "Nächste Folie",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Προσθήκη στοιχείου στην υπηρεσία",
"ADD_TO_SERVICE": "Προσθήκη στην υπηρεσία",
"ALERT": "Ειδοποίηση",
"ALERT_SUBMITTED": "Η ειδοποίηση υποβλήθηκε",
"ALERTS": "Ειδοποιήσεις",
"BIBLE_VERSION": "Βιβλική έκδοση",
"CHANGE_DISPLAY_MODE": "Αλλαγή λειτουργίας εμφάνισης",
"CHORD_VIEW": "Προβολή συγχορδιών",
"CHORDS": "Συγχορδίες",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Επιστροφή στον ελεγκτή",
"HIDE_NOTES": "Απόκρυψη σημειώσεων",
"LOGIN": "Σύνδεση",
"LOGIN_FAILED": "Η σύνδεση απέτυχε",
"LOGIN_SUCCEEDED": "Συνδέθηκε με επιτυχία",
"MAIN_VIEW": "Κύρια προβολή",
"NEXT_ITEM": "Επόμενο στοιχείο",
"NEXT_SLIDE": "Επόμενη διαφάνεια",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Add Item to Service",
"ADD_TO_SERVICE": "Add to Service",
"ALERT": "Alert",
"ALERT_SUBMITTED": "Alert Submitted",
"ALERTS": "Alerts",
"BIBLE_VERSION": "Bible version",
"CHANGE_DISPLAY_MODE": "Change Display Mode",
"CHORD_VIEW": "Chord View",
"CHORDS": "Chords",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Go Back to Controller",
"HIDE_NOTES": "Hide Notes",
"LOGIN": "Login",
"LOGIN_FAILED": "Login failed",
"LOGIN_SUCCEEDED": "Successfully logged in",
"MAIN_VIEW": "Main View",
"NEXT_ITEM": "Next Item",
"NEXT_SLIDE": "Next Slide",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Add Item to Service",
"ADD_TO_SERVICE": "Add to Service",
"ALERT": "Alert",
"ALERT_SUBMITTED": "Alert Submitted",
"ALERTS": "Alerts",
"BIBLE_VERSION": "Bible version",
"CHANGE_DISPLAY_MODE": "Change Display Mode",
"CHORD_VIEW": "Chord View",
"CHORDS": "Chords",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Go Back to Controller",
"HIDE_NOTES": "Hide Notes",
"LOGIN": "Login",
"LOGIN_FAILED": "Login failed",
"LOGIN_SUCCEEDED": "Successfully logged in",
"MAIN_VIEW": "Main View",
"NEXT_ITEM": "Next Item",
"NEXT_SLIDE": "Next Slide",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Agregar Elemento al Servicio",
"ADD_TO_SERVICE": "Agregar al Servicio",
"ALERT": "Alerta",
"ALERT_SUBMITTED": "Alerta Enviada",
"ALERTS": "Alertas",
"BIBLE_VERSION": "Versión de la Biblia",
"CHANGE_DISPLAY_MODE": "Cambiar Modo de Visualización",
"CHORD_VIEW": "Vista de Acordes",
"CHORDS": "Acordes",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Volver al Controlador",
"HIDE_NOTES": "Ocultar Notas",
"LOGIN": "Iniciar Sesión",
"LOGIN_FAILED": "Error de inicio de sesión",
"LOGIN_SUCCEEDED": "Ha iniciado sesión correctamente",
"MAIN_VIEW": "Vista Principal",
"NEXT_ITEM": "Siguiente Elemento",
"NEXT_SLIDE": "Siguiente Diapositiva",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Agregar Elemento al Servicio",
"ADD_TO_SERVICE": "Agregar al Servicio",
"ALERT": "Alerta",
"ALERT_SUBMITTED": "Alerta Enviada",
"ALERTS": "Alertas",
"BIBLE_VERSION": "Versión de la Biblia",
"CHANGE_DISPLAY_MODE": "Cambiar Modo de Visualización",
"CHORD_VIEW": "Vista de Acordes",
"CHORDS": "Acordes",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Volver al Controlador",
"HIDE_NOTES": "Ocultar Notas",
"LOGIN": "Iniciar Sesión",
"LOGIN_FAILED": "Error de inicio de sesión",
"LOGIN_SUCCEEDED": "Ha iniciado sesión correctamente",
"MAIN_VIEW": "Vista Principal",
"NEXT_ITEM": "Siguiente Elemento",
"NEXT_SLIDE": "Siguiente Diapositiva",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Üksuse Lisamine Teenusesse",
"ADD_TO_SERVICE": "Lisa Teenusesse",
"ALERT": "Teatise",
"ALERT_SUBMITTED": "Hoiatusteade on Esitatud",
"ALERTS": "Teatised",
"BIBLE_VERSION": "Piibli versioon",
"CHANGE_DISPLAY_MODE": "Muuda Kuvamisrežiimi",
"CHORD_VIEW": "Akordi Vaade",
"CHORDS": "Akorde",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Tagasi Kontrolleri Juurde",
"HIDE_NOTES": "Märkmete Peitmine",
"LOGIN": "Login",
"LOGIN_FAILED": "Sisselogimine ebaõnnestus",
"LOGIN_SUCCEEDED": "Edukalt sisse logitud",
"MAIN_VIEW": "Põhivaade",
"NEXT_ITEM": "Järgmine Päevakorrapunkt",
"NEXT_SLIDE": "Järgmine Slaid",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Lisää Tuote Palveluun",
"ADD_TO_SERVICE": "Lisää Palveluun",
"ALERT": "Huomio Viesti",
"ALERT_SUBMITTED": "Ilmoitus Lähetetty",
"ALERTS": "Huomio Viestit",
"BIBLE_VERSION": "Raamatun versio",
"CHANGE_DISPLAY_MODE": "Vaihda Näyttötilaa",
"CHORD_VIEW": "Sointunäkymä",
"CHORDS": "Soinnut",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Palaa Ohjaimeen",
"HIDE_NOTES": "Piilota Muistiinpanot",
"LOGIN": "Kirjaudu",
"LOGIN_FAILED": "Kirjautuminen epäonnistui",
"LOGIN_SUCCEEDED": "Kirjautuminen onnistui",
"MAIN_VIEW": "Päänäkymä",
"NEXT_ITEM": "Seuraava Kohta",
"NEXT_SLIDE": "Seuraava Dia",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Ajouter un Élément au Service",
"ADD_TO_SERVICE": "Ajouter au Service",
"ALERT": "Alerte",
"ALERT_SUBMITTED": "Alerte Soumise",
"ALERTS": "Alertes",
"BIBLE_VERSION": "Version de la Bible",
"CHANGE_DISPLAY_MODE": "Changer le Mode dAffichage",
"CHORD_VIEW": "Vue des Accords",
"CHORDS": "Accords",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Retour au Contrôleur",
"HIDE_NOTES": "Masquer les Notes",
"LOGIN": "Connexion",
"LOGIN_FAILED": "Echec de la connexion",
"LOGIN_SUCCEEDED": "Connexion réussie",
"MAIN_VIEW": "Vue Principale",
"NEXT_ITEM": "Élément Suivant",
"NEXT_SLIDE": "Diapositive Suivante",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Elem Hozzáadása a Szolgáltatáshoz",
"ADD_TO_SERVICE": "Hozzáadás a Szolgáltatáshoz",
"ALERT": "Riasztási",
"ALERT_SUBMITTED": "Riasztás Elküldve",
"ALERTS": "Riasztások",
"BIBLE_VERSION": "Bibliai változat",
"CHANGE_DISPLAY_MODE": "Megjelenítési mód Módosítása",
"CHORD_VIEW": "Akkord Nézet",
"CHORDS": "Akkordok",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Vissza a Kontrollerhez",
"HIDE_NOTES": "Jegyzetek Elrejtése",
"LOGIN": "Bejelentkezés",
"LOGIN_FAILED": "Sikertelen bejelentkezés",
"LOGIN_SUCCEEDED": "Sikeresen bejelentkezve",
"MAIN_VIEW": "Fő Nézet",
"NEXT_ITEM": "Következő Elem",
"NEXT_SLIDE": "Következő Dia",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Tambahkan Item ke Layanan",
"ADD_TO_SERVICE": "Tambahkan ke Layanan",
"ALERT": "Peringatan",
"ALERT_SUBMITTED": "Peringatan Dikirim",
"ALERTS": "Peringatan",
"BIBLE_VERSION": "Versi Alkitab",
"CHANGE_DISPLAY_MODE": "Ubah Mode Tampilan",
"CHORD_VIEW": "Tampilan Kunci",
"CHORDS": "Kunci",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Kembali ke Pengontrol",
"HIDE_NOTES": "Sembunyikan Catatan",
"LOGIN": "Masuk",
"LOGIN_FAILED": "Login gagal",
"LOGIN_SUCCEEDED": "Berhasil login",
"MAIN_VIEW": "Tampilan Utama",
"NEXT_ITEM": "Item Berikutnya",
"NEXT_SLIDE": "Slide Berikutnya",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Aggiungi Elemento al Servizio",
"ADD_TO_SERVICE": "Aggiungi al Servizio",
"ALERT": "Allarme",
"ALERT_SUBMITTED": "Avviso Inviato",
"ALERTS": "Avvisi",
"BIBLE_VERSION": "Versione biblica",
"CHANGE_DISPLAY_MODE": "Cambia Modalità di Visualizzazione",
"CHORD_VIEW": "Vista degli Accordi",
"CHORDS": "Accordi",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Torna al Controller",
"HIDE_NOTES": "Nascondi le Note",
"LOGIN": "Accedi",
"LOGIN_FAILED": "Accesso non riuscito",
"LOGIN_SUCCEEDED": "Accesso effettuato con successo",
"MAIN_VIEW": "Vista Principale",
"NEXT_ITEM": "Prossimo Elemento",
"NEXT_SLIDE": "Prossima Diapositiva",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Aggiungi Elemento al Servizio",
"ADD_TO_SERVICE": "Aggiungi al Servizio",
"ALERT": "Allarme",
"ALERT_SUBMITTED": "Avviso Inviato",
"ALERTS": "Avvisi",
"BIBLE_VERSION": "Versione biblica",
"CHANGE_DISPLAY_MODE": "Cambia Modalità di Visualizzazione",
"CHORD_VIEW": "Vista degli Accordi",
"CHORDS": "Accordi",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Torna al Controller",
"HIDE_NOTES": "Nascondi le Note",
"LOGIN": "Accedi",
"LOGIN_FAILED": "Accesso non riuscito",
"LOGIN_SUCCEEDED": "Accesso effettuato con successo",
"MAIN_VIEW": "Vista Principale",
"NEXT_ITEM": "Prossimo Elemento",
"NEXT_SLIDE": "Prossima Diapositiva",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Aggiungi Elemento al Servizio",
"ADD_TO_SERVICE": "Aggiungi al Servizio",
"ALERT": "Allarme",
"ALERT_SUBMITTED": "Avviso Inviato",
"ALERTS": "Avvisi",
"BIBLE_VERSION": "Versione biblica",
"CHANGE_DISPLAY_MODE": "Cambia Modalità di Visualizzazione",
"CHORD_VIEW": "Vista degli Accordi",
"CHORDS": "Accordi",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Torna al Controller",
"HIDE_NOTES": "Nascondi le Note",
"LOGIN": "Accedi",
"LOGIN_FAILED": "Accesso non riuscito",
"LOGIN_SUCCEEDED": "Accesso effettuato con successo",
"MAIN_VIEW": "Vista Principale",
"NEXT_ITEM": "Prossimo Elemento",
"NEXT_SLIDE": "Prossima Diapositiva",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "サービスにアイテムを追加",
"ADD_TO_SERVICE": "サービスに追加",
"ALERT": "アラート",
"ALERT_SUBMITTED": "アラート送信済み",
"ALERTS": "アラート",
"BIBLE_VERSION": "聖書版",
"CHANGE_DISPLAY_MODE": "表示モードを変更",
"CHORD_VIEW": "コード表示",
"CHORDS": "コード",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "コントローラーに戻る",
"HIDE_NOTES": "ノートを非表示",
"LOGIN": "ログイン",
"LOGIN_FAILED": "ログインに失敗しました",
"LOGIN_SUCCEEDED": "ログインに成功しました",
"MAIN_VIEW": "メインビュー",
"NEXT_ITEM": "次のアイテム",
"NEXT_SLIDE": "次のスライド",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "서비스에 항목 추가",
"ADD_TO_SERVICE": "서비스에 추가",
"ALERT": "경고",
"ALERT_SUBMITTED": "경고가 제출됨",
"ALERTS": "경고",
"BIBLE_VERSION": "성경 번역본",
"CHANGE_DISPLAY_MODE": "디스플레이 모드 변경",
"CHORD_VIEW": "코드 보기",
"CHORDS": "코드",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "컨트롤러로 돌아가기",
"HIDE_NOTES": "메모 숨기기",
"LOGIN": "로그인",
"LOGIN_FAILED": "로그인 실패",
"LOGIN_SUCCEEDED": "성공적으로 로그인했습니다.",
"MAIN_VIEW": "주 화면",
"NEXT_ITEM": "다음 항목",
"NEXT_SLIDE": "다음 슬라이드",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Pridėti Elementą prie Paslaugos",
"ADD_TO_SERVICE": "Pridėti prie Paslaugos",
"ALERT": "Įspėjimas",
"ALERT_SUBMITTED": "Pateiktas Įspėjimas",
"ALERTS": "Įspėjimai",
"BIBLE_VERSION": "Biblijos versija",
"CHANGE_DISPLAY_MODE": "Keisti Rodymo Režimą",
"CHORD_VIEW": "Akordei",
"CHORDS": "Akordei",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Grįžti į Valdiklį",
"HIDE_NOTES": "Slėpti Pastabas",
"LOGIN": "Prisijungti",
"LOGIN_FAILED": "Prisijungti nepavyko",
"LOGIN_SUCCEEDED": "Sėkmingai prisijungęs",
"MAIN_VIEW": "Pagrindinis Rodinys",
"NEXT_ITEM": "Kitas Elementas",
"NEXT_SLIDE": "Kitas Skaidrė",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Legg til Element i Tjenesten",
"ADD_TO_SERVICE": "Legg til i Tjenesten",
"ALERT": "Varsel",
"ALERT_SUBMITTED": "Varsel Sendt Inn",
"ALERTS": "Varsler",
"BIBLE_VERSION": "Bibelens versjon",
"CHANGE_DISPLAY_MODE": "Endre Visningsmodus",
"CHORD_VIEW": "Akkordvisning",
"CHORDS": "Akkorder",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Gå Tilbake til Kontrolleren",
"HIDE_NOTES": "Skjul Notater",
"LOGIN": "Logg Inn",
"LOGIN_FAILED": "Innlogging mislyktes",
"LOGIN_SUCCEEDED": "Vellykket innlogging",
"MAIN_VIEW": "Hovedvisning",
"NEXT_ITEM": "Neste Element",
"NEXT_SLIDE": "Neste Lysbilde",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Voeg Item Toe aan Liturgie",
"ADD_TO_SERVICE": "Voeg Toe aan Liturgie",
"ALERT": "Waarschuwing",
"ALERT_SUBMITTED": "Waarschuwing Verstuurd",
"ALERTS": "Waarschuwingen",
"BIBLE_VERSION": "Bijbelversie",
"CHANGE_DISPLAY_MODE": "Wijzig Weergave",
"CHORD_VIEW": "Akkoordenscherm",
"CHORDS": "Akkoorden",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Ga Terug naar Controller",
"HIDE_NOTES": "Verberg Notities",
"LOGIN": "Log In",
"LOGIN_FAILED": "Log in mislukt",
"LOGIN_SUCCEEDED": "Succesvol ingelogd",
"MAIN_VIEW": "Hoofdscherm",
"NEXT_ITEM": "Volgend Item",
"NEXT_SLIDE": "Volgende Slide",
@ -46,7 +50,7 @@
"STAGE_VIEW": "Podiumscherm",
"THEMES": "Thema's",
"THEME_LEVEL": "Thema Niveau",
"THEME_OPTIONS": "Theme Opties",
"THEME_OPTIONS": "Thema Opties",
"USER_NAME": "Gebruikersnaam",
"USER_INTERFACE": "Gebruikersinterface"
}

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Dodaj Element do Usługi",
"ADD_TO_SERVICE": "Dodaj do Usługi",
"ALERT": "Alert",
"ALERT_SUBMITTED": "Przesłano Alert",
"ALERTS": "Alerty",
"BIBLE_VERSION": "Wersja Biblii",
"CHANGE_DISPLAY_MODE": "Zmień Tryb Wyświetlania",
"CHORD_VIEW": "Widok Akordów",
"CHORDS": "Akordy",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Wróć do Kontrolera",
"HIDE_NOTES": "Ukryj Notatki",
"LOGIN": "Zaloguj Się",
"LOGIN_FAILED": "Logowanie nie powiodło się",
"LOGIN_SUCCEEDED": "Pomyślnie zalogowano",
"MAIN_VIEW": "Widok Główny",
"NEXT_ITEM": "Następny Element",
"NEXT_SLIDE": "Następny Slajd",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Adicionar Item ao Serviço",
"ADD_TO_SERVICE": "Adicionar ao Serviço",
"ALERT": "Alerta",
"ALERT_SUBMITTED": "Alerta Enviado",
"ALERTS": "Alertas",
"BIBLE_VERSION": "Versão da Bíblia",
"CHANGE_DISPLAY_MODE": "Alterar Modo de Exibição",
"CHORD_VIEW": "Visualização de Acordes",
"CHORDS": "Acordes",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Voltar para o Controlador",
"HIDE_NOTES": "Ocultar Notas",
"LOGIN": "Login",
"LOGIN_FAILED": "Falha no login",
"LOGIN_SUCCEEDED": "Efetuado login com êxito",
"MAIN_VIEW": "Visualização Principal",
"NEXT_ITEM": "Próximo Item",
"NEXT_SLIDE": "Próximo Slide",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Adăugați Element la Serviciu",
"ADD_TO_SERVICE": "Adăugați la Serviciu",
"ALERT": "Alertă",
"ALERT_SUBMITTED": "Alertă Transmisă",
"ALERTS": "Alerte",
"BIBLE_VERSION": "Versiunea Bibliei",
"CHANGE_DISPLAY_MODE": "Schimbați Modul de Afișare",
"CHORD_VIEW": "Vizualizare Acorduri",
"CHORDS": "Acorduri",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Înapoi la Controler",
"HIDE_NOTES": "Ascundeți Notele",
"LOGIN": "Conectare",
"LOGIN_FAILED": "Conectarea nu a reușit",
"LOGIN_SUCCEEDED": "Conectat cu succes",
"MAIN_VIEW": "Vizualizare Principală",
"NEXT_ITEM": "Elementul Următo",
"NEXT_SLIDE": "Diapozitivul Următo",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Добавить элемент в службу",
"ADD_TO_SERVICE": "Добавить в службу",
"ALERT": "Оповещение",
"ALERT_SUBMITTED": "Оповещение отправлено",
"ALERTS": "Оповещения",
"BIBLE_VERSION": "Перевод Библии",
"CHANGE_DISPLAY_MODE": "Изменить режим отображения",
"CHORD_VIEW": "Просмотр аккордов",
"CHORDS": "Аккорды",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Вернуться к контроллеру",
"HIDE_NOTES": "Скрыть заметки",
"LOGIN": "Войти",
"LOGIN_FAILED": "Не удалось войти в систему",
"LOGIN_SUCCEEDED": "Успешно вошел в систему",
"MAIN_VIEW": "Основное представление",
"NEXT_ITEM": "Следующий элемент",
"NEXT_SLIDE": "Следующий слайд",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Pridať Položku do Služby",
"ADD_TO_SERVICE": "Pridať do Služby",
"ALERT": "Upozornenie",
"ALERT_SUBMITTED": "Upozornenie Bolo Odoslané",
"ALERTS": "Upozornenia",
"BIBLE_VERSION": "Verzia Biblie",
"CHANGE_DISPLAY_MODE": "Zmeniť Režim Zobrazenia",
"CHORD_VIEW": "Zobrazenie Akordov",
"CHORDS": "Akordy",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Ísť Späť na Ovládač",
"HIDE_NOTES": "Skryť Poznámky",
"LOGIN": "Prihlásenie",
"LOGIN_FAILED": "Prihlásenie zlyhalo",
"LOGIN_SUCCEEDED": "Úspešne prihlásené",
"MAIN_VIEW": "Hlavný Pohľad",
"NEXT_ITEM": "Ďalšia Položka",
"NEXT_SLIDE": "Ďalší Snímok",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Dodaj Predmet v Spored",
"ADD_TO_SERVICE": "Dodaj v Spored",
"ALERT": "Opozorilo",
"ALERT_SUBMITTED": "Predloženo Opozorilo",
"ALERTS": "Opozorila",
"BIBLE_VERSION": "Svetopisemska različica",
"CHANGE_DISPLAY_MODE": "Spremeni Način Prikaza",
"CHORD_VIEW": "Pogled s Sozvoki",
"CHORDS": "Sozvoki",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Vrni se na Upravljalnik",
"HIDE_NOTES": "Skrij Opombe",
"LOGIN": "Prijava",
"LOGIN_FAILED": "Prijava ni uspela",
"LOGIN_SUCCEEDED": "Uspešno prijavljeni",
"MAIN_VIEW": "Glavni Pogled",
"NEXT_ITEM": "Naslednji Predmet",
"NEXT_SLIDE": "Naslednja Prosojnica",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Lägg till Objekt i Tjänsten",
"ADD_TO_SERVICE": "Lägg till i Tjänsten",
"ALERT": "Varning",
"ALERT_SUBMITTED": "Avisering Skickad",
"ALERTS": "Varningar",
"BIBLE_VERSION": "Bibelöversättning",
"CHANGE_DISPLAY_MODE": "Ändra Visningsläge",
"CHORD_VIEW": "Ackordvy",
"CHORDS": "Ackord",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Gå Tillbaka till Kontrollenhet",
"HIDE_NOTES": "Dölj Anteckningar",
"LOGIN": "Logga In",
"LOGIN_FAILED": "Inloggningen misslyckades",
"LOGIN_SUCCEEDED": "Har loggat in",
"MAIN_VIEW": "Huvudvy",
"NEXT_ITEM": "Nästa Objekt",
"NEXT_SLIDE": "Nästa Bild",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "பொருள் சேர்க்க சேவைக்கு",
"ADD_TO_SERVICE": "சேவைக்கு சேர்க்கவும்",
"ALERT": "எச்சரிக்கை",
"ALERT_SUBMITTED": "எச்சரிக்கை சமர்ப்பிக்கப்பட்டது",
"ALERTS": "எச்சரிக்கைகள்",
"BIBLE_VERSION": "பைபிள் பதிப்பு",
"CHANGE_DISPLAY_MODE": "காட்சி முறையை மாற்று",
"CHORD_VIEW": "கார்டு காட்சி",
"CHORDS": "கார்டுகள்",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "கட்டுப்பாட்டிற்கு திரும்பு",
"HIDE_NOTES": "குறிப்புகளை மறை",
"LOGIN": "உள்நுழை",
"LOGIN_FAILED": "உள்நுழைவு தோல்வியுற்றது",
"LOGIN_SUCCEEDED": "வெற்றிகரமாக உள்நுழைந்தது",
"MAIN_VIEW": "முக்கிய காட்சி",
"NEXT_ITEM": "அடுத்த பொருள்",
"NEXT_SLIDE": "அடுத்த ஸ்லைட்",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "เพิ่มรายการในบริการ",
"ADD_TO_SERVICE": "เพิ่มในบริการ",
"ALERT": "แจ้งเตือน",
"ALERT_SUBMITTED": "ส่งการแจ้งเตือนแล้ว",
"ALERTS": "การแจ้งเตือน",
"BIBLE_VERSION": "ฉบับพระคัมภีร์",
"CHANGE_DISPLAY_MODE": "เปลี่ยนโหมดการแสดงผล",
"CHORD_VIEW": "มุมมองคอร์ด",
"CHORDS": "คอร์ด",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "กลับไปที่ควบคุม",
"HIDE_NOTES": "ซ่อนบันทึก",
"LOGIN": "เข้าสู่ระบบ",
"LOGIN_FAILED": "การเข้าสู่ระบบล้มเหลว",
"LOGIN_SUCCEEDED": "เข้าสู่ระบบสําเร็จ",
"MAIN_VIEW": "มุมมองหลัก",
"NEXT_ITEM": " รายการถัดไป",
"NEXT_SLIDE": "ภาพนิ่งถัดไป",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "Thêm mục vào Dịch vụ",
"ADD_TO_SERVICE": "Thêm vào Dịch vụ",
"ALERT": "Cảnh báo",
"ALERT_SUBMITTED": "Cảnh báo đã Gửi",
"ALERTS": "Các cảnh báo",
"BIBLE_VERSION": "Phiên bản Kinh Thánh",
"CHANGE_DISPLAY_MODE": "Thay đổi Chế độ Hiển thị",
"CHORD_VIEW": "Xem hợp âm",
"CHORDS": "Hợp âm",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "Quay lại Bộ điều khiển",
"HIDE_NOTES": "Ẩn ghi chú",
"LOGIN": "Đăng nhập",
"LOGIN_FAILED": "Đăng nhập không thành công",
"LOGIN_SUCCEEDED": "Đăng nhập thành công",
"MAIN_VIEW": "Chế độ xem chính",
"NEXT_ITEM": "Mục tiếp theo",
"NEXT_SLIDE": "Trang tiếp theo",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "添加项目到服务",
"ADD_TO_SERVICE": "添加到服务",
"ALERT": "警报",
"ALERT_SUBMITTED": "警报已提交",
"ALERTS": "警报",
"BIBLE_VERSION": "圣经版本",
"CHANGE_DISPLAY_MODE": "更改显示模式",
"CHORD_VIEW": "和弦视图",
"CHORDS": "和弦",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "返回到控制器",
"HIDE_NOTES": "隐藏注释",
"LOGIN": "登录",
"LOGIN_FAILED": "登录失败",
"LOGIN_SUCCEEDED": "登录成功",
"MAIN_VIEW": "主视图",
"NEXT_ITEM": "下一个项目",
"NEXT_SLIDE": "下一张幻灯片",

View File

@ -3,7 +3,9 @@
"ADD_ITEM_TO_SERVICE": "新增項目至服務",
"ADD_TO_SERVICE": "新增至服務",
"ALERT": "警示",
"ALERT_SUBMITTED": "警報已提交",
"ALERTS": "警示訊息",
"BIBLE_VERSION": "聖經版本",
"CHANGE_DISPLAY_MODE": "變更顯示模式",
"CHORD_VIEW": "和弦檢視",
"CHORDS": "和弦",
@ -16,6 +18,8 @@
"GO_BACK_TO_CONTROLLER": "返回控制器",
"HIDE_NOTES": "隱藏筆記",
"LOGIN": "登入",
"LOGIN_FAILED": "登錄失敗",
"LOGIN_SUCCEEDED": "登錄成功",
"MAIN_VIEW": "主畫面",
"NEXT_ITEM": "下一項目",
"NEXT_SLIDE": "下一張投影片",

802
yarn.lock

File diff suppressed because it is too large Load Diff