Commit 8fecb5fa authored by Léonard Treille's avatar Léonard Treille
Browse files

End init from pwa

parent b01b3e71
import { NgModule, Component } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LinesResolver } from 'src/app/features/lines/lines.resolver';
import { HorairesLignesComponent } from '@pages/horaires-lignes/horaires-lignes.component';
import { DetailLigneComponent } from '@pages/detail-ligne/detail-ligne.component';
import { LinesResolver } from '@features/lines/lines.resolver';
import { LineResolver } from '@features/line/line.resolver';
const routes: Routes = [
{
......@@ -10,17 +12,16 @@ const routes: Routes = [
lines: LinesResolver
}
},
// {
// path: 'detailligne/:id', component: DetailLigneComponent, data: {
// title: 'detail de la ligne ',
// description: 'Accedez à plus de details sur votre ligne',
// topButtonWithoutToolbar: true
// },
// },
{
path: 'ligne/:id', component: DetailLigneComponent,
resolve: {
clusters: LineResolver
}
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
exports: [RouterModule]
})
export class AppRoutingModule { }
......@@ -2,17 +2,39 @@ import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { MatCardModule } from '@angular/material/card';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatListModule } from '@angular/material/list';
import { MatDialogModule } from '@angular/material/dialog';
import { MatButtonModule } from '@angular/material/button';
import { MatRippleModule } from '@angular/material/core';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { WINDOW_PROVIDERS } from './window.provider';
import { HorairesLignesComponent } from '@pages/horaires-lignes/horaires-lignes.component';
import { DetailLigneComponent } from '@pages/detail-ligne/detail-ligne.component';
import { LogoLigneComponent } from '@components/logo-ligne/logo-ligne.component';
import { DetailProchainspassagesComponent } from '@components/detail-prochainspassages/detail-prochainspassages.component';
import { DialogRecherchePointComponent } from '@components/dialog-recherche-point/dialog-recherche-point.component';
import { RecherchePointComponent } from '@components/recherche-point/recherche-point.component';
import { MListWrapperComponent } from '@components/m-list-wrapper/m-list-wrapper.component';
import { IconTypeComponent } from '@components/icon-type/icon-type.component';
import { RealtimeIconComponent } from '@components/realtime-icon/realtime-icon.component';
import { SearchDialogDirective } from '@directives/search-dialog.directive';
import { GroupByPipe } from '@pipes/groupBy.pipe';
import { CommunePipe } from '@pipes/commune.pipe';
import { LibellePipe } from '@pipes/libelle.pipe';
import { FilterPipe } from '@pipes/filter.pipe';
import { TimePipe, TimeUnitPipe, TimeSchedulePipe } from '@pipes/time.pipe';
@NgModule({
declarations: [
......@@ -20,15 +42,43 @@ import { GroupByPipe } from '@pipes/groupBy.pipe';
HorairesLignesComponent,
LogoLigneComponent,
GroupByPipe,
SearchDialogDirective,
DialogRecherchePointComponent,
RecherchePointComponent,
MListWrapperComponent,
IconTypeComponent,
CommunePipe,
LibellePipe,
DetailLigneComponent,
FilterPipe,
DetailProchainspassagesComponent,
RealtimeIconComponent,
TimePipe,
TimeUnitPipe,
TimeSchedulePipe,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
HttpClientModule,
MatCardModule,
MatSidenavModule,
MatIconModule,
MatProgressSpinnerModule,
MatListModule,
MatDialogModule,
MatButtonModule,
MatRippleModule,
MatExpansionModule,
MatFormFieldModule,
MatInputModule,
MatProgressBarModule,
],
entryComponents: [
DialogRecherchePointComponent
],
providers: [WINDOW_PROVIDERS],
bootstrap: [AppComponent]
......
<ng-template #times let-obj="obj">
<span class="time-wrapper">
<span class="divider vertical right">
<span class="layout column">
<span class="time-value-wrapper">
<app-realtime-icon *ngIf="obj.time[0]?.realtime"></app-realtime-icon>
<b>{{ obj.time[0] | time }}</b>
</span>
<span class="text-secondary">{{ obj.time[0] | timeUnit }}</span>
</span>
</span>
<span>
<span class="layout column">
<span class="time-value-wrapper text-secondary">
<app-realtime-icon *ngIf="obj.time[1]?.realtime"></app-realtime-icon>
<b>{{ obj.time[1] | time }}</b>
</span>
<span class="text-secondary">{{ obj.time[1] | timeUnit }}</span>
</span>
</span>
</span>
</ng-template>
<ng-template #time let-obj="obj">
<span class="layout align-center">
<span class="time-spacing">
<app-realtime-icon class="real-time" *ngIf="obj.time[0]?.realtime"></app-realtime-icon>
<b>{{ obj.time[0] | time }}</b>
</span>
<span><b>{{ obj.time[0] | timeUnit }}</b></span>
</span>
</ng-template>
<ng-template #expansionPanel let-obj="obj" let-logo="logo">
<mat-panel-title class="layout align-center">
<span [ngStyle]="{'background-color':'#'+obj.ligne?.color}" *ngIf="logo">
<app-logo-ligne [ligne]="obj.ligne" [height]="73" width="56"></app-logo-ligne>
</span>
<span class="flex">
<span class="m-multiline">
<span class="layout">
<mat-icon class="small-icon" *ngIf="logo && obj.ligne.mode === 'TRAM'">tram</mat-icon>
<mat-icon class="small-icon" *ngIf="logo && obj.ligne.mode === 'BUS'">directions_bus</mat-icon>
<span class="flex">
<span class="ellipsis">{{ obj.name }}</span>
</span>
</span>
<span *ngIf="obj.city" class="ellipsis">{{ obj.city }}</span>
</span>
</span>
<ng-container *ngTemplateOutlet="times; context: { obj: obj }"></ng-container>
</mat-panel-title>
</ng-template>
<ng-template #listItem let-obj="obj" let-logo="logo">
<span class="layout align-center full-width">
<span [ngStyle]="{'background-color':'#'+obj.ligne?.color}" *ngIf="logo">
<app-logo-ligne [ligne]="obj.ligne" [height]="73" width="56"></app-logo-ligne>
</span>
<span class="flex layout align-center">
<mat-icon class="small-icon" *ngIf="logo && obj.ligne.mode === 'TRAM'">tram</mat-icon>
<mat-icon class="small-icon" *ngIf="logo && obj.ligne.mode === 'BUS'">directions_bus</mat-icon>
<span class="flex">
<span class="ellipsis item-name">{{ obj.name }}</span>
</span>
</span>
<ng-container *ngTemplateOutlet="times; context: { obj: obj }"></ng-container>
</span>
</ng-template>
<ng-template #unavailableLabel>
Données indisponible
</ng-template>
<mat-progress-bar *ngIf="prochPassages.length === 0 && !unavailable" mode="indeterminate"></mat-progress-bar>
<ng-container *ngIf="prochPassages.length > 0 || ['compact', 'compact-unique'].includes(mode)">
<ng-container *ngIf="mode === 'default'">
<mat-accordion class="m-theme m-list important">
<mat-expansion-panel *ngFor="let obj of prochPassages" class="content-no-spacing dark-overlay-8" #panel="matExpansionPanel">
<mat-expansion-panel-header class="no-indicator no-padding" collapsedHeight="73px" expandedHeight="73px">
<ng-container *ngTemplateOutlet="expansionPanel; context: {obj: obj, logo: showLogo}"></ng-container>
</mat-expansion-panel-header>
</mat-expansion-panel>
</mat-accordion>
</ng-container>
<ng-container *ngIf="mode === 'list-item'">
<mat-list class="no-padding--right">
<mat-list-item *ngFor="let obj of prochPassages">
<ng-container *ngTemplateOutlet="listItem; context: {obj: obj, logo: showLogo}"></ng-container>
</mat-list-item>
</mat-list>
</ng-container>
<ng-container *ngIf="mode === 'compact'">
<mat-list class="m-theme m-list important no-padding--left no-padding--right more-height">
<mat-list-item class="content-no-spacing dark-overlay-8 light-overlay" *ngFor="let line of lines">
<span class="layout full-width">
<span class="layout column content-center" [ngStyle]="{'background-color':'#'+ line?.color}">
<app-logo-ligne [ligne]="line" [height]="70" width="56"></app-logo-ligne>
</span>
<span class="full-width margin-lr layout column content-center text-secondary ellipsis">
<span class="layout column content-center full-height" *ngIf="prochPassagesCompact && prochPassagesCompact[line.id]">
<span class="layout space-between align-center no-padding--right" *ngFor="let obj of prochPassagesCompact[line.id].object">
<span class="ellipsis item-name">{{ obj.name}}</span>
<ng-container *ngTemplateOutlet="time; context: { obj: obj }"></ng-container>
</span>
</span>
<span *ngIf="unavailable" class="ellipsis full-height">
<span class="full-height layout align-center">
<span class="ellipsis">
<ng-container *ngTemplateOutlet="unavailableLabel"></ng-container>
</span>
</span>
</span>
</span>
</span>
</mat-list-item>
</mat-list>
</ng-container>
<ng-container *ngIf="mode === 'compact-unique'">
<span class="layout full-width no-padding">
<span [ngStyle]="{'background-color':'#'+ lines[0]?.color}">
<app-logo-ligne [ligne]="lines[0]" [height]="logoHeight || 44 + 16" width="56"></app-logo-ligne>
</span>
<span class="full-width margin-lr ellipsis">
<span class="m-multiline layout content-center full-height">
<span class="layout align-center">
<app-icon-type class="panel-icon" [type]="zoneArret.type"></app-icon-type>
<span class="ellipsis">{{ zoneArret.name}}</span>
</span>
<span class="layout column" *ngIf="displayTimes">
<span class="layout space-between no-padding--right align-center" *ngFor="let obj of prochPassages">
<span class="ellipsis item-name">{{ obj.name}}</span>
<ng-container *ngTemplateOutlet="time; context: { obj: obj }"></ng-container>
</span>
<span *ngIf="unavailable" class="ellipsis">
<ng-container *ngTemplateOutlet="unavailableLabel"></ng-container>
</span>
</span>
</span>
</span>
</span>
</ng-container>
</ng-container>
<div *ngIf="unavailable && zoneArret.type=='clusters' && !['compact', 'compact-unique'].includes(mode)">
<p class="no-results">
<ng-container *ngTemplateOutlet="unavailableLabel"></ng-container>
</p>
</div>
@import "../../../styles/variables";
:host {
display: block;
height: auto;
position: relative;
.mat-list-item-content {
padding-right: 0;
}
}
.mat-expansion-panel-header-title,
.mat-list-item {
min-width: 0;
> span:first-of-type {
margin-right: $spacing * 2;
}
.small-icon {
height: $default-fz;
width: $default-fz;
line-height: $default-fz;
font-size: $default-fz;
margin-right: $spacing;
}
}
.time-wrapper {
display: flex;
align-items: center;
text-align: center;
> span > span {
width: 42px;
}
@media screen and (min-width: 321px) {
> span {
padding: 0 $spacing;
}
}
}
.m-multiline {
> span + span {
margin-top: $spacing / 2;
}
}
.time-value-wrapper {
position: relative;
font-size: $mpwa-time-fz;
font-weight: bold;
line-height: $mpwa-time-fz;
+ span {
font-size: $mpwa-time-fz-next;
line-height: $mpwa-time-fz-next;
font-weight: normal;
}
}
.time-spacing {
padding: $spacing/2;
position: relative;
margin-left: 14px;
font-size: $mpwa-time-fz - 0.8rem;
+ span {
font-size: $mpwa-time-fz - 1rem;
}
.real-time {
top: 12px;
left: -4px;
}
}
.real-time {
top: 5px;
left: 1px;
}
app-realtime-icon {
width: 12px;
height: 12px;
position: absolute;
top: -5px;
left: 12px;
transform: translate(-50%, -50%) rotate(45deg);
}
.full-width {
width: 100%;
}
.full-height {
height: 100%;
}
.no-results {
display: flex;
justify-content: center;
padding: $spacing * 2;
margin: 0;
}
.mat-list-item {
.item-name {
font-size: $default-fz;
}
}
.margin-lr {
margin-left: $spacing * 2;
margin-right: $spacing * 2;
}
.margin-tb {
margin-top: $spacing * 2;
margin-bottom: $spacing * 2;
}
.margin-b {
margin-bottom: $spacing/2;
}
.mat-progress-bar {
position: absolute;
}
import { Component, Input, OnDestroy, OnInit, Output, EventEmitter } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { AppVisibilityService } from '@services/app-visibility.service';
import { groupByField } from '@helpers/array.helper';
import { RealtimeDataService } from '@features/realtime-data/realtime-data.service';
@Component({
selector: 'app-detail-prochainspassages',
templateUrl: './detail-prochainspassages.component.html',
styleUrls: ['./detail-prochainspassages.component.scss']
})
export class DetailProchainspassagesComponent implements OnInit, OnDestroy {
@Input() lines: any[];
@Input() avecAccordeon: any;
@Input() shouldBeUpdated = true;
@Input() showLogo = true;
@Input() mode: 'default' | 'list-item' | 'compact' | 'compact-unique' = 'default';
@Output() nbreLignes: EventEmitter<number> = new EventEmitter<number>();
@Input() logoHeight: number;
@Input() displayTimes = true;
prochPassages = [];
prochPassagesCompact = [];
displayedColumns: string[] = ['logo', 'desc', 'timeone', 'timetwo'];
expandedElement: any;
url;
unavailable = false;
private paused = false;
private _zoneArret: any;
intervalId;
@Input() set zoneArret(obj: any) {
this._zoneArret = obj;
this.prochPassages = [];
this.prochPassagesCompact = [];
this.chargeData();
if (this.intervalId) {
clearInterval(this.intervalId);
}
this.intervalId = setInterval(() => {
this.chargeData();
}, 20000);
}
get zoneArret() {
return this._zoneArret;
}
constructor(
private realtimeDataService: RealtimeDataService,
private appVisibilityService: AppVisibilityService,
public dialog: MatDialog
) { }
ngOnInit() {
this.appVisibilityService.visibility$.subscribe((visible) => {
if (!visible && this.intervalId) {
clearInterval(this.intervalId);
} else {
this.chargeData();
this.intervalId = setInterval(() => {
this.chargeData();
}, 20000);
}
});
}
chargeData() {
this.unavailable = false;
const lineIds = this.lines.map((line: any) => line.id) || [];
this.realtimeDataService.getStoptimes(this.zoneArret.type, this.zoneArret.code, lineIds).subscribe(res => {
const nbEltToDisplay = 2;
if (this.shouldBeUpdated) {
const passages = groupByField(this.realtimeDataService.parseResultPP(res, nbEltToDisplay), 'ligne.id');
// Add/Update objects instead of replace the entire list.
passages.forEach((passage: any) => {
const p = this.prochPassages.find((pp: any) => passage.id === pp.id);
if (!p) {
passage.opened = false;
this.prochPassages.push(passage);
} else {
p.time = passage.time;
}
});
// Remove old objects from the list.
this.prochPassages.forEach((pp, index) => {
if (!passages.find((p) => p.id === pp.id)) {
this.prochPassages.splice(index, 1);
}
});
if (this.prochPassages.length === 0) {
this.unavailable = true;
}
if (this.mode === 'compact-unique' && this.lines) {
this.prochPassages = this.prochPassages.filter(proch => {
return proch.ligne.id === this.lines[0].id;
});
this.nbreLignes.emit(this.unavailable ? -1 : this.prochPassages.length);
}
if (this.mode === 'compact' && this.prochPassages.length > 0) {
this.prochPassagesCompact = [];
this.prochPassages.forEach(el => {
if (!this.prochPassagesCompact[el.ligne.id]) {
this.prochPassagesCompact[el.ligne.id] = {
object: [el],
};
} else {
this.prochPassagesCompact[el.ligne.id].object.push(el);
}
});
}
}
}, (err) => this.unavailable = true);
}
ngOnDestroy() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
}
}
<app-recherche-point [idDialog]="myId" [state]="data"></app-recherche-point>
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({
selector: 'app-dialog-recherche-point',
templateUrl: './dialog-recherche-point.component.html'
})
export class DialogRecherchePointComponent implements OnInit {
myId: any;
constructor(
public dialogRef: MatDialogRef<DialogRecherchePointComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.myId = this.dialogRef.id;
}
ngOnInit() {
}
}
<div [ngSwitch]="type">
<mat-icon *ngSwitchCase="'arret'">directions_bus</mat-icon>
<mat-icon *ngSwitchCase="'clusters'" svgIcon="clusters"></mat-icon>
<mat-icon *ngSwitchCase="'stops'">nature_people</mat-icon>
<mat-icon *ngSwitchCase="'rue'">place</mat-icon>
<mat-icon *ngSwitchCase="'lieux'" svgIcon="lieux"></mat-icon>
<mat-icon *ngSwitchCase="'PAR'" svgIcon="PAR"></mat-icon>
<mat-icon *ngSwitchCase="'PKG'" svgIcon="PKG"></mat-icon>
<mat-icon *ngSwitchCase="'dat'">local_grocery_store</mat-icon>
<mat-icon *ngSwitchCase="'agenceM'" svgIcon="agenceM"></mat-icon>
<mat-icon *ngSwitchCase="'CAM'">videocam</mat-icon>
<mat-icon *ngSwitchCase="'iti'">directions</mat-icon>
<mat-icon *ngSwitchCase="'WALK'">directions_walk</mat-icon>
<mat-icon *ngSwitchCase="'BICYCLE'">directions_bike</mat-icon>
<mat-icon *ngSwitchCase="'CAR'">directions_car</mat-icon>
<mat-icon *ngSwitchCase="'TRAM'">directions_transit</mat-icon>
<mat-icon *ngSwitchCase="'BUS'">directions_bus</mat-icon>
<mat-icon *ngSwitchCase="'RAIL'">directions_railway</mat-icon>
<mat-icon *ngSwitchCase="'SUBWAY'">subway</mat-icon>
<mat-icon *ngSwitchCase="'recharge'" svgIcon="recharge"></mat-icon>
<mat-icon *ngSwitchCase="'autostop'" svgIcon="autostop"></mat-icon>
<mat-icon *ngSwitchCase="'citiz'" svgIcon="citiz"></mat-icon>
<mat-icon *ngSwitchCase="'citizyea'" svgIcon="citizyea"></mat-icon>
<mat-icon *ngSwitchCase="'parkingCov'" svgIcon="parkingCov"></mat-icon>
<mat-icon *ngSwitchCase="'pointCov'" svgIcon="pointCov"></mat-icon>
<mat-icon *ngSwitchCase="'pointService'" svgIcon="pointService"></mat-icon>
<mat-icon *ngSwitchCase="'depositaire'" svgIcon="depositaire"></mat-icon>
<mat-icon *ngSwitchCase="'MVA'" svgIcon="MVA"></mat-icon>
<mat-icon *ngSwitchCase="'MVC'" svgIcon="MVC"></mat-icon>
<mat-icon *ngSwitchCase="'gpl'" svgIcon="gpl"></mat-icon>
<mat-icon *ngSwitchCase="'gnv'" svgIcon="gnv"></mat-icon>