v1
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -45,6 +45,7 @@ yarn-error.log
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vs/*
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
|
||||
39
.vscode/launch.json
vendored
Normal file
39
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "localhost (Chrome)",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:8100",
|
||||
"webRoot": "${workspaceFolder}/www",
|
||||
"preLaunchTask": "ng serve",
|
||||
"sourceMaps": true,
|
||||
"trace": true
|
||||
},
|
||||
{
|
||||
"name": "Debug node process",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${workspaceFolder}/capacitor.config.ts",
|
||||
"skipFiles": [
|
||||
"<node_internals/**"
|
||||
],
|
||||
"stopOnEntry": true,
|
||||
"console": "externalTerminal",
|
||||
"env": {
|
||||
"port": "5000"
|
||||
}
|
||||
}
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
"name": "Launch Node and Browser",
|
||||
"configurations": [
|
||||
"Debug node process",
|
||||
"localhost (Chrome)"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
11
MIGRATED_PROJECT - Backup.esproj
Normal file
11
MIGRATED_PROJECT - Backup.esproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/0.5.89-alpha">
|
||||
<PropertyGroup>
|
||||
<!--Command to run on project build-->
|
||||
<BuildCommand>ionic build</BuildCommand>
|
||||
<!--Command to run on project clean-->
|
||||
<CleanCommand>
|
||||
</CleanCommand>
|
||||
<StartupCommand>
|
||||
</StartupCommand>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
10
PROJECT_MIGRATION_LOG.txt
Normal file
10
PROJECT_MIGRATION_LOG.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Hello! Thank you for trying out our new JavaScript and TypeScript project experience. We've added the below list of files to your project directory in order to enable the new experience:
|
||||
|
||||
C:\Users\m.ilhan\source\repos\verag\.vscode\launch.json
|
||||
C:\Users\m.ilhan\source\repos\verag\nuget.config
|
||||
C:\Users\m.ilhan\source\repos\verag\MIGRATED_PROJECT.esproj
|
||||
C:\Users\m.ilhan\source\repos\verag\PROJECT_MIGRATION_LOG.txt
|
||||
|
||||
We'd love to get your feedback! Please submit any bugs or improvements that need to be made by going to Help -> Send Feedback.
|
||||
|
||||
If you'd like to revert to your original project, you can right-click on the project and click on 'Revert Project To Old Experience'.
|
||||
36
VeragTVAppFrontend.sln
Normal file
36
VeragTVAppFrontend.sln
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.11.35327.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{54A90642-561A-4BB1-A94E-469ADEE60C69}") = "VeragTvApp.client", "VeragTvApp.client.esproj", "{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C} = {C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VeragTvApp.server", "..\VeragTvApp\VeragTvApp.server.csproj", "{C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1650CC57-EA5F-4ACF-BD98-B8A5DED15956}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C085CCA8-3E7E-4AA3-A0C5-D41DDAF8192C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9B2DABB1-ADAB-46C3-B82D-B9BB96C00E15}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
9
VeragTvApp.client.esproj
Normal file
9
VeragTvApp.client.esproj
Normal file
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.VisualStudio.JavaScript.Sdk/0.5.89-alpha">
|
||||
<PropertyGroup>
|
||||
<!--Command to run on project build-->
|
||||
<!--Command to run on project clean-->
|
||||
<CleanCommand>
|
||||
</CleanCommand>
|
||||
<StartupCommand>ionic serve</StartupCommand>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
4
VeragTvApp.client.esproj.user
Normal file
4
VeragTvApp.client.esproj.user
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
10
nuget.config
Normal file
10
nuget.config
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear />
|
||||
</disabledPackageSources>
|
||||
</configuration>
|
||||
1
obj/Debug/MIGRATED_PROJECT.esproj.FileListAbsolute.txt
Normal file
1
obj/Debug/MIGRATED_PROJECT.esproj.FileListAbsolute.txt
Normal file
@@ -0,0 +1 @@
|
||||
C:\Users\m.ilhan\source\repos\verag\obj\Debug\MIGRATED_PROJECT.esproj.CoreCompileInputs.cache
|
||||
1
obj/Debug/VeragTvApp.client.esproj.FileListAbsolute.txt
Normal file
1
obj/Debug/VeragTvApp.client.esproj.FileListAbsolute.txt
Normal file
@@ -0,0 +1 @@
|
||||
C:\Users\m.ilhan\source\repos\verag\obj\Debug\VeragTvApp.client.esproj.CoreCompileInputs.cache
|
||||
21
package-lock.json
generated
21
package-lock.json
generated
@@ -21,9 +21,10 @@
|
||||
"@capacitor/haptics": "6.0.1",
|
||||
"@capacitor/keyboard": "6.0.2",
|
||||
"@capacitor/status-bar": "6.0.1",
|
||||
"@ionic/angular": "^8.0.0",
|
||||
"@ionic/angular": "^8.4.0",
|
||||
"ionicons": "^7.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"swiper": "^11.1.15",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.2"
|
||||
},
|
||||
@@ -14801,6 +14802,24 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/swiper": {
|
||||
"version": "11.1.15",
|
||||
"resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.15.tgz",
|
||||
"integrity": "sha512-IzWeU34WwC7gbhjKsjkImTuCRf+lRbO6cnxMGs88iVNKDwV+xQpBCJxZ4bNH6gSrIbbyVJ1kuGzo3JTtz//CBw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/swiperjs"
|
||||
},
|
||||
{
|
||||
"type": "open_collective",
|
||||
"url": "http://opencollective.com/swiper"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 4.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/symbol-observable": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz",
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
"@capacitor/haptics": "6.0.1",
|
||||
"@capacitor/keyboard": "6.0.2",
|
||||
"@capacitor/status-bar": "6.0.1",
|
||||
"@ionic/angular": "^8.0.0",
|
||||
"@ionic/angular": "^8.4.0",
|
||||
"ionicons": "^7.0.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"swiper": "^11.1.15",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.2"
|
||||
},
|
||||
|
||||
@@ -4,17 +4,17 @@ import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'home',
|
||||
loadChildren: () => import('./home/home.module').then( m => m.HomePageModule)
|
||||
loadChildren: () => import('./pages/home/home.module').then( m => m.HomePageModule)
|
||||
},
|
||||
{
|
||||
path: 'message/:id',
|
||||
loadChildren: () => import('./view-message/view-message.module').then( m => m.ViewMessagePageModule)
|
||||
path: 'aviso',
|
||||
loadChildren: () => import('./pages/aviso/aviso.module').then( m => m.AvisoPageModule)
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'home',
|
||||
redirectTo: 'aviso',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
IonicModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
HttpClientModule // Hinzufügen
|
||||
],
|
||||
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
export class AppModule { }
|
||||
|
||||
128
src/app/directives/auto-resize-text.directive.ts
Normal file
128
src/app/directives/auto-resize-text.directive.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Directive, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { debounceTime, takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Directive({
|
||||
selector: '[autoResizeText]'
|
||||
})
|
||||
export class AutoResizeTextDirective implements AfterViewInit, OnDestroy {
|
||||
private resizeObserver!: ResizeObserver;
|
||||
private resize$ = new Subject<void>();
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(private el: ElementRef) { }
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.adjustFontSizes();
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
this.resize$.next();
|
||||
});
|
||||
this.resizeObserver.observe(this.el.nativeElement);
|
||||
|
||||
// Debounce der Resize-Events
|
||||
this.resize$.pipe(
|
||||
debounceTime(100), // Warte 100ms nach dem letzten Resize-Event
|
||||
takeUntil(this.destroy$)
|
||||
).subscribe(() => {
|
||||
this.adjustFontSizes();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.disconnect();
|
||||
}
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Passt die Schriftgrößen der einzelnen Spans individuell an.
|
||||
*/
|
||||
private adjustFontSizes() {
|
||||
const container: HTMLElement = this.el.nativeElement;
|
||||
const spans: HTMLElement[] = Array.from(container.querySelectorAll('div.dynamic-font-size'));
|
||||
|
||||
// Store the original font sizes
|
||||
spans.forEach(span => {
|
||||
if (!span.dataset['originalFontSizePx']) {
|
||||
const computedStyle = window.getComputedStyle(span);
|
||||
const originalFontSizePx = parseFloat(computedStyle.fontSize);
|
||||
span.dataset['originalFontSizePx'] = originalFontSizePx.toString();
|
||||
}
|
||||
});
|
||||
|
||||
// Reset font sizes to original
|
||||
spans.forEach(span => {
|
||||
const originalFontSizePx = parseFloat(span.dataset['originalFontSizePx'] || '16');
|
||||
span.style.fontSize = `${originalFontSizePx}px`;
|
||||
});
|
||||
|
||||
// If content overflows, adjust font sizes
|
||||
if (this.isOverflowing(container)) {
|
||||
// Find the scaling factor needed to fit the content
|
||||
let scalingFactor = this.calculateScalingFactor(container, spans);
|
||||
|
||||
// Apply the scaling factor to all spans
|
||||
spans.forEach(span => {
|
||||
const originalFontSizePx = parseFloat(span.dataset['originalFontSizePx'] || '16');
|
||||
let newFontSizePx = originalFontSizePx * scalingFactor;
|
||||
|
||||
// Ensure the font size doesn't go below a minimum value
|
||||
const minFontSizePx = 12;
|
||||
if (newFontSizePx < minFontSizePx) {
|
||||
newFontSizePx = minFontSizePx;
|
||||
}
|
||||
|
||||
span.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.
|
||||
*/
|
||||
private calculateScalingFactor(container: HTMLElement, spans: HTMLElement[]): number {
|
||||
const minFontSizePx = 12; // Minimum font size
|
||||
let low = 0.1; // 10% scaling
|
||||
let high = 1; // 100% scaling
|
||||
let mid = 1;
|
||||
|
||||
// Binary search to find the optimal scaling factor
|
||||
while (high - low > 0.01) {
|
||||
mid = (low + high) / 2;
|
||||
|
||||
// Apply scaling factor
|
||||
spans.forEach(span => {
|
||||
const originalFontSizePx = parseFloat(span.dataset['originalFontSizePx'] || '16');
|
||||
let newFontSizePx = originalFontSizePx * mid;
|
||||
if (newFontSizePx < minFontSizePx) {
|
||||
newFontSizePx = minFontSizePx;
|
||||
}
|
||||
span.style.fontSize = `${newFontSizePx}px`;
|
||||
});
|
||||
|
||||
// Check if content overflows
|
||||
if (this.isOverflowing(container)) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Überprüft, ob der Inhalt des Containers überläuft.
|
||||
* @param container Das zu überprüfende HTMLElement.
|
||||
* @returns Wahr, wenn ein Überlauf vorliegt, sonst falsch.
|
||||
*/
|
||||
private isOverflowing(container: HTMLElement): boolean {
|
||||
return container.scrollWidth > container.clientWidth || container.scrollHeight > container.clientHeight;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<ion-header [translucent]="true">
|
||||
<ion-toolbar>
|
||||
<ion-title>
|
||||
Inbox
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content [fullscreen]="true">
|
||||
<ion-refresher slot="fixed" (ionRefresh)="refresh($event)">
|
||||
<ion-refresher-content></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
|
||||
<ion-header collapse="condense">
|
||||
<ion-toolbar>
|
||||
<ion-title size="large">
|
||||
Inbox
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-list>
|
||||
<app-message *ngFor="let message of getMessages()" [message]="message"></app-message>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
@@ -1,25 +0,0 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { RefresherCustomEvent } from '@ionic/angular';
|
||||
import { MessageComponent } from '../message/message.component';
|
||||
|
||||
import { DataService, Message } from '../services/data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: 'home.page.html',
|
||||
styleUrls: ['home.page.scss'],
|
||||
})
|
||||
export class HomePage {
|
||||
private data = inject(DataService);
|
||||
constructor() {}
|
||||
|
||||
refresh(ev: any) {
|
||||
setTimeout(() => {
|
||||
(ev as RefresherCustomEvent).detail.complete();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
getMessages(): Message[] {
|
||||
return this.data.getMessages();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<ion-item *ngIf="message" [routerLink]="'/message/' + message.id" [detail]="false">
|
||||
<div slot="start" [class]="!message.read ? 'dot dot-unread' : 'dot'"></div>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2>
|
||||
{{ message.fromName }}
|
||||
<span class="date">
|
||||
<ion-note>{{ message.date }}</ion-note>
|
||||
<ion-icon aria-hidden="true" name="chevron-forward" size="small" *ngIf="isIos()"></ion-icon>
|
||||
</span>
|
||||
</h2>
|
||||
<h3>{{ message.subject }}</h3>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
@@ -1,69 +0,0 @@
|
||||
ion-item {
|
||||
--padding-start: 0;
|
||||
--inner-padding-end: 0;
|
||||
}
|
||||
|
||||
ion-label {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
ion-item h2 {
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
|
||||
/**
|
||||
* With larger font scales
|
||||
* the date/time should wrap to the next
|
||||
* line. However, there should be
|
||||
* space between the name and the date/time
|
||||
* if they can appear on the same line.
|
||||
*/
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
ion-item p {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
ion-item .date {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
ion-item ion-icon {
|
||||
color: #c9c9ca;
|
||||
}
|
||||
|
||||
ion-item ion-note {
|
||||
font-size: 0.9375rem;
|
||||
margin-right: 8px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
ion-item ion-note.md {
|
||||
margin-right: 14px;
|
||||
}
|
||||
|
||||
.dot {
|
||||
display: block;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border-radius: 50%;
|
||||
align-self: start;
|
||||
margin: 16px 10px 16px 16px;
|
||||
}
|
||||
|
||||
.dot-unread {
|
||||
background: var(--ion-color-primary);
|
||||
}
|
||||
|
||||
ion-footer ion-title {
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { MessageComponent } from './message.component';
|
||||
|
||||
describe('MessageComponent', () => {
|
||||
let component: MessageComponent;
|
||||
let fixture: ComponentFixture<MessageComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [MessageComponent],
|
||||
imports: [IonicModule.forRoot(), RouterModule.forRoot([])]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MessageComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, inject, Input } from '@angular/core';
|
||||
import { Platform } from '@ionic/angular';
|
||||
import { Message } from '../services/data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-message',
|
||||
templateUrl: './message.component.html',
|
||||
styleUrls: ['./message.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MessageComponent {
|
||||
private platform = inject(Platform);
|
||||
@Input() message?: Message;
|
||||
isIos() {
|
||||
return this.platform.is('ios')
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { MessageComponent } from './message.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule, FormsModule, IonicModule, RouterModule],
|
||||
declarations: [MessageComponent],
|
||||
exports: [MessageComponent]
|
||||
})
|
||||
export class MessageComponentModule {}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { ViewMessagePage } from './view-message.page';
|
||||
import { AvisoPage } from './aviso.page';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ViewMessagePage
|
||||
component: AvisoPage
|
||||
}
|
||||
];
|
||||
|
||||
@@ -14,4 +14,4 @@ const routes: Routes = [
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ViewMessagePageRoutingModule {}
|
||||
export class AvisoPageRoutingModule {}
|
||||
23
src/app/pages/aviso/aviso.module.ts
Normal file
23
src/app/pages/aviso/aviso.module.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { AvisoPageRoutingModule } from './aviso-routing.module';
|
||||
import { AutoResizeTextDirective } from '../../directives/auto-resize-text.directive';
|
||||
|
||||
import { AvisoPage } from './aviso.page';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
AvisoPageRoutingModule
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [AvisoPage, AutoResizeTextDirective]
|
||||
})
|
||||
export class AvisoPageModule {}
|
||||
96
src/app/pages/aviso/aviso.page.html
Normal file
96
src/app/pages/aviso/aviso.page.html
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
<ion-content fullscreen>
|
||||
<!-- Titel für Arrivals -->
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title class="ion-text-center">
|
||||
Ankünfte ({{ totalArrivals }}) Seite {{ currentPageIndex + 1 }} von {{ pages.length }}
|
||||
</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<!-- Fehlernachricht anzeigen -->
|
||||
<ion-grid>
|
||||
<ion-row *ngIf="errorMessage">
|
||||
<ion-col size="12" class="ion-text-center">
|
||||
<ion-text color="danger">
|
||||
<p>{{ errorMessage }}</p>
|
||||
</ion-text>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
|
||||
<!-- Ladeindikator -->
|
||||
<ion-row *ngIf="loadingArrivals && arrivals.length === 0">
|
||||
<ion-col size="12" class="ion-text-center">
|
||||
<ion-spinner name="crescent"></ion-spinner>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<!-- Grid-Container für Arrivals Kacheln -->
|
||||
<div class="grid-container" *ngIf="!loadingArrivals && pages.length > 0">
|
||||
<ion-card *ngFor="let aviso of pages[currentPageIndex]"
|
||||
class="arrival-card"
|
||||
[ngClass]="getStatusClass(aviso.status)">
|
||||
<ion-card-header>
|
||||
<ion-card-title class="ion-text-center">
|
||||
<strong>{{ aviso.lkW_Nr }}</strong>
|
||||
</ion-card-title>
|
||||
</ion-card-header>
|
||||
<ion-card-content>
|
||||
<!-- Zentrierter Absatz für Ankunft und Dauer -->
|
||||
<div class="centered-content">
|
||||
<p class="ion-text-center">
|
||||
<ion-icon [name]="getStatusIcon(aviso.status)"
|
||||
[color]="getStatusColor(aviso.status)"></ion-icon>
|
||||
{{ aviso.ankunft }}
|
||||
<ion-icon name="hourglass-outline"></ion-icon>
|
||||
{{ aviso.dauer }}
|
||||
</p>
|
||||
<p class="ion-text-center">
|
||||
<ion-icon name="person-outline"></ion-icon>
|
||||
{{ aviso.letzterMitarbeiter }}
|
||||
</p>
|
||||
</div>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</div>
|
||||
|
||||
<!-- Nachricht, wenn keine Arrivals vorhanden sind -->
|
||||
<ion-grid>
|
||||
<ion-row *ngIf="!loadingArrivals && arrivals.length === 0 && !errorMessage">
|
||||
<ion-col size="12" class="ion-text-center">
|
||||
<ion-text>
|
||||
<p>Keine Ankünfte gefunden.</p>
|
||||
</ion-text>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
|
||||
<!-- Bedingtes Textfeld für TV-Einstellungen -->
|
||||
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
<ng-container *ngFor="let setting of avisoTvSettings; let i = index">
|
||||
<ng-container *ngIf="setting.isActive && setting.fixeZeile1">
|
||||
<ion-item>
|
||||
<!-- Erstes Div, wird angezeigt, wenn showFirstDiv true ist -->
|
||||
<div *ngIf="showFirstDiv"
|
||||
[innerHTML]="sanitizeHtml(setting.fixeZeile1 || '',i)"
|
||||
autoResizeText
|
||||
[style.text-align]="getTextAlign(i)"
|
||||
class="htmltext">
|
||||
</div>
|
||||
|
||||
<!-- Zweites Div, wird angezeigt, wenn showFirstDiv false ist -->
|
||||
<div *ngIf="!showFirstDiv"
|
||||
[innerHTML]="sanitizeHtml(setting.fixeZeile2 || '',i)"
|
||||
autoResizeText
|
||||
[style.text-align]="getTextAlign(i)"
|
||||
class="htmltext">
|
||||
</div>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ion-footer>
|
||||
149
src/app/pages/aviso/aviso.page.scss
Normal file
149
src/app/pages/aviso/aviso.page.scss
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
|
||||
ion-content {
|
||||
--background: #f0f0f0; /* Heller Hintergrund für besseren Kontrast */
|
||||
}
|
||||
|
||||
.title-card {
|
||||
background-color: #3880ff; /* Beispiel: Blaue Hintergrundfarbe */
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ion-card-content p {
|
||||
font-size: 1.8em; /* Größere Schriftgröße für die Inhalte */
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(15%, 1fr)); /* Feste Mindestbreite */
|
||||
gap: 1%; /* Abstand zwischen den Kacheln */
|
||||
padding: 0px; /* Optional: Innenabstand */
|
||||
justify-content: center; /* Zentriert die Kacheln */
|
||||
}
|
||||
|
||||
.arrival-card {
|
||||
width: 95%; /* Feste Breite */
|
||||
height: 24vh; /* Feste Höhe */
|
||||
border-radius: 15px; /* Abgerundete Ecken für ein moderneres Aussehen */
|
||||
transition: box-shadow 0.3s, transform 0.3s;
|
||||
}
|
||||
|
||||
.htmltext {
|
||||
height: 30vh;
|
||||
width: 100%;
|
||||
white-space: pre-line;
|
||||
transition: box-shadow 0.3s, transform 0.3s;
|
||||
}
|
||||
ion-content {
|
||||
ion-grid.htmltext {
|
||||
height: 30vh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ion-icon {
|
||||
vertical-align: middle;
|
||||
font-size: 1.2em; /* Größere Icons für bessere Sichtbarkeit */
|
||||
}
|
||||
|
||||
/* Statusklassen */
|
||||
.statusLKW_Erfasst {
|
||||
border-left: 10px solid #2dd36f; /* Grün */
|
||||
}
|
||||
|
||||
.statusLKW_Freigegeben {
|
||||
border-left: 10px solid #3880ff; /* Blau */
|
||||
}
|
||||
|
||||
.statusLKW_LKW_neu {
|
||||
border-left: 10px solid #f78c40; /* Orange */
|
||||
}
|
||||
|
||||
.statusLKW_Ankunft {
|
||||
border-left: 10px solid #f78c40; /* Orange */
|
||||
}
|
||||
|
||||
.statusLKW_Vorbereitet {
|
||||
border-left: 10px solid #c8c8c8; /* Grau */
|
||||
}
|
||||
|
||||
.statusLKW_Vorgeschrieben {
|
||||
border-left: 10px solid #a259ff; /* Violett */
|
||||
}
|
||||
|
||||
.status-default {
|
||||
border-left: 10px solid #c8c8c8; /* Grau */
|
||||
}
|
||||
|
||||
/* Animationen für Ankunftskarten */
|
||||
.arrival-card {
|
||||
animation: fadeIn 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
ion-card-title {
|
||||
font-size: 3.5em;
|
||||
}
|
||||
|
||||
ion-card-content p {
|
||||
font-size: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
ion-text p {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 2.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-title ion-icon {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
ion-footer {
|
||||
background-color: #ffffff;
|
||||
border-top: 1px solid #c8c8c8;
|
||||
}
|
||||
|
||||
ion-toolbar {
|
||||
--padding-start: 0;
|
||||
--padding-end: 0;
|
||||
}
|
||||
|
||||
ion-title {
|
||||
font-size: 1.6em;
|
||||
font-weight: bold;
|
||||
color: #3880ff;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
ion-title {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
17
src/app/pages/aviso/aviso.page.spec.ts
Normal file
17
src/app/pages/aviso/aviso.page.spec.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { AvisoPage } from './aviso.page';
|
||||
|
||||
describe('AvisoPage', () => {
|
||||
let component: AvisoPage;
|
||||
let fixture: ComponentFixture<AvisoPage>;
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AvisoPage);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
484
src/app/pages/aviso/aviso.page.ts
Normal file
484
src/app/pages/aviso/aviso.page.ts
Normal file
@@ -0,0 +1,484 @@
|
||||
import {
|
||||
Component,OnInit,OnDestroy,HostListener,ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AvisoService, AvisoArrivalsResponse } from '../../services/aviso.service';
|
||||
import { AvisoDto } from '../../services/aviso.dto';
|
||||
import { AvisoTvSettingsDto } from '../../services/aviso-tv-settings.dto';
|
||||
import { ToastController } from '@ionic/angular';
|
||||
import { interval, Subject } from 'rxjs';
|
||||
import { switchMap, takeUntil, startWith } from 'rxjs/operators';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-aviso',
|
||||
templateUrl: './aviso.page.html',
|
||||
styleUrls: ['./aviso.page.scss'],
|
||||
})
|
||||
export class AvisoPage implements OnInit, OnDestroy {
|
||||
|
||||
|
||||
standort: string = '';
|
||||
seiten: boolean = false;
|
||||
onlyOK: boolean = false;
|
||||
|
||||
// Datenmodelle
|
||||
arrivals: AvisoDto[] = [];
|
||||
avisoTvSettings: AvisoTvSettingsDto[] = []; // Neues Datenmodell
|
||||
|
||||
// Paginierung
|
||||
pages: AvisoDto[][] = [];
|
||||
currentPageIndex: number = 0;
|
||||
tilesPerPage: number = 0;
|
||||
|
||||
// Ladezustand
|
||||
loadingArrivals: boolean = false;
|
||||
loadingSettings: boolean = false; // Ladezustand für Einstellungen
|
||||
|
||||
// Gesamtanzahl
|
||||
totalArrivals: number = 0;
|
||||
totalSettings: number = 0; // Gesamtanzahl für Einstellungen
|
||||
|
||||
// Fehlernachricht
|
||||
errorMessage: string = '';
|
||||
settingsErrorMessage: string = ''; // Fehlernachricht für Einstellungen
|
||||
|
||||
// Subjects zum Beenden der Subscriptions
|
||||
private destroy$ = new Subject<void>();
|
||||
private pageRotation$ = new Subject<void>(); // Optional, für separate Page Rotation
|
||||
|
||||
// Feste Kachelgrößen (entsprechend den CSS-Einstellungen)
|
||||
private readonly tileWidth: number = 450; // in px
|
||||
private readonly tileHeight: number = 100; // in px
|
||||
private readonly gutter: number = 0; // Abstand zwischen den Kacheln in px
|
||||
private readonly containerPadding: number = 0; // Innenabstand des Grid-Containers in px
|
||||
public fontSettings: {textAlign: string}[] = [];
|
||||
private toggleDivInterval: any;
|
||||
showFirstDiv: boolean = true;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private avisoService: AvisoService,
|
||||
private toastController: ToastController,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private sanitizer: DomSanitizer
|
||||
) { }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sanitizes HTML, extracts font size and text align from span elements,
|
||||
* and stores them in dataset attributes and the fontSettings array.
|
||||
* @param html Das zu sanitizende HTML
|
||||
* @param index Index der Einstellung zur Zuordnung der Stilinformationen
|
||||
* @returns Sanitized HTML als SafeHtml
|
||||
*/
|
||||
sanitizeHtml(html: string, index: number): SafeHtml {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, 'text/html');
|
||||
const spans = doc.querySelectorAll('div');
|
||||
|
||||
spans.forEach(span => {
|
||||
const fontSize = span.style.fontSize;
|
||||
|
||||
if (fontSize) {
|
||||
|
||||
let fontSizePx: number;
|
||||
if (fontSize.endsWith('pt')) {
|
||||
fontSizePx = parseFloat(fontSize) * 1.333; // Umrechnung von pt zu px
|
||||
} else if (fontSize.endsWith('px')) {
|
||||
fontSizePx = parseFloat(fontSize);
|
||||
} else {
|
||||
// Andere Einheiten oder Standardfall
|
||||
fontSizePx = parseFloat(fontSize);
|
||||
}
|
||||
|
||||
const textAlign = span.style.textAlign || 'left';
|
||||
|
||||
// Speichern der ursprünglichen Schriftgröße und Textausrichtung
|
||||
this.fontSettings[index] = {
|
||||
textAlign: textAlign
|
||||
};
|
||||
|
||||
// Speichern in dataset
|
||||
span.dataset['originalFontSizePx'] = fontSizePx.toString();
|
||||
span.dataset['originalTextAlign'] = textAlign;
|
||||
|
||||
// Debugging: Loggen der ursprünglichen Schriftgröße
|
||||
console.log(`Original Font Size for span: "${span.textContent}" = ${fontSizePx}px`);
|
||||
} else {
|
||||
// Falls keine Schriftgröße definiert ist
|
||||
console.log(`No inline font size found for span: "${span.textContent}"`);
|
||||
}
|
||||
|
||||
// Entfernen der Inline-Schriftgröße
|
||||
span.style.fontSize = '';
|
||||
|
||||
// Hinzufügen der Klasse für die dynamische Anpassung
|
||||
span.classList.add('dynamic-font-size');
|
||||
});
|
||||
|
||||
// Debugging: Loggen des bearbeiteten HTML
|
||||
console.log('Processed HTML:', doc.body.innerHTML);
|
||||
|
||||
return this.sanitizer.bypassSecurityTrustHtml(doc.body.innerHTML);
|
||||
}
|
||||
|
||||
getTextAlign(index: number): string {
|
||||
const settings = this.fontSettings[index];
|
||||
return settings ? settings.textAlign : 'left';
|
||||
}
|
||||
|
||||
|
||||
ngOnInit() {
|
||||
this.route.queryParams.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||
this.standort = params['standort'] || 'SUB';
|
||||
this.seiten = params['seiten'] === 'true' || false;
|
||||
this.onlyOK = params['onlyOK'] === 'true' || false;
|
||||
|
||||
// Initiales Laden der Daten
|
||||
this.loadArrivals();
|
||||
this.loadAvisoTvSettings();
|
||||
this.startDivToggle();
|
||||
|
||||
});
|
||||
|
||||
interval(1000000) // 10000 Millisekunden = 10 Sekunden
|
||||
.pipe(
|
||||
startWith(0), // Sofortiger Start ohne Warten
|
||||
switchMap(() => {
|
||||
// Nur den Ladeindikator anzeigen, wenn keine Daten vorhanden sind
|
||||
this.loadingArrivals = this.arrivals.length === 0;
|
||||
this.errorMessage = '';
|
||||
return this.avisoService.getArrivals(this.standort, this.seiten, this.onlyOK);
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe(
|
||||
(data: AvisoArrivalsResponse) => { // Typisierung der empfangenen Daten
|
||||
console.log('Received arrivals data:', data); // Zum Debuggen
|
||||
this.arrivals = data.avisos;
|
||||
this.totalArrivals = data.totalCount;
|
||||
this.loadingArrivals = false;
|
||||
this.paginateArrivals();
|
||||
this.cdr.detectChanges(); // Manuelle Change Detection
|
||||
},
|
||||
(error) => {
|
||||
console.error('Fehler beim Laden der Arrivals:', error);
|
||||
this.presentToast(`Fehler beim Laden der Arrivals: ${error}`);
|
||||
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.';
|
||||
this.loadingArrivals = false;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Automatisches Aktualisieren der TV-Einstellungen alle 10 Sekunden
|
||||
interval(1000000) // 10000 Millisekunden = 10 Sekunden
|
||||
.pipe(
|
||||
startWith(0),
|
||||
switchMap(() => {
|
||||
this.loadingSettings = this.avisoTvSettings.length === 0;
|
||||
this.settingsErrorMessage = '';
|
||||
return this.avisoService.getAvisoTvSettings(this.standort);
|
||||
}),
|
||||
takeUntil(this.destroy$)
|
||||
)
|
||||
.subscribe(
|
||||
(data: AvisoTvSettingsDto[]) => { // Typisierung als Array
|
||||
console.log('Received TV settings data:', data);
|
||||
this.avisoTvSettings = data;
|
||||
this.totalSettings = data.length; // Setze totalSettings auf die Länge des Arrays
|
||||
this.loadingSettings = false;
|
||||
this.cdr.detectChanges(); // Manuelle Change Detection
|
||||
|
||||
// Debugging: Überprüfe jede Einstellung
|
||||
this.avisoTvSettings.forEach(setting => {
|
||||
console.log(`Setting ID: ${setting.tvTextBezeichnungID}, isActive: ${setting.isActive}, position: ${setting.position}, fixeZeile1: ${setting.fixeZeile1}`);
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
console.error('Fehler beim Laden der TV Settings:', error);
|
||||
this.presentToast(`Fehler beim Laden der TV Settings: ${error}`);
|
||||
this.settingsErrorMessage = 'Fehler beim Laden der TV Settings. Bitte versuche es später erneut.';
|
||||
this.loadingSettings = false;
|
||||
}
|
||||
);
|
||||
|
||||
// Starte die Page Rotation einmal nach dem Initialen Laden
|
||||
// Optional: Falls du separate Subjects für Page Rotation verwendest
|
||||
// this.startPageRotation();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// Beenden aller Subscriptions, um Speicherlecks zu vermeiden
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
|
||||
// Beende auch die Page Rotation Subscription, falls du separate Subjects verwendest
|
||||
// this.pageRotation$.next();
|
||||
// this.pageRotation$.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt die Ankünfte (Arrivals) von der API.
|
||||
*/
|
||||
loadArrivals() {
|
||||
this.loadingArrivals = true;
|
||||
this.avisoService
|
||||
.getArrivals(this.standort, this.seiten, this.onlyOK)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
(data: AvisoArrivalsResponse) => {
|
||||
console.log('Received arrivals data:', data);
|
||||
this.arrivals = data.avisos;
|
||||
this.totalArrivals = data.totalCount;
|
||||
this.loadingArrivals = false;
|
||||
this.paginateArrivals();
|
||||
this.cdr.detectChanges();
|
||||
},
|
||||
(error) => {
|
||||
console.error('Fehler beim Laden der Arrivals:', error);
|
||||
this.presentToast(`Fehler beim Laden der Arrivals: ${error}`);
|
||||
this.errorMessage = 'Fehler beim Laden der Arrivals. Bitte versuche es später erneut.';
|
||||
this.loadingArrivals = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt die Aviso TV Einstellungen von der API.
|
||||
*/
|
||||
loadAvisoTvSettings() {
|
||||
this.loadingSettings = true;
|
||||
this.avisoService
|
||||
.getAvisoTvSettings(this.standort)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(
|
||||
(data: AvisoTvSettingsDto[]) => { // Typisierung als Array
|
||||
console.log('Received TV settings data:', data); // Zum Debuggen
|
||||
this.avisoTvSettings = data;
|
||||
this.totalSettings = data.length; // Setze totalSettings auf die Länge des Arrays
|
||||
this.loadingSettings = false;
|
||||
this.cdr.detectChanges(); // Manuelle Change Detection
|
||||
showFirstDiv: true // Initialisiere alle auf true
|
||||
|
||||
// Debugging: Überprüfe jede Einstellung
|
||||
this.avisoTvSettings.forEach(setting => {
|
||||
console.log(`Setting ID: ${setting.tvTextBezeichnungID}, isActive: ${setting.isActive}, position: ${setting.position}, fixeZeile1: ${setting.fixeZeile1}`);
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
console.error('Fehler beim Laden der TV Settings:', error);
|
||||
this.presentToast(`Fehler beim Laden der TV Settings: ${error}`);
|
||||
this.settingsErrorMessage = 'Fehler beim Laden der TV Settings. Bitte versuche es später erneut.';
|
||||
this.loadingSettings = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
startDivToggle() {
|
||||
this.toggleDivInterval = setInterval(() => {
|
||||
this.showFirstDiv = !this.showFirstDiv;
|
||||
this.cdr.detectChanges(); // Manuelle Change Detection, falls nötig
|
||||
}, 5000); // 5000 Millisekunden = 5 Sekunden
|
||||
}
|
||||
/**
|
||||
* Lädt Arrivals und TV-Einstellungen basierend auf aktuellen Filtern.
|
||||
*/
|
||||
applyFilters() {
|
||||
this.loadArrivals();
|
||||
this.loadAvisoTvSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt eine Toast-Nachricht an.
|
||||
* @param message Die Nachricht, die angezeigt werden soll.
|
||||
*/
|
||||
async presentToast(message: string) {
|
||||
const toast = await this.toastController.create({
|
||||
message: message,
|
||||
duration: 3000,
|
||||
position: 'bottom',
|
||||
});
|
||||
toast.present();
|
||||
}
|
||||
|
||||
// Methoden zur Bestimmung von Statusklassen und -farben
|
||||
getStatusClass(status: number): string {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return 'statusLKW_Erfasst';
|
||||
case 1:
|
||||
return 'statusLKW_Freigegeben';
|
||||
case 2:
|
||||
return 'statusLKW_LKW_neu';
|
||||
case 3:
|
||||
return 'statusLKW_Ankunft';
|
||||
case 4:
|
||||
return 'statusLKW_Vorbereitet';
|
||||
case 5:
|
||||
return 'statusLKW_Vorgeschrieben';
|
||||
default:
|
||||
return 'status-default';
|
||||
}
|
||||
}
|
||||
|
||||
getStatusIcon(status: number): string {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return 'checkmark-circle'; // Erfasst
|
||||
case 1:
|
||||
return 'checkmark-circle'; // Freigegeben
|
||||
case 2:
|
||||
return 'help-circle'; // LKW n.e.
|
||||
case 3:
|
||||
return 'time'; // Ankunft
|
||||
case 4:
|
||||
return 'construct'; // Vorbereitet
|
||||
case 5:
|
||||
return 'bookmarks'; // Vorgeschrieben
|
||||
default:
|
||||
return 'help-circle'; // Unbekannt
|
||||
}
|
||||
}
|
||||
|
||||
getStatusColor(status: number): string {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return 'success'; // Erfasst - Grün
|
||||
case 1:
|
||||
return 'primary'; // Freigegeben - Blau
|
||||
case 2:
|
||||
return 'warning'; // LKW n.e. - Gelb/Orange
|
||||
case 3:
|
||||
return 'warning'; // Ankunft - Gelb/Orange
|
||||
case 4:
|
||||
return 'secondary'; // Vorbereitet - Grau
|
||||
case 5:
|
||||
return 'tertiary'; // Vorgeschrieben - Violett
|
||||
default:
|
||||
return 'medium'; // Unbekannt - Grau
|
||||
}
|
||||
}
|
||||
|
||||
getStatusText(status: number): string {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return 'Erfasst';
|
||||
case 1:
|
||||
return 'Freigegeben';
|
||||
case 2:
|
||||
return 'LKW n.e.';
|
||||
case 3:
|
||||
return 'Ankunft';
|
||||
case 4:
|
||||
return 'Vorbereitet';
|
||||
case 5:
|
||||
return 'Vorgeschrieben';
|
||||
default:
|
||||
return 'Unbekannt';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die CSS-Klasse basierend auf dem Position-Wert zurück.
|
||||
* @param position Die Position (Top, Middle, Left, Right)
|
||||
* @returns Eine CSS-Klassen-String
|
||||
*/
|
||||
getPositionClass(position: string): string {
|
||||
const pos = position.toLowerCase(); // Konvertiere zu Kleinbuchstaben
|
||||
switch (pos) {
|
||||
case 'top':
|
||||
return 'position-top';
|
||||
case 'middle':
|
||||
return 'position-middle';
|
||||
case 'left':
|
||||
return 'position-left';
|
||||
case 'right':
|
||||
return 'position-right';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// Paginierung der Arrivals
|
||||
paginateArrivals() {
|
||||
// Berechnung der verfügbaren Breite und Höhe
|
||||
const windowWidth = window.innerWidth;
|
||||
const windowHeight = window.innerHeight;
|
||||
// Definiere die Prozentsätze für Layout-Parameter
|
||||
const titleHeightPercent = 5; // z.B. 10% der Fensterhöhe
|
||||
const htmltextPercent = this.totalArrivals > 0 ? 30 : 0;
|
||||
|
||||
const containerPaddingPercent = 0; // z.B. 5% der Fensterbreite
|
||||
const gutterPercent = 1;
|
||||
const tileWidthPercent = 15; // z.B. 20% der Fensterbreite
|
||||
const tileHeightPercent = 23; // z.B. 25% der Fensterhöhe
|
||||
|
||||
|
||||
|
||||
const containerPadding = (containerPaddingPercent / 100) * windowWidth;
|
||||
const gutter = (gutterPercent / 100) * windowWidth;
|
||||
const tileWidth = (tileWidthPercent / 100) * windowWidth;
|
||||
const tileHeight = (tileHeightPercent / 100) * windowHeight;
|
||||
|
||||
// Berechnung der verfügbaren Breite für die Kacheln
|
||||
const containerPaddingTotal = containerPadding * 2; // Links und rechts
|
||||
const columns = Math.floor((windowWidth - containerPaddingTotal + gutter) / (tileWidth + gutter));
|
||||
|
||||
// Berechnung der verfügbaren Höhe für die Kacheln
|
||||
const titleHeight = (titleHeightPercent / 100) * windowHeight;
|
||||
let htmltext = 0;
|
||||
if (this.totalArrivals > 0) {
|
||||
htmltext = (htmltextPercent / 100) * windowHeight;
|
||||
}
|
||||
|
||||
const availableHeightForTiles = windowHeight - htmltext - titleHeight - containerPadding * 2 - gutter * (columns > 1 ? columns : 0);
|
||||
|
||||
// Berechnung der maximal möglichen Kacheln pro Spalte
|
||||
const rows = Math.floor((availableHeightForTiles + gutter) / (tileHeight + gutter));
|
||||
|
||||
// Berechnung der Kacheln pro Seite
|
||||
this.tilesPerPage = columns * rows;
|
||||
|
||||
// Sicherstellen, dass mindestens eine Kachel pro Seite angezeigt wird
|
||||
this.tilesPerPage = this.tilesPerPage > 0 ? this.tilesPerPage : 1;
|
||||
|
||||
console.log('Columns:', columns);
|
||||
console.log('Rows:', rows);
|
||||
console.log('Tiles per Page:', this.tilesPerPage);
|
||||
|
||||
// Aufteilung der Arrivals in Seiten
|
||||
this.pages = [];
|
||||
for (let i = 0; i < this.arrivals.length; i += this.tilesPerPage) {
|
||||
this.pages.push(this.arrivals.slice(i, i + this.tilesPerPage));
|
||||
}
|
||||
|
||||
// Reset der aktuellen Seite, wenn nötig
|
||||
if (this.currentPageIndex >= this.pages.length) {
|
||||
this.currentPageIndex = 0;
|
||||
}
|
||||
|
||||
console.log('Total Pages:', this.pages.length);
|
||||
}
|
||||
|
||||
// Automatisches Wechseln der Seiten alle 10 Sekunden
|
||||
startPageRotation() {
|
||||
interval(10000) // 10000 Millisekunden = 10 Sekunden
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
if (this.pages.length > 0) {
|
||||
this.currentPageIndex = (this.currentPageIndex + 1) % this.pages.length;
|
||||
console.log('Wechsel zu Seite:', this.currentPageIndex + 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Listener für Fenstergrößenänderungen, um die Paginierung anzupassen
|
||||
*/
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event: Event) {
|
||||
this.paginateArrivals();
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,13 @@ import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { HomePage } from './home.page';
|
||||
import { HomePageRoutingModule } from './home-routing.module';
|
||||
import { MessageComponentModule } from '../message/message.module';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
MessageComponentModule,
|
||||
HomePageRoutingModule
|
||||
],
|
||||
declarations: [HomePage]
|
||||
0
src/app/pages/home/home.page.html
Normal file
0
src/app/pages/home/home.page.html
Normal file
0
src/app/pages/home/home.page.scss
Normal file
0
src/app/pages/home/home.page.scss
Normal file
15
src/app/pages/home/home.page.ts
Normal file
15
src/app/pages/home/home.page.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { RefresherCustomEvent } from '@ionic/angular';
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: 'home.page.html',
|
||||
styleUrls: ['home.page.scss'],
|
||||
})
|
||||
export class HomePage {
|
||||
constructor() {}
|
||||
|
||||
|
||||
}
|
||||
24
src/app/services/aviso-tv-settings.dto.ts
Normal file
24
src/app/services/aviso-tv-settings.dto.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export interface AvisoTvSettingsDto {
|
||||
tvTextBezeichnungID: number;
|
||||
standortID: number;
|
||||
tvTextBezeichnung: string;
|
||||
standort: string;
|
||||
position: string;
|
||||
fixeZeile1?: string;
|
||||
fixeZeile2?: string;
|
||||
fixeZeile3?: string;
|
||||
art?: string;
|
||||
startDate?: string | null;
|
||||
endDate?: string | null;
|
||||
startTime?: string | null;
|
||||
endTime?: string | null;
|
||||
isRecurring: boolean;
|
||||
isMonday: boolean;
|
||||
isTuesday: boolean;
|
||||
isWednesday: boolean;
|
||||
isThursday: boolean;
|
||||
isFriday: boolean;
|
||||
isSaturday: boolean;
|
||||
isSunday: boolean;
|
||||
isActive: boolean;
|
||||
}
|
||||
13
src/app/services/aviso.dto.ts
Normal file
13
src/app/services/aviso.dto.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export interface AvisoDto {
|
||||
avisoID: number;
|
||||
status: number;
|
||||
lkW_Nr: string;
|
||||
ankunft: string | null;
|
||||
dauer: string;
|
||||
letzterMitarbeiter: string;
|
||||
weiterleitungTextTV: string;
|
||||
imEx: string;
|
||||
zollDigitalEingereicht: boolean;
|
||||
buero: string;
|
||||
avisoTVHinweis: string;
|
||||
}
|
||||
88
src/app/services/aviso.service.ts
Normal file
88
src/app/services/aviso.service.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
import { AvisoDto } from './aviso.dto'; // Importiere das Interface
|
||||
import { AvisoTvSettingsDto } from './aviso-tv-settings.dto'; // Importiere das neue Interface
|
||||
|
||||
// Definiere die Response Interfaces
|
||||
export interface AvisoArrivalsResponse {
|
||||
avisos: AvisoDto[];
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AvisoService {
|
||||
|
||||
private baseUrl = 'https://localhost:7063/api/Aviso';
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
/**
|
||||
* Holt die Ankünfte (Arrivals) basierend auf den übergebenen Parametern.
|
||||
* @param standort Standort zur Filterung der Ankünfte.
|
||||
* @param seiten Gibt an, ob nur Seiten zurückgegeben werden sollen.
|
||||
* @param onlyOK Gibt an, ob nur gültige Ankünfte zurückgegeben werden sollen.
|
||||
* @returns Ein Observable von AvisoArrivalsResponse.
|
||||
*/
|
||||
getArrivals(standort: string, seiten: boolean = false, onlyOK: boolean = false): Observable<AvisoArrivalsResponse> {
|
||||
let params = new HttpParams()
|
||||
.set('standort', standort)
|
||||
.set('seiten', seiten.toString())
|
||||
.set('onlyOK', onlyOK.toString());
|
||||
|
||||
return this.http.get<AvisoArrivalsResponse>(`${this.baseUrl}/arrivals`, { params })
|
||||
.pipe(
|
||||
tap(data => console.log('AvisoService received arrivals data:', data)), // Logge die empfangenen Daten
|
||||
catchError(this.handleError)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt die Aviso TV Einstellungen basierend auf dem übergebenen Standort.
|
||||
* @param standort Standort zur Filterung der Einstellungen.
|
||||
* @returns Ein Observable von AvisoTvSettingsDto[].
|
||||
*/
|
||||
getAvisoTvSettings(standort: string): Observable<AvisoTvSettingsDto[]> {
|
||||
return this.http.get<AvisoTvSettingsDto[]>(`${this.baseUrl}/${standort}`)
|
||||
.pipe(
|
||||
tap(data => console.log('AvisoService received TV settings data:', data)), // Logge die empfangenen Daten
|
||||
catchError(this.handleError)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holt die bereitstehenden Avisos basierend auf dem übergebenen Standort.
|
||||
* @param standort Standort zur Filterung der bereitstehenden Avisos.
|
||||
* @returns Ein Observable von AvisoDto[].
|
||||
*/
|
||||
getReadyAvisos(standort: string = ''): Observable<AvisoDto[]> {
|
||||
let params = new HttpParams().set('standort', standort);
|
||||
return this.http.get<AvisoDto[]>(`${this.baseUrl}/ready`, { params })
|
||||
.pipe(
|
||||
tap(data => console.log('AvisoService received ready avisos:', data)), // Logge die empfangenen Daten
|
||||
catchError(this.handleError)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Behandelt Fehler, die während HTTP-Anfragen auftreten.
|
||||
* @param error Das aufgetretene HttpErrorResponse-Objekt.
|
||||
* @returns Ein Observable, das einen Fehler auswirft.
|
||||
*/
|
||||
private handleError(error: HttpErrorResponse) {
|
||||
let errorMessage = 'Unbekannter Fehler!';
|
||||
if (error.error instanceof ErrorEvent) {
|
||||
// Client-seitiger Fehler
|
||||
errorMessage = `Fehler: ${error.error.message}`;
|
||||
} else {
|
||||
// Server-seitiger Fehler
|
||||
errorMessage = `Server returned code: ${error.status}, error message is: ${error.message}`;
|
||||
}
|
||||
return throwError(errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DataService } from './data.service';
|
||||
|
||||
describe('DataService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
|
||||
it('should be created', () => {
|
||||
const service: DataService = TestBed.get(DataService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
export interface Message {
|
||||
fromName: string;
|
||||
subject: string;
|
||||
date: string;
|
||||
id: number;
|
||||
read: boolean;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DataService {
|
||||
public messages: Message[] = [
|
||||
{
|
||||
fromName: 'Matt Chorsey',
|
||||
subject: 'New event: Trip to Vegas',
|
||||
date: '9:32 AM',
|
||||
id: 0,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Lauren Ruthford',
|
||||
subject: 'Long time no chat',
|
||||
date: '6:12 AM',
|
||||
id: 1,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Jordan Firth',
|
||||
subject: 'Report Results',
|
||||
date: '4:55 AM',
|
||||
id: 2,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Bill Thomas',
|
||||
subject: 'The situation',
|
||||
date: 'Yesterday',
|
||||
id: 3,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Joanne Pollan',
|
||||
subject: 'Updated invitation: Swim lessons',
|
||||
date: 'Yesterday',
|
||||
id: 4,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Andrea Cornerston',
|
||||
subject: 'Last minute ask',
|
||||
date: 'Yesterday',
|
||||
id: 5,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Moe Chamont',
|
||||
subject: 'Family Calendar - Version 1',
|
||||
date: 'Last Week',
|
||||
id: 6,
|
||||
read: false
|
||||
},
|
||||
{
|
||||
fromName: 'Kelly Richardson',
|
||||
subject: 'Placeholder Headhots',
|
||||
date: 'Last Week',
|
||||
id: 7,
|
||||
read: false
|
||||
}
|
||||
];
|
||||
|
||||
constructor() { }
|
||||
|
||||
public getMessages(): Message[] {
|
||||
return this.messages;
|
||||
}
|
||||
|
||||
public getMessageById(id: number): Message {
|
||||
return this.messages[id];
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ViewMessagePage } from './view-message.page';
|
||||
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { ViewMessagePageRoutingModule } from './view-message-routing.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
ViewMessagePageRoutingModule
|
||||
],
|
||||
declarations: [ViewMessagePage]
|
||||
})
|
||||
export class ViewMessagePageModule {}
|
||||
@@ -1,29 +0,0 @@
|
||||
<ion-header [translucent]="true">
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button [text]="getBackButtonText()" defaultHref="/"></ion-back-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content [fullscreen]="true" *ngIf="message">
|
||||
<ion-item>
|
||||
<ion-icon aria-hidden="true" name="person-circle" color="primary"></ion-icon>
|
||||
<ion-label class="ion-text-wrap">
|
||||
<h2>
|
||||
{{ message.fromName }}
|
||||
<span class="date">
|
||||
<ion-note>{{ message.date }}</ion-note>
|
||||
</span>
|
||||
</h2>
|
||||
<h3>To: <ion-note>Me</ion-note></h3>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
||||
<div class="ion-padding">
|
||||
<h1>{{ message.subject }}</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
</div>
|
||||
</ion-content>
|
||||
@@ -1,50 +0,0 @@
|
||||
ion-item {
|
||||
--inner-padding-end: 0;
|
||||
--background: transparent;
|
||||
}
|
||||
|
||||
ion-label {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
ion-item h2 {
|
||||
font-weight: 600;
|
||||
|
||||
/**
|
||||
* With larger font scales
|
||||
* the date/time should wrap to the next
|
||||
* line. However, there should be
|
||||
* space between the name and the date/time
|
||||
* if they can appear on the same line.
|
||||
*/
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
ion-item .date {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
ion-item ion-icon {
|
||||
font-size: 42px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
ion-item ion-note {
|
||||
font-size: 0.9375rem;
|
||||
margin-right: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.4;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { ViewMessagePageRoutingModule } from './view-message-routing.module';
|
||||
import { ViewMessagePage } from './view-message.page';
|
||||
|
||||
describe('ViewMessagePage', () => {
|
||||
let component: ViewMessagePage;
|
||||
let fixture: ComponentFixture<ViewMessagePage>;
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ViewMessagePage],
|
||||
imports: [IonicModule.forRoot(), ViewMessagePageRoutingModule, RouterModule.forRoot([])]
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ViewMessagePage);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, inject, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { IonicModule, Platform } from '@ionic/angular';
|
||||
import { DataService, Message } from '../services/data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-view-message',
|
||||
templateUrl: './view-message.page.html',
|
||||
styleUrls: ['./view-message.page.scss'],
|
||||
})
|
||||
export class ViewMessagePage implements OnInit {
|
||||
public message!: Message;
|
||||
private data = inject(DataService);
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private platform = inject(Platform);
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {
|
||||
const id = this.activatedRoute.snapshot.paramMap.get('id') as string;
|
||||
this.message = this.data.getMessageById(parseInt(id, 10));
|
||||
}
|
||||
|
||||
getBackButtonText() {
|
||||
const isIos = this.platform.is('ios')
|
||||
return isIos ? 'Inbox' : '';
|
||||
}
|
||||
}
|
||||
1480
verag.njsproj
Normal file
1480
verag.njsproj
Normal file
File diff suppressed because it is too large
Load Diff
6
verag.njsproj.user
Normal file
6
verag.njsproj.user
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
1481
verage.njsproj
Normal file
1481
verage.njsproj
Normal file
File diff suppressed because it is too large
Load Diff
9
verage.njsproj.user
Normal file
9
verage.njsproj.user
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PromptedToMigrateToJsps />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user