diff --git a/src/app/directives/auto-font-size.directive.ts b/src/app/directives/auto-font-size.directive.ts new file mode 100644 index 0000000..d5befbb --- /dev/null +++ b/src/app/directives/auto-font-size.directive.ts @@ -0,0 +1,184 @@ +import { Directive, ElementRef, AfterViewInit, OnDestroy, Input, Renderer2, OnChanges, SimpleChanges } from '@angular/core'; +import { Subject } from 'rxjs'; +import { debounceTime, takeUntil } from 'rxjs/operators'; + +@Directive({ + selector: '[appAutoFontSize]' +}) +export class AutoFontSizeDirective implements AfterViewInit, OnDestroy, OnChanges { + @Input() minFontSize: number = 12; // Mindestschriftgröße in Pixel + @Input() maxFontSize?: number = 70; // Maximale Schriftgröße in Pixel, optional + @Input() debounceDuration: number = 0; // Debounce-Dauer in Millisekunden + @Input() maxFontSizePercentage: number = 30; // Maximaler Prozentsatz der Elternhöhe für die Schriftgröße + + private resizeObserver!: ResizeObserver; + private mutationObserver!: MutationObserver; + private resize$ = new Subject(); + private destroy$ = new Subject(); + + private originalFontSizePx!: number; + + // Internes Property zur Validierung + private _maxFontSizePercentage: number = 30; + + constructor(private el: ElementRef, private renderer: Renderer2) { } + + ngAfterViewInit() { + const element: HTMLElement = this.el.nativeElement; + + // Speichere die originale Schriftgröße + const computedStyle = window.getComputedStyle(element); + const parsedFontSize = parseFloat(computedStyle.fontSize); + this.originalFontSizePx = isNaN(parsedFontSize) ? 16 : parsedFontSize; + + // Set maxFontSize, falls nicht gesetzt + const effectiveMaxFontSize = this.maxFontSize ?? this.originalFontSizePx; + + // Set initial font size + this.renderer.setStyle(element, 'font-size', `${effectiveMaxFontSize}px`); + + // Initial Anpassung + this.adjustFontSize(); + + // Initialisiere den ResizeObserver + this.resizeObserver = new ResizeObserver(() => { + this.resize$.next(); + }); + this.resizeObserver.observe(element); + + // Suche das nächstgelegene Element mit der Klasse 'arrival-card' + const arrivalCard = element.closest('.arrival-card') as HTMLElement | null; + if (arrivalCard) { + this.resizeObserver.observe(arrivalCard); + } + + // Initialisiere den MutationObserver + this.mutationObserver = new MutationObserver(() => { + this.resize$.next(); + }); + this.mutationObserver.observe(element, { + childList: true, + subtree: true, + characterData: true + }); + + // Debounce der Resize-Events, um übermäßige Aufrufe zu vermeiden + this.resize$.pipe( + debounceTime(this.debounceDuration), + takeUntil(this.destroy$) + ).subscribe(() => { + this.adjustFontSize(); + }); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['maxFontSizePercentage']) { + // Re-validate und Anpassung der Schriftgröße bei Änderung + this.validateMaxFontSizePercentage(); + this.adjustFontSize(); + } + + if (changes['maxFontSize']) { + this.adjustFontSize(); + } + + if (changes['minFontSize']) { + this.adjustFontSize(); + } + } + + ngOnDestroy() { + if (this.resizeObserver) { + this.resizeObserver.disconnect(); + } + if (this.mutationObserver) { + this.mutationObserver.disconnect(); + } + this.destroy$.next(); + this.destroy$.complete(); + } + + /** + * Re-validate und setze den maxFontSizePercentage + */ + private validateMaxFontSizePercentage() { + if (this.maxFontSizePercentage < 1) { + this._maxFontSizePercentage = 1; + } else if (this.maxFontSizePercentage > 100) { + this._maxFontSizePercentage = 100; + } else { + this._maxFontSizePercentage = this.maxFontSizePercentage; + } + } + + /** + * Passt die Schriftgröße des Elements an, um Überlauf zu vermeiden und + * sicherzustellen, dass die Schriftgröße nicht mehr als maxFontSizePercentage der Elternhöhe beträgt. + * Verwendet eine binäre Suche zur effizienten Anpassung. + */ + private adjustFontSize() { + const element: HTMLElement = this.el.nativeElement; + // Suche das nächstgelegene Element mit der Klasse 'arrival-card' + const parent: HTMLElement | null = element.closest('.arrival-card') as HTMLElement | null; + + if (!parent) { + return; + } + + const parentWidth = parent.clientWidth; + const parentHeight = parent.clientHeight; + const elementScrollWidth = element.scrollWidth; + + // Validierung des maxFontSizePercentage + this.validateMaxFontSizePercentage(); + + // Berechne die maximale Schriftgröße basierend auf der Elternhöhe (maxFontSizePercentage%) + const maxFontSizeByHeight = (this._maxFontSizePercentage / 100) * parentHeight; + + // Bestimme die effektive maximale Schriftgröße + const effectiveMaxFontSize = this.maxFontSize + ? Math.min(this.maxFontSize, maxFontSizeByHeight) + : Math.min(this.originalFontSizePx, maxFontSizeByHeight); + + // Setze die Schriftgröße auf die maximale Größe + this.renderer.setStyle(element, 'font-size', `${effectiveMaxFontSize}px`); + + // Überprüfe, ob der Inhalt überläuft (nur Breite) + if (this.isWidthOverflowing(element, parent)) { + let low = this.minFontSize; + let high = effectiveMaxFontSize; + let fontSize = high; + + // Binäre Suche zur Anpassung der Schriftgröße + while (low <= high) { + const mid = Math.floor((low + high) / 2); + this.renderer.setStyle(element, 'font-size', `${mid}px`); + + if (this.isWidthOverflowing(element, parent)) { + high = mid - 1; + } else { + fontSize = mid; + low = mid + 1; + } + } + + this.renderer.setStyle(element, 'font-size', `${fontSize}px`); + + } + + // Zusätzliche Debugging-Informationen + const finalFontSize = parseFloat(window.getComputedStyle(element).fontSize); + const finalElementWidth = element.scrollWidth; + } + + /** + * Überprüft, ob die Breite des Elements die des Eltern-Elements überschreitet. + * @param element Das zu überprüfende HTMLElement. + * @param parent Das Eltern-HTMLElement. + * @returns Wahr, wenn die Breite überläuft, sonst falsch. + */ + private isWidthOverflowing(element: HTMLElement, parent: HTMLElement): boolean { + const overflowing = element.scrollWidth > parent.clientWidth; + return overflowing; + } +} diff --git a/src/app/directives/auto-resize-text.directive.ts b/src/app/directives/auto-resize-text.directive.ts index f4cd84f..7f9e786 100644 --- a/src/app/directives/auto-resize-text.directive.ts +++ b/src/app/directives/auto-resize-text.directive.ts @@ -7,6 +7,7 @@ import { debounceTime, takeUntil } from 'rxjs/operators'; }) export class AutoResizeTextDirective implements AfterViewInit, OnDestroy { private resizeObserver!: ResizeObserver; + private mutationObserver!: MutationObserver; private resize$ = new Subject(); private destroy$ = new Subject(); @@ -14,15 +15,26 @@ export class AutoResizeTextDirective implements AfterViewInit, OnDestroy { ngAfterViewInit() { this.adjustFontSizes(); + + // Initialisiere den ResizeObserver this.resizeObserver = new ResizeObserver(() => { this.resize$.next(); }); this.resizeObserver.observe(this.el.nativeElement); - // Debounce der Resize-Events + // Initialisiere den MutationObserver + this.mutationObserver = new MutationObserver(() => { + this.resize$.next(); + }); + this.mutationObserver.observe(this.el.nativeElement, { + childList: true, + subtree: true, + characterData: true + }); + + // Debounce der Resize-Events, um übermäßige Aufrufe zu vermeiden this.resize$.pipe( - debounceTime(100), // Warte 100ms nach dem letzten Resize-Event - takeUntil(this.destroy$) + takeUntil(this.destroy$) ).subscribe(() => { this.adjustFontSizes(); }); @@ -32,80 +44,83 @@ export class AutoResizeTextDirective implements AfterViewInit, OnDestroy { if (this.resizeObserver) { this.resizeObserver.disconnect(); } + if (this.mutationObserver) { + this.mutationObserver.disconnect(); + } this.destroy$.next(); this.destroy$.complete(); } /** - * Passt die Schriftgrößen der einzelnen Spans individuell an. + * Passt die Schriftgrößen der einzelnen Divs individuell an. */ private adjustFontSizes() { const container: HTMLElement = this.el.nativeElement; - const spans: HTMLElement[] = Array.from(container.querySelectorAll('div.dynamic-font-size')); + const divs: HTMLElement[] = Array.from(container.querySelectorAll('div')); - // Store the original font sizes - spans.forEach(span => { - if (!span.dataset['originalFontSizePx']) { - const computedStyle = window.getComputedStyle(span); + // Original-Schriftgrößen speichern, falls noch nicht gespeichert + divs.forEach(div => { + if (!div.dataset['originalFontSizePx']) { + const computedStyle = window.getComputedStyle(div); const originalFontSizePx = parseFloat(computedStyle.fontSize); - span.dataset['originalFontSizePx'] = originalFontSizePx.toString(); + div.dataset['originalFontSizePx'] = originalFontSizePx.toString(); } }); - // Reset font sizes to original - spans.forEach(span => { - const originalFontSizePx = parseFloat(span.dataset['originalFontSizePx'] || '16'); - span.style.fontSize = `${originalFontSizePx}px`; + // Setze die Schriftgrößen auf die Originalwerte zurück + divs.forEach(div => { + const originalFontSizePx = parseFloat(div.dataset['originalFontSizePx'] || '16'); + div.style.fontSize = `${originalFontSizePx}px`; }); - // If content overflows, adjust font sizes + // Wenn der Inhalt überläuft, passe die Schriftgrößen an if (this.isOverflowing(container)) { - // Find the scaling factor needed to fit the content - let scalingFactor = this.calculateScalingFactor(container, spans); + // Berechne den Skalierungsfaktor, der benötigt wird, um den Inhalt anzupassen + let scalingFactor = this.calculateScalingFactor(container, divs); - // Apply the scaling factor to all spans - spans.forEach(span => { - const originalFontSizePx = parseFloat(span.dataset['originalFontSizePx'] || '16'); + // Wende den Skalierungsfaktor auf alle Divs an + divs.forEach(div => { + const originalFontSizePx = parseFloat(div.dataset['originalFontSizePx'] || '16'); let newFontSizePx = originalFontSizePx * scalingFactor; - // Ensure the font size doesn't go below a minimum value + // Stelle sicher, dass die Schriftgröße nicht unter einen Mindestwert fällt const minFontSizePx = 12; if (newFontSizePx < minFontSizePx) { newFontSizePx = minFontSizePx; } - span.style.fontSize = `${newFontSizePx}px`; + div.style.fontSize = `${newFontSizePx}px`; }); } } /** - * Calculates the scaling factor needed to fit all content within the container. - * @param container The container element. - * @param spans The list of span elements. - * @returns The scaling factor as a decimal. + * Berechnet den Skalierungsfaktor, um den gesamten Inhalt anzupassen. + * @param container Das Container-Element. + * @param divs Die Liste der Div-Elemente. + * @returns Der Skalierungsfaktor als Dezimalzahl. */ - private calculateScalingFactor(container: HTMLElement, spans: HTMLElement[]): number { - const minFontSizePx = 12; // Minimum font size - let low = 0.1; // 10% scaling - let high = 1; // 100% scaling + private calculateScalingFactor(container: HTMLElement, divs: HTMLElement[]): number { + const minFontSizePx = 12; // Mindest-Schriftgröße + let low = 0.1; // 10% Skalierung + let high = 1; // 100% Skalierung let mid = 1; - // Binary search to find the optimal scaling factor + // Binäre Suche, um den optimalen Skalierungsfaktor zu finden while (high - low > 0.01) { mid = (low + high) / 2; - // Apply scaling factor - spans.forEach(span => { - const originalFontSizePx = parseFloat(span.dataset['originalFontSizePx'] || '16'); + // Anwenden des Skalierungsfaktors + divs.forEach(div => { + const originalFontSizePx = parseFloat(div.dataset['originalFontSizePx'] || '16'); let newFontSizePx = originalFontSizePx * mid; if (newFontSizePx < minFontSizePx) { newFontSizePx = minFontSizePx; } - span.style.fontSize = `${newFontSizePx}px`; + div.style.fontSize = `${newFontSizePx}px`; }); - // Check if content overflows + // Überprüfen, ob der Inhalt überläuft if (this.isOverflowing(container)) { high = mid; } else { @@ -116,7 +131,6 @@ export class AutoResizeTextDirective implements AfterViewInit, OnDestroy { return low; } - /** * Überprüft, ob der Inhalt des Containers überläuft. * @param container Das zu überprüfende HTMLElement. diff --git a/src/app/pages/aviso/aviso.module.ts b/src/app/pages/aviso/aviso.module.ts index 776f4df..9036afa 100644 --- a/src/app/pages/aviso/aviso.module.ts +++ b/src/app/pages/aviso/aviso.module.ts @@ -7,17 +7,18 @@ import { IonicModule } from '@ionic/angular'; import { AvisoPageRoutingModule } from './aviso-routing.module'; import { AutoResizeTextDirective } from '../../directives/auto-resize-text.directive'; +import { AutoFontSizeDirective } from '../../directives/auto-font-size.directive'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; - + @NgModule({ imports: [ CommonModule, FormsModule, IonicModule, - AvisoPageRoutingModule + AvisoPageRoutingModule, ], schemas: [CUSTOM_ELEMENTS_SCHEMA], - declarations: [AvisoPage, AutoResizeTextDirective] + declarations: [AvisoPage, AutoResizeTextDirective, AutoFontSizeDirective] }) export class AvisoPageModule {} diff --git a/src/app/pages/aviso/aviso.page.html b/src/app/pages/aviso/aviso.page.html index 5d7bb5c..4624508 100644 --- a/src/app/pages/aviso/aviso.page.html +++ b/src/app/pages/aviso/aviso.page.html @@ -1,12 +1,17 @@ + - + - - + + @@ -23,41 +28,83 @@ - +
- - + [ngClass]="getStatusClass(aviso.status, aviso.lkW_fertig, aviso.avisoTVHinweis)">
{{ getOverallIndex(i) }}
- - - {{ aviso.lkW_Nr }} - - - - -
-

+ +

+ +
+ {{ aviso.lkW_Nr }} +
+ +
+ [color]="getStatusColor(aviso.status)" + class="inline-icon"> {{ aviso.ankunft }} - + {{ aviso.dauer }} -

-

+

+ +
{{ aviso.letzterMitarbeiter }} -

+
+ +
- +
+ Aviso Hinweis +
+
+ Aviso Hinweis +
+ + + + + +
+
+ {{ aviso.avisoTVHinweis }} +
+
+ Aviso Hinweis +
+
+
+ +
- - + @@ -71,45 +118,56 @@ + + - {{ currentDate | date: 'HH:mm:ss' }}
- {{ currentDate | date: ' dd.MM.yyyy' }} - + {{ currentDate | date: 'dd.MM.yyyy' }}
- + - ({{ totalArrivals }})
{{ currentPageIndex + 1 }} / {{ pages.length }}
- + + ({{ totalArrivals }})
{{ currentPageIndex + 1 }} / {{ pages.length }} +
+ +
- + + + - +
+ class="htmltext responsive-title">
-
-
- - - - +
+
+
- - diff --git a/src/app/pages/aviso/aviso.page.scss b/src/app/pages/aviso/aviso.page.scss index ab9ad47..2f18728 100644 --- a/src/app/pages/aviso/aviso.page.scss +++ b/src/app/pages/aviso/aviso.page.scss @@ -1,13 +1,30 @@ +/* ====================================================== + Allgemeine Stile +====================================================== */ + ion-content { - --background: #f0f0f0; /* Heller Hintergrund für besseren Kontrast */ + --background: #f0f0f0; } +p { + padding: 0; + margin: 0; +} + +div { + white-space: nowrap; + color: #333; +} + +/* ====================================================== + Grid-Container für Arrivals Kacheln +====================================================== */ .grid-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--tile-width-percent), 1fr)); row-gap: 1vh; column-gap: 1vh; - padding: 0px; + padding: 0; justify-content: center; } @@ -20,9 +37,45 @@ ion-content { justify-content: center; align-items: center; margin: 0; - padding: 0em; - box-sizing: border-box; /* Padding wird in der Höhe berücksichtigt */ - animation: fadeIn 0.2s ease-in-out; /* Kürzere Animationsdauer */ + padding: 0; + box-sizing: border-box; + animation: fadeIn 0.2s ease-in-out; +} + +.card-number { + position: absolute; + top: 5px; + left: 5px; + font-size: calc(var(--tile-height-vh) * 0.18); + font-weight: bold; + background-color: transparent; + padding: 2px 5px; + border-radius: 3px; + color: #003680; +} + +/* ====================================================== + Typografie +====================================================== */ + +ion-title { + font-size: calc(var(--tile-height-vh) * 0.24); + font-weight: bold; + color: #003680; +} + +.title { + font-size: clamp(12px, 2vw, var(--tile-title-font-size)); + font-weight: bold; + color: #003680; +} + +.lkwnr { + + text-align: center; + white-space: nowrap; + color: #002050; + font-weight: bold; } .htmltext { @@ -32,23 +85,41 @@ ion-content { transition: box-shadow 0.3s, transform 0.3s; } +/* ====================================================== + Icons +====================================================== */ + ion-icon { vertical-align: middle; - font-size: calc(var(--tile-height-vh) * 0.18); /* Anpassung der Icon-Größe */ - margin-right: 0.3em; /* Abstand zwischen Icon und Text */ + font-size: calc(var(--tile-height-vh) * 0.12); + margin-right: -3px; + margin-left: 0.1em; + margin-bottom:0.1em; } -/* Statusklassen */ + + +/* ====================================================== + Statusklassen +====================================================== */ .lkwfertig { - border-left: 10px solid green; - background-color: #e6ffe6; /* Leicht grüner Hintergrund für "fertig" */ + border-left: 10px solid #306c0c; + background-color: #e6ffe6; +} + +.fehlt { + border-left: 10px solid #a00f05; + background-color: #f79391; } .statusLKW_LKW_neu, .statusLKW_Ankunft { - } +} + +/* ====================================================== + Animationen +====================================================== */ -/* Animationen für Ankunftskarten */ @keyframes fadeIn { from { opacity: 0; @@ -61,138 +132,141 @@ ion-icon { } } -/* Typografie */ -ion-title { - font-size: calc(var(--tile-height-vh) * 0.24); /* 4% der Kachelhöhe */ - font-weight: bold; - color: #003680; +.blinking-image { + animation: blink-animation 1s steps(2, start) infinite; } -.title { - font-size: calc(var(--tile-height-vh) * 0.24); /* 4% der Kachelhöhe */ - font-weight: bold; - color: #003680; -} - -ion-card-title { - font-size: calc(var(--tile-height-vh) * 0.06); /* Erhöht auf 6% der Kachelhöhe */ - margin: 0; /* Abstand unter dem Titel */ - text-align: center; - white-space: nowrap; /* Erlaubt Zeilenumbrüche */ - overflow-wrap: normal; /* Bricht lange Wörter um */ - color: #002050; /* Dunkleres Blau für besseren Kontrast */ -} - -ion-card-content p { - font-size: calc(var(--tile-height-vh) * 0.04); /* Erhöht auf 4% der Kachelhöhe */ - margin: 0; - text-align: center; - white-space: nowrap; /* Erlaubt Zeilenumbrüche */ - overflow-wrap: normal; /* Bricht lange Wörter um */ - line-height: 1.5; /* Verbesserte Lesbarkeit */ - color: #333; /* Dunkle Schriftfarbe für besseren Kontrast */ -} - -.centered-content p { - margin-bottom: 0.5em; /* Abstand zwischen den Absätzen */ -} - -/* Icon-Text-Gruppe */ -.icon-text-group { - display: flex; - align-items: center; - margin-bottom: 0.5em; -} - -.icon-text-group ion-icon { - margin-right: 0.5em; -} - -/* Mobile Geräte */ -@media (max-width: 599px) { - .arrival-card { - height: auto; /* Höhe passt sich dem Inhalt an */ +@keyframes blink-animation { + 0%, 50% { + opacity: 1; } - ion-card-title { - font-size: calc(var(--tile-height-vh) * 0.08); - } - - ion-card-content p { - font-size: calc(var(--tile-height-vh) * 0.05); + 50.01%, 100% { + opacity: 0; } } -/* Tablets */ -@media (min-width: 600px) and (max-width: 1199px) { - ion-card-title { - font-size: var(--tile-title-font-size); - } - - ion-card-content p { - font-size: var(--tile-font-size-date-time); - } -} - -/* Desktops */ -@media (min-width: 1200px) { - ion-card-title { - font-size: var(--tile-title-font-size); - } - - ion-card-content p { - font-size: var(--tile-font-size-date-time); - } -} +/* ====================================================== + Bilder und Logos +====================================================== */ .logo { - max-height: calc(var(--tile-height-vh) * 0.40); + max-height: 10vh; object-fit: contain; } .logobar { - max-height: 10vh; + max-height: 12vh; +} + + + +.bottom-left-image-problem img { + position: absolute; + width: 11%; + bottom: 2%; + left: 2%; + aspect-ratio: 9 / 9; +} + +.bottom-left-image-passport img { + position: absolute; + width: 18%; + bottom: 2%; + left: 2%; +} + +.bottom-left-image-round img { + position: absolute; + width: 11%; + aspect-ratio: 10 / 9; + bottom: 2%; + left: 1%; +} + + + +.problem { + width: 32%; + } + +.passport { + width: 42%; } +/* ====================================================== + Benutzerdefinierte Segmente +====================================================== */ +.custom-segment { + display: flex; + justify-content: center; + background-color: #ffffff; + height: 40px; +} + +.custom-segment-button { + min-width: 50px; + height: 35px; + margin: 2px; + padding: 5px; + font-size: 12px; + background-color: transparent; + border: none; + border-bottom: 2px solid transparent; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + cursor: pointer; + transition: border-bottom 0.3s ease, color 0.3s ease; +} + +.custom-segment-button.active { + border-bottom: 2px solid #003680; +} + +.custom-segment-button:hover { + border-bottom: 2px solid #cccccc; +} + +.custom-segment-button:focus { + outline: none; +} + +.custom-segment-button.active .tab-label { + color: #003680; +} + +.tab-image { + width: 24px; + height: 20px; +} + +/* ====================================================== + Dynamische und Lade-Indikatoren +====================================================== */ + +.loading-indicator { + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} + .custom-progress-bar { - --progress-background: #003680; /* Fortschrittsfarbe (gefüllter Teil) */ - --background: #e0e0e0; /* Hintergrundfarbe der Leiste */ - --buffer-background: #003680; /* Hintergrundfarbe des Puffers */ -} -.card-number { - position: absolute; - top: 5px; - left: 5px; - font-size: calc(var(--tile-height-vh) * 0.18); - font-weight: bold; - background-color: transparent; - padding: 2px 5px; - border-radius: 3px; -} -/* Versteckt die Buttons und zeigt nur den Indikator-Strich an */ -.custom-segment-button { - --color: transparent; /* Text unsichtbar machen */ - --background: #003680; /* Hintergrund des Buttons transparent */ - min-height: 0; - padding: 0; - margin: 0; - border: none; - width: 200px; - --indicator-color: transparent; + --progress-background: #003680; } -/* Styling für das ion-segment */ -.custom-segment { - --background: transparent; - height: 0.4vh; - position: relative; - margin: 0; - padding: 0; - +/* ====================================================== + Flex Container +====================================================== */ +.flex-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + row-gap: var(--tile-row-gap); + height: 100%; } - - - - - diff --git a/src/app/pages/aviso/aviso.page.ts b/src/app/pages/aviso/aviso.page.ts index d398f0e..02de9b9 100644 --- a/src/app/pages/aviso/aviso.page.ts +++ b/src/app/pages/aviso/aviso.page.ts @@ -1,17 +1,20 @@ -// src/app/pages/aviso/aviso.page.ts - import { Component, OnInit, OnDestroy, HostListener, ChangeDetectorRef, - HostBinding + HostBinding, + ViewChildren, + QueryList, + ElementRef, + AfterViewInit, + Renderer2 } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { interval, Subject, throwError, lastValueFrom, Subscription } from 'rxjs'; -import { switchMap, takeUntil, distinctUntilChanged, tap, catchError, map, take } from 'rxjs/operators'; +import { switchMap, takeUntil, distinctUntilChanged, tap, catchError, map, take, debounceTime } from 'rxjs/operators'; import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service'; import { AvisoDto, TvSettings } from '../../services/aviso.dto'; @@ -24,10 +27,7 @@ interface AvisoResolvedData { arrivals: AvisoArrivalsResponse; } -interface AvisoPageData { - avisoData: AvisoResolvedData; -} - + interface CssVariables { tileWidthPercent: string; tileHeightVh: string; @@ -35,6 +35,7 @@ interface CssVariables { tileFontSizeDateTime: string; tileSeitenwechselInSek: string; textBalkenHeightVh: string; + tileRowGapinPercent: string; } const ARRIVALS_INTERVAL_MS = 10000; @@ -52,7 +53,8 @@ interface StatusInfo { const STATUS_MAP: { [key: string]: StatusInfo } = { '3': { class: 'statusLKW_Ankunft', icon: 'time', color: 'medium', text: 'Ankunft' }, 'lkwfertig': { class: 'lkwfertig', icon: 'time', color: 'warning', text: 'Ankunft' }, - 'default': { class: 'status-default', icon: 'help-circle', color: 'medium', text: 'Unbekannt' } + 'fehlt': { class: 'fehlt', icon: 'time', color: 'danger', text: 'Dokument Fehlt' }, + 'default': { class: 'status-default', icon: 'help-circle', color: 'medium', text: 'Unbekannt' } }; // Neues Interface für die Anzeige der Fixzeilen @@ -62,6 +64,7 @@ interface SettingDisplayData { textAlign: string; }[]; currentDivIndex: number; + isDivReady: boolean; // Flag zur Steuerung der Sichtbarkeit } @Component({ @@ -69,19 +72,22 @@ interface SettingDisplayData { templateUrl: './aviso.page.html', styleUrls: ['./aviso.page.scss'], }) -export class AvisoPage implements OnInit, OnDestroy { +export class AvisoPage implements OnInit, OnDestroy, AfterViewInit { // HostBindings für CSS-Variablen - @HostBinding('style.--tile-width-percent') tileWidthPercent = '30vw'; - @HostBinding('style.--tile-height-vh') tileHeightVh = '20vh'; - @HostBinding('style.--tile-title-font-size') tileTitleFontSize = '2vh'; - @HostBinding('style.--tile-font-size-date-time') tileFontSizeDateTime = '1vh'; - @HostBinding('style.--text-balken-height-vh') textBalkenHeightVh = '5vh'; + @HostBinding('style.--tile-width-percent') tileWidthPercent = '50vw'; + @HostBinding('style.--tile-height-vh') tileHeightVh = '40vh'; + @HostBinding('style.--tile-title-font-size') tileTitleFontSize = '5vh'; + @HostBinding('style.--tile-font-size-date-time') tileFontSizeDateTime = '5vh'; + @HostBinding('style.--text-balken-height-vh') textBalkenHeightVh = '10vh'; + @HostBinding('style.--tile-row-gap') tileRowGapinPercent = '10%'; + + + progressBarValue: number = 0; private progressBarSubscription: Subscription = new Subscription(); - currentDate: Date = new Date(); private dateSubscription: Subscription = new Subscription(); @@ -122,11 +128,20 @@ export class AvisoPage implements OnInit, OnDestroy { // Neues Array für die Anzeige der Fixzeilen settingDisplayData: SettingDisplayData[] = []; + // Hinzugefügte Variablen für die Kachel-Umschaltung + avisoTimeouts: { [key: string]: any } = {}; + avisoStates: { [key: string]: boolean } = {}; + + // Dauer in Millisekunden + contentDuration = 3000; // Zeit in ms, die der normale Inhalt angezeigt wird + avisoHinweisDuration = 1500; // Zeit in ms, die der avisoTVHinweis Text angezeigt wird + constructor( private route: ActivatedRoute, private avisoService: AvisoService, private cdr: ChangeDetectorRef, - private sanitizer: DomSanitizer + private sanitizer: DomSanitizer, + private renderer: Renderer2 ) { } /** @@ -151,7 +166,7 @@ export class AvisoPage implements OnInit, OnDestroy { this.dateSubscription = interval(1000).subscribe(() => { this.currentDate = new Date(); }); - + this.route.paramMap.subscribe(params => { this.standort = params.get('standort') || 'SUB'; this.standortID = parseInt(params.get('standortID') || '1', 10); @@ -171,6 +186,17 @@ export class AvisoPage implements OnInit, OnDestroy { this.arrivals = data.arrivals.avisos; this.totalArrivals = data.arrivals.totalCount; + // Avisos für Testzwecke modifizieren + this.arrivals.forEach(aviso => { + if (aviso.lkW_Nr === '10AKN963') { + aviso.lkW_Nr = '10AKN96310AKN96310AKN96310AKN963'; + } + }); + + this.paginateArrivals(); + this.updateAvisoStatesAndCycles(); + this.cdr.detectChanges(); + // Process the HTML settings this.preprocessHtmlSettings(); @@ -183,6 +209,12 @@ export class AvisoPage implements OnInit, OnDestroy { // Starten der Seitenrotation this.paginateArrivals(); this.startPageRotation(); + + // Starten der Aviso-Kachel-Umschaltung + this.updateAvisoStatesAndCycles(); + + // Nach dem Laden der Daten die Schriftgröße anpassen (falls nicht mehr benötigt) + // Da die Direktive jetzt die Schriftgröße anpasst, kann dieser Code eventuell entfernt werden }); @@ -202,8 +234,17 @@ export class AvisoPage implements OnInit, OnDestroy { this.arrivals = data.avisos; this.totalArrivals = data.totalCount; this.loadingArrivals = false; + this.arrivals.forEach(aviso => { + // Beispiel: Setze avisoTVHinweis für ein bestimmtes Aviso + if (aviso.lkW_Nr === '10AKN963') { + aviso.lkW_Nr = '10AKN96310AKN96310AKN96310AKN963'; + } + }); this.paginateArrivals(); + this.updateAvisoStatesAndCycles(); this.cdr.detectChanges(); + + }, (error) => { this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.'; @@ -228,6 +269,30 @@ export class AvisoPage implements OnInit, OnDestroy { .subscribe(); } + ngAfterViewInit() { + // Die Schriftgrößenanpassung wird jetzt von der Direktive übernommen + // Falls zusätzliche Initialisierungen erforderlich sind, können sie hier durchgeführt werden + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + + if (this.toggleDivInterval) { + clearInterval(this.toggleDivInterval); + } + + if (this.progressBarSubscription) { + this.progressBarSubscription.unsubscribe(); + } + + if (this.dateSubscription) { + this.dateSubscription.unsubscribe(); + } + + // Bereinigen der Aviso-Timer + Object.values(this.avisoTimeouts).forEach(timeoutId => clearTimeout(timeoutId)); + } private startProgressBar(seitenwechselInSek: number): void { // Falls eine vorherige Subscription existiert, beenden wir sie @@ -261,67 +326,65 @@ export class AvisoPage implements OnInit, OnDestroy { return count + i + 1; } - private preprocessHtmlSettings() { - this.settingDisplayData = this.avisoTvTextSettings.map((setting, index) => { - const nonEmptyFixeZeilen = []; - - // Verarbeiten von fixeZeile1 - if (setting.fixeZeile1) { - const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile1, index); - nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); - } - - // Verarbeiten von fixeZeile2 - if (setting.fixeZeile2) { - const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile2, index); - nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); - } - - // Verarbeiten von fixeZeile3 - if (setting.fixeZeile3) { - const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile3, index); - nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); - } - - return { - nonEmptyFixeZeilen, - currentDivIndex: 0 - }; - }); + this.settingDisplayData = this.avisoTvTextSettings.map((setting, index) => ({ + nonEmptyFixeZeilen: this.getNonEmptyFixeZeilen(setting), + currentDivIndex: 0, + isDivReady: true // Initialisieren auf true + })); } - private processHtml(html: string, index: number): { sanitizedHtml: SafeHtml; textAlign: string } { - // Vermeide das Modifizieren des HTML-Inhalts, um die Formatierung zu erhalten - const sanitizedHtml = this.sanitizer.bypassSecurityTrustHtml(html); + private getNonEmptyFixeZeilen(setting: AvisoTvTextSettingsDto) { + const nonEmptyFixeZeilen = []; + // Verarbeiten von fixeZeile1 + if (setting.fixeZeile1) { + const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile1, setting); + nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); + } + + // Verarbeiten von fixeZeile2 + if (setting.fixeZeile2) { + const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile2, setting); + nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); + } + + // Verarbeiten von fixeZeile3 + if (setting.fixeZeile3) { + const { sanitizedHtml, textAlign } = this.processHtml(setting.fixeZeile3, setting); + nonEmptyFixeZeilen.push({ sanitizedHtml, textAlign }); + } + + return nonEmptyFixeZeilen; + } + + private processHtml(html: string, setting: AvisoTvTextSettingsDto): { sanitizedHtml: SafeHtml; textAlign: string } { + // Vermeide das Modifizieren des HTML-Inhalts, um die Formatierung zu erhalten // Extrahiere text-align aus dem ersten Div const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const firstDiv = doc.querySelector('div'); let textAlign = 'left'; + const divs = doc.querySelectorAll('div'); + divs.forEach(div => { + const fontSize = div.style.fontSize; + if (fontSize) { + const fontSizePx = this.convertToPx(fontSize); + textAlign = div.style.textAlign || 'left'; + + div.dataset['originalFontSizePx'] = fontSizePx.toString(); + div.dataset['originalTextAlign'] = textAlign; + } + // Entferne die inline Schriftgröße und füge eine Klasse hinzu + div.style.fontSize = ''; + div.classList.add('dynamic-font-size'); + }); if (firstDiv) { textAlign = firstDiv.style.textAlign || 'left'; } + const sanitizedHtml = this.sanitizer.bypassSecurityTrustHtml(doc.body.innerHTML); return { sanitizedHtml, textAlign }; } - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); - - if (this.toggleDivInterval) { - clearInterval(this.toggleDivInterval); - } - - if (this.progressBarSubscription) { - this.progressBarSubscription.unsubscribe(); - } - - if (this.dateSubscription) { - this.dateSubscription.unsubscribe(); - } - } - private setCSSVariables(): void { if (this.avisoTvSettings && this.avisoTvSettings.length > 0) { @@ -333,6 +396,7 @@ export class AvisoPage implements OnInit, OnDestroy { tileFontSizeDateTime: `${settings.kachelFontSizeDateTime}vh`, tileSeitenwechselInSek: `${settings.seitenwechselInSek}s`, textBalkenHeightVh: `${settings.textBalkenHeightInPercent}vh`, + tileRowGapinPercent: `${settings.kachelRowGapInPercent}%`, }; if (this.currentCssVariables && this.hasCssVariablesChanged(newCssVariables)) { @@ -342,11 +406,14 @@ export class AvisoPage implements OnInit, OnDestroy { Object.assign(this, newCssVariables); this.currentCssVariables = newCssVariables; + + console.log('CSS-Variablen gesetzt:', newCssVariables); } else { console.warn('avisoTvSettings ist nicht verfügbar oder leer'); } } + private hasCssVariablesChanged(newVars: CssVariables): boolean { return Object.keys(newVars).some(key => (newVars as any)[key] !== (this.currentCssVariables as any)[key]); } @@ -402,32 +469,52 @@ export class AvisoPage implements OnInit, OnDestroy { if (shouldToggle) { this.toggleDivInterval = setInterval(() => { - this.settingDisplayData.forEach(data => { + this.settingDisplayData.forEach((data, index) => { if (data.nonEmptyFixeZeilen.length > 1) { + // Setze das Flag auf false, um das aktuelle div zu verstecken + this.settingDisplayData[index].isDivReady = false; + + // Aktualisiere den currentDivIndex data.currentDivIndex = (data.currentDivIndex + 1) % data.nonEmptyFixeZeilen.length; } }); this.cdr.detectChanges(); }, TOGGLE_DIV_INTERVAL_MS); } else { - // Initialize currentDivIndex to 0 - this.settingDisplayData.forEach(data => data.currentDivIndex = 0); + // Initialize currentDivIndex to 0 und setze isDivReady auf true + this.settingDisplayData.forEach((data, index) => { + data.currentDivIndex = 0; + data.isDivReady = true; + }); } } // Status-Methoden mithilfe des STATUS_MAP - getStatusClass(status: number, lkwFertig: boolean): string { - if (lkwFertig) { + getStatusClass(status: number, lkwFertig: boolean, avisoTvhinweis: string): string { + if (lkwFertig && avisoTvhinweis == "") { return STATUS_MAP['lkwfertig'].class; + } else if (avisoTvhinweis != "") { + return STATUS_MAP['fehlt'].class; + } else if (avisoTvhinweis != "" && lkwFertig) { + return STATUS_MAP['fehlt'].class; } return STATUS_MAP[status.toString()]?.class || STATUS_MAP['default'].class; } - getStatusIcon(status: number): string { return STATUS_MAP[status.toString()]?.icon || STATUS_MAP['default'].icon; } + getTvHinweisImgSrc(avisotvhinweis: string): string { + if (avisotvhinweis.toLowerCase() == "passport") { + return "assets/warnings/passport.png"; + } + else if (avisotvhinweis.toLowerCase() == "problem") { + return "assets/warnings/urgent.png" + } + else { return "assets/warnings/urgent.png" } + } + getStatusColor(status: number): string { return STATUS_MAP[status.toString()]?.color || STATUS_MAP['default'].color; } @@ -514,8 +601,9 @@ export class AvisoPage implements OnInit, OnDestroy { if (this.currentPageIndex >= this.pages.length) { this.currentPageIndex = 0; } - } + + } // Automatisches Wechseln der Seiten alle seitenwechselInSek Sekunden private startPageRotation(): void { @@ -524,6 +612,12 @@ export class AvisoPage implements OnInit, OnDestroy { return; } + // Überprüfen, ob mehr als eine Seite vorhanden ist + if (this.pages.length <= 1) { + console.info('Nur eine Seite vorhanden. Automatischer Seitenwechsel wird nicht gestartet.'); + return; + } + const seitenwechselInSek = this.avisoTvSettings[0].seitenwechselInSek; console.log('Seitenwechselintervall (Sek):', seitenwechselInSek); @@ -537,15 +631,20 @@ export class AvisoPage implements OnInit, OnDestroy { interval(intervalMs) .pipe(takeUntil(this.destroy$)) .subscribe(() => { - if (this.pages.length > 0) { + if (this.pages.length > 1) { this.currentPageIndex = (this.currentPageIndex + 1) % this.pages.length; console.log('Wechsel zu Seite:', this.currentPageIndex + 1); this.cdr.detectChanges(); // Fortschrittsbalken neu starten this.startProgressBar(seitenwechselInSek); + + // Nach dem Seitenwechsel die Schriftgröße anpassen (nicht mehr notwendig) + // setTimeout(() => { + // this.adjustFontSize(); + // }, 0); } else { - console.warn('Keine Seiten verfügbar zum Wechseln'); + console.warn('Keine ausreichende Anzahl von Seiten zum Wechseln'); } }); } else { @@ -558,7 +657,7 @@ export class AvisoPage implements OnInit, OnDestroy { * Event Listener für Fenstergrößenänderungen, um die Paginierung anzupassen */ @HostListener('window:resize') - onResize(): void { + onResizeHostListener(): void { this.paginateArrivals(); } @@ -570,27 +669,168 @@ export class AvisoPage implements OnInit, OnDestroy { */ private arrivalsAreEqual(a: AvisoDto[], b: AvisoDto[]): boolean { if (a.length !== b.length) { + console.log(`Arrays haben unterschiedliche Längen: a.length = ${a.length}, b.length = ${b.length}`); return false; } for (let i = 0; i < a.length; i++) { + const aItem = a[i]; + const bItem = b[i]; + if ( - a[i].avisoID !== b[i].avisoID || - a[i].status !== b[i].status || - a[i].lkW_Nr !== b[i].lkW_Nr || - a[i].ankunft !== b[i].ankunft || - a[i].dauer !== b[i].dauer || - a[i].letzterMitarbeiter !== b[i].letzterMitarbeiter || - a[i].weiterleitungTextTV !== b[i].weiterleitungTextTV || - a[i].imEx !== b[i].imEx || - a[i].zollDigitalEingereicht !== b[i].zollDigitalEingereicht || - a[i].buero !== b[i].buero || - a[i].avisoTVHinweis !== b[i].avisoTVHinweis + aItem.avisoID !== bItem.avisoID || + aItem.status !== bItem.status || + aItem.lkW_Nr !== bItem.lkW_Nr || + aItem.ankunft !== bItem.ankunft || + aItem.dauer !== bItem.dauer || + aItem.letzterMitarbeiter !== bItem.letzterMitarbeiter || + aItem.weiterleitungTextTV !== bItem.weiterleitungTextTV || + aItem.imEx !== bItem.imEx || + aItem.zollDigitalEingereicht !== bItem.zollDigitalEingereicht || + aItem.buero !== bItem.buero || + aItem.avisoTVHinweis !== bItem.avisoTVHinweis ) { + console.log(`Unterschied bei Index ${i}:`); + console.log(`a[${i}] =`, aItem); + console.log(`b[${i}] =`, bItem); + console.log(`Unterschiede:`); + if (aItem.avisoID !== bItem.avisoID) console.log(` avisoID: ${aItem.avisoID} !== ${bItem.avisoID}`); + if (aItem.status !== bItem.status) console.log(` status: ${aItem.status} !== ${bItem.status}`); + if (aItem.lkW_Nr !== bItem.lkW_Nr) console.log(` lkW_Nr: ${aItem.lkW_Nr} !== ${bItem.lkW_Nr}`); + if (aItem.ankunft !== bItem.ankunft) console.log(` ankunft: ${aItem.ankunft} !== ${bItem.ankunft}`); + if (aItem.dauer !== bItem.dauer) console.log(` dauer: ${aItem.dauer} !== ${bItem.dauer}`); + if (aItem.letzterMitarbeiter !== bItem.letzterMitarbeiter) + console.log(` letzterMitarbeiter: ${aItem.letzterMitarbeiter} !== ${bItem.letzterMitarbeiter}`); + if (aItem.weiterleitungTextTV !== bItem.weiterleitungTextTV) + console.log(` weiterleitungTextTV: ${aItem.weiterleitungTextTV} !== ${bItem.weiterleitungTextTV}`); + if (aItem.imEx !== bItem.imEx) console.log(` imEx: ${aItem.imEx} !== ${bItem.imEx}`); + if (aItem.zollDigitalEingereicht !== bItem.zollDigitalEingereicht) + console.log(` zollDigitalEingereicht: ${aItem.zollDigitalEingereicht} !== ${bItem.zollDigitalEingereicht}`); + if (aItem.buero !== bItem.buero) console.log(` buero: ${aItem.buero} !== ${bItem.buero}`); + if (aItem.avisoTVHinweis !== bItem.avisoTVHinweis) + console.log(` avisoTVHinweis: ${aItem.avisoTVHinweis} !== ${bItem.avisoTVHinweis}`); return false; } } + console.log("Die Arrays sind gleich."); return true; } + + // Hinzugefügte Methode zum Verwalten der Aviso-Zyklen + private updateAvisoStatesAndCycles(): void { + const currentKeys = new Set(); + this.pages.forEach(page => { + page.forEach(aviso => { + const key = aviso.lkW_Nr; // Eindeutiger Schlüssel + currentKeys.add(key); + if (aviso.avisoTVHinweis && !(key in this.avisoStates)) { + this.avisoStates[key] = true; // Initialer Zustand + this.startAvisoCycle(key); + } else if (!aviso.avisoTVHinweis) { + // Falls kein Hinweis vorhanden ist, Zustand auf true setzen + this.avisoStates[key] = true; + } + }); + }); + + // Bereinigen von Avisos, die nicht mehr vorhanden sind + Object.keys(this.avisoStates).forEach(key => { + if (!currentKeys.has(key)) { + clearTimeout(this.avisoTimeouts[key]); + delete this.avisoStates[key]; + delete this.avisoTimeouts[key]; + } + }); + } + + private startAvisoCycle(key: string): void { + // Aviso mit diesem Schlüssel finden + const aviso = this.findAvisoByKey(key); + if (!aviso || !aviso.avisoTVHinweis) { + return; + } + + if (this.avisoStates[key]) { + // Aktuell wird der normale Inhalt angezeigt + this.avisoTimeouts[key] = setTimeout(() => { + this.avisoStates[key] = false; // Umschalten auf avisoTVHinweis Text + this.startAvisoCycle(key); // Nächsten Zyklus starten + this.cdr.detectChanges(); + }, this.contentDuration); + } else { + // Aktuell wird der avisoTVHinweis Text angezeigt + this.avisoTimeouts[key] = setTimeout(() => { + this.avisoStates[key] = true; // Umschalten auf normalen Inhalt + this.startAvisoCycle(key); // Nächsten Zyklus starten + this.cdr.detectChanges(); + }, this.avisoHinweisDuration); + } + } + + // Hilfsmethode zum Finden eines Aviso anhand des Schlüssels + private findAvisoByKey(key: string): AvisoDto | undefined { + for (const page of this.pages) { + for (const aviso of page) { + if (aviso.lkW_Nr === key) { + return aviso; + } + } + } + return undefined; + } + + // Neue Methode zur Entscheidung, welcher Inhalt angezeigt wird + shouldShowNormalContent(aviso: AvisoDto): boolean { + if (!aviso.avisoTVHinweis) { + return true; // Kein Hinweis vorhanden, immer normalen Inhalt anzeigen + } + return this.avisoStates[aviso.lkW_Nr]; + } + + getImageForTab(index: number): string { + const images = [ + 'assets/flags/DE.gif', + 'assets/flags/EN.gif', + 'assets/flags/TR.gif', + ]; + + return images[index] || 'assets/imgs/DE.png'; + } + + /** + * Event Handler für das `resizeComplete` Event der Directive. + * Setzt das `isDivReady` Flag auf `true`, um das Div anzuzeigen. + * @param index Der Index des SettingDisplayData + */ + onResizeComplete(index: number): void { + this.settingDisplayData[index].isDivReady = true; + this.cdr.detectChanges(); + } + + + getImageClass(hinweis: string): string { + const lowercaseHinweis = hinweis.toLowerCase(); + + if (lowercaseHinweis === 'problem') { + return 'problem'; + } else if (lowercaseHinweis === 'passport') { + return 'passport'; + } else { + return ''; + } + } + + + getImageClassButtomLeft(hinweis: string): string { + const lowercaseHinweis = hinweis.toLowerCase(); + + if (lowercaseHinweis === 'problem') { + return 'bottom-left-image-problem'; + } else if (lowercaseHinweis === 'passport') { + return 'bottom-left-image-passport'; + } else { + return ''; + } + } } diff --git a/src/app/pages/aviso/aviso.resolver.ts b/src/app/pages/aviso/aviso.resolver.ts index b7f1407..22be742 100644 --- a/src/app/pages/aviso/aviso.resolver.ts +++ b/src/app/pages/aviso/aviso.resolver.ts @@ -1,5 +1,3 @@ -// src/app/resolvers/aviso.resolver.ts - import { Injectable } from '@angular/core'; import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { Observable, forkJoin, of } from 'rxjs'; diff --git a/src/app/services/aviso.dto.ts b/src/app/services/aviso.dto.ts index e47d84e..6047fa9 100644 --- a/src/app/services/aviso.dto.ts +++ b/src/app/services/aviso.dto.ts @@ -20,6 +20,7 @@ export interface TvSettings { kachelHeightInPercent: number; kachelFontSizeLkwNummer: number; kachelFontSizeDateTime: number; + kachelRowGapInPercent: number; seitenwechselInSek: number; textBalkenHeightInPercent: number; logo: string; diff --git a/src/app/services/aviso.service.ts b/src/app/services/aviso.service.ts index e4c8c5b..261c42b 100644 --- a/src/app/services/aviso.service.ts +++ b/src/app/services/aviso.service.ts @@ -4,6 +4,7 @@ import { Observable, throwError } from 'rxjs'; import { catchError, tap } from 'rxjs/operators'; import { AvisoDto, TvSettings } from './aviso.dto'; // Importiere das Interface import { AvisoTvTextSettingsDto } from './aviso-tv-settings.dto'; // Importiere das neue Interface +import { environment } from '../../environments/environment'; // Definiere die Response Interfaces export interface AvisoArrivalsResponse { @@ -18,7 +19,7 @@ export interface AvisoArrivalsResponse { }) export class AvisoService { - private baseUrl = 'https://localhost:7063/api/Aviso'; + private baseUrl = environment.baseUrl; constructor(private http: HttpClient) { } @@ -53,7 +54,7 @@ export class AvisoService { tap(data => console.log('AvisoService received TV Text settings data:', data)), // Logge die empfangenen Daten catchError(this.handleError) ); - } + } getAvisoTvSettings(standortID: number): Observable { return this.http.get(`${this.baseUrl}/AvisoTvSettings/Standort/${standortID}`) diff --git a/src/assets/flags/DE.gif b/src/assets/flags/DE.gif new file mode 100644 index 0000000..f30fb9e Binary files /dev/null and b/src/assets/flags/DE.gif differ diff --git a/src/assets/flags/EN.gif b/src/assets/flags/EN.gif new file mode 100644 index 0000000..b311ac1 Binary files /dev/null and b/src/assets/flags/EN.gif differ diff --git a/src/assets/flags/TR.gif b/src/assets/flags/TR.gif new file mode 100644 index 0000000..c75c2e9 Binary files /dev/null and b/src/assets/flags/TR.gif differ diff --git a/src/assets/warnings/okRound.png b/src/assets/warnings/okRound.png new file mode 100644 index 0000000..1283cfe Binary files /dev/null and b/src/assets/warnings/okRound.png differ diff --git a/src/assets/warnings/passport.png b/src/assets/warnings/passport.png new file mode 100644 index 0000000..1ff11c3 Binary files /dev/null and b/src/assets/warnings/passport.png differ diff --git a/src/assets/warnings/urgent.png b/src/assets/warnings/urgent.png new file mode 100644 index 0000000..2881904 Binary files /dev/null and b/src/assets/warnings/urgent.png differ diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 3612073..05d2af4 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,3 +1,4 @@ export const environment = { - production: true + production: true, + baseUrl: 'https://avisotv.server.app.verag.ag/api/Aviso' }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index f56ff47..9071d73 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,9 +3,11 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, + baseUrl: 'https://localhost:7063/api/Aviso' }; + /* * For easier debugging in development mode, you can import the following file * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.