diff --git a/projects/speech-statistics/src/app/auth/edit/time-tracking/time-tracking.component.ts b/projects/speech-statistics/src/app/auth/edit/time-tracking/time-tracking.component.ts index 41fefaf..afc75e8 100644 --- a/projects/speech-statistics/src/app/auth/edit/time-tracking/time-tracking.component.ts +++ b/projects/speech-statistics/src/app/auth/edit/time-tracking/time-tracking.component.ts @@ -5,7 +5,7 @@ import {Observable, Subscription} from 'rxjs'; import {Faction} from '../../administration/factions/faction'; import {RecordingState} from './recording-state'; -import {SpeechType} from './speech-type'; +import {SpeechType} from '../../../shared/speech-type'; import {SpeechTimeService} from '../../shared/speech-time.service'; @Component({ diff --git a/projects/speech-statistics/src/app/auth/shared/speech-time.service.ts b/projects/speech-statistics/src/app/auth/shared/speech-time.service.ts index 239bade..aa34468 100644 --- a/projects/speech-statistics/src/app/auth/shared/speech-time.service.ts +++ b/projects/speech-statistics/src/app/auth/shared/speech-time.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import {AngularFireDatabase} from '@angular/fire/compat/database'; -import {SpeechType} from '../edit/time-tracking/speech-type'; -import {Speech} from '../edit/time-tracking/speech'; +import {SpeechType} from '../../shared/speech-type'; +import {Speech} from '../../shared/speech'; @Injectable({ providedIn: 'root' diff --git a/projects/speech-statistics/src/app/auth/edit/time-tracking/speech-type.ts b/projects/speech-statistics/src/app/shared/speech-type.ts similarity index 100% rename from projects/speech-statistics/src/app/auth/edit/time-tracking/speech-type.ts rename to projects/speech-statistics/src/app/shared/speech-type.ts diff --git a/projects/speech-statistics/src/app/auth/edit/time-tracking/speech.ts b/projects/speech-statistics/src/app/shared/speech.ts similarity index 100% rename from projects/speech-statistics/src/app/auth/edit/time-tracking/speech.ts rename to projects/speech-statistics/src/app/shared/speech.ts diff --git a/projects/speech-statistics/src/app/shared/to-minute-seconds.pipe.spec.ts b/projects/speech-statistics/src/app/shared/to-minute-seconds.pipe.spec.ts new file mode 100644 index 0000000..45ed1e6 --- /dev/null +++ b/projects/speech-statistics/src/app/shared/to-minute-seconds.pipe.spec.ts @@ -0,0 +1,8 @@ +import { ToMinuteSecondsPipe } from './to-minute-seconds.pipe'; + +describe('ToMinuteSecondsPipe', () => { + it('create an instance', () => { + const pipe = new ToMinuteSecondsPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/projects/speech-statistics/src/app/shared/to-minute-seconds.pipe.ts b/projects/speech-statistics/src/app/shared/to-minute-seconds.pipe.ts new file mode 100644 index 0000000..7fe7001 --- /dev/null +++ b/projects/speech-statistics/src/app/shared/to-minute-seconds.pipe.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'toMinuteSeconds' +}) +export class ToMinuteSecondsPipe implements PipeTransform { + + transform(value: number|undefined, ...args: unknown[]): string { + if (value == null) { + return ''; + } + const seconds = Math.floor(value / 1000); + const secondsLeft = seconds % 60; + const minutes = (seconds - secondsLeft) / 60; + return minutes + ':' + secondsLeft; + } + +} diff --git a/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.html b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.html new file mode 100644 index 0000000..522bd54 --- /dev/null +++ b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.html @@ -0,0 +1,50 @@ +
+ +
+
+
+

{{(session | async)?.payload?.val()?.body}} Sitzung Nr. {{(session | async)?.payload?.val()?.number}}, + {{(session | async)?.payload?.val()?.date}}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FraktionGesamtrededauer (mm:ss)Gesamtdauer Zwischenrufe (mm:ss)Kürzeste Rede (mm:ss)Längste Rede (mm:ss)Anzahl Sitze
Insgesamt{{totalSpeechTime | toMinuteSeconds}} (100%){{totalCommentaryTime | toMinuteSeconds}} (100%){{shortestSpeech?.timeInMilliseconds | toMinuteSeconds}}{{longestSpeech?.timeInMilliseconds | toMinuteSeconds}}
{{faction.payload.val()?.faction}}{{speechTimesPerFaction.get(faction.payload.val()?.factionKey || '') | toMinuteSeconds}} + + ({{proportionOfSpeechTimePerFaction.get(faction.payload.val()?.factionKey || '') | percent}}) + + {{commentaryTimesPerFaction.get(faction.payload.val()?.factionKey || '') | toMinuteSeconds}} + + ({{proportionOfCommentaryTimePerFaction.get(faction.payload.val()?.factionKey || '') | percent}}) + + {{shortestSpeechPerFaction.get(faction.payload.val()?.factionKey || '')?.timeInMilliseconds | toMinuteSeconds}}{{longestSpeechPerFaction.get(faction.payload.val()?.factionKey || '')?.timeInMilliseconds | toMinuteSeconds}}{{faction.payload.val()?.size}}
+
+
diff --git a/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.scss b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.spec.ts b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.spec.ts new file mode 100644 index 0000000..f934641 --- /dev/null +++ b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SessionStatisticsComponent } from './session-statistics.component'; + +describe('SessionStatisticsComponent', () => { + let component: SessionStatisticsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SessionStatisticsComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SessionStatisticsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.ts b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.ts new file mode 100644 index 0000000..d30c6b8 --- /dev/null +++ b/projects/speech-statistics/src/app/statistics/session-statistics/session-statistics.component.ts @@ -0,0 +1,119 @@ +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {Observable, Subscription} from 'rxjs'; +import {Speech} from '../../shared/speech'; +import {AngularFireDatabase, SnapshotAction} from '@angular/fire/compat/database'; +import {map} from 'rxjs/operators'; +import {FactionInBodyService} from '../../auth/shared/faction-in-body.service'; +import {SpeechType} from '../../shared/speech-type'; +import {Session} from '../../auth/edit/session'; + +@Component({ + selector: 'app-session-statistics', + templateUrl: './session-statistics.component.html', + styleUrls: ['./session-statistics.component.scss'] +}) +export class SessionStatisticsComponent implements OnInit, OnDestroy { + public totalSpeechTime: number = 0; + public totalCommentaryTime: number = 0; + public longestSpeech: Speech | undefined; + public shortestSpeech: Speech | undefined; + public readonly speechTimesPerFaction: Map = new Map(); + public readonly commentaryTimesPerFaction: Map = new Map(); + public readonly shortestSpeechPerFaction: Map = new Map(); + public readonly longestSpeechPerFaction: Map = new Map(); + public readonly proportionOfSpeechTimePerFaction: Map = new Map(); + public readonly proportionOfCommentaryTimePerFaction: Map = new Map(); + public session: Observable> = new Observable>(); + + private sessionKey: string | undefined; + private speechTimes: Observable[]> = new Observable[]>(); + private subscriptions: Subscription[] = []; + + constructor(private database: AngularFireDatabase, + private route: ActivatedRoute, + public factionInBodyService: FactionInBodyService) { + } + + ngOnInit(): void { + this.sessionKey = this.route.snapshot.params['sessionKey']; + const speechTimesRef = this.database.list('speechTimes'); + const sessionRef = this.database.object('sessions/' + this.sessionKey); + this.session = sessionRef.snapshotChanges(); + + this.speechTimes = speechTimesRef.snapshotChanges().pipe( + map(speechTimesList => { + return speechTimesList.filter(speechTime => speechTime.payload.val()?.sessionKey == this.sessionKey); + }) + ); + + this.subscriptions.push( + this.speechTimes.subscribe((speechTimes) => this.calculateStatistics(speechTimes)), + ); + } + + ngOnDestroy(): void { + this.subscriptions.forEach(sub => sub.unsubscribe()); + } + + private calculateStatistics(speechTimes: SnapshotAction[]): void { + this.totalCommentaryTime = 0; + this.totalSpeechTime = 0; + this.speechTimesPerFaction.clear(); + this.commentaryTimesPerFaction.clear(); + this.shortestSpeechPerFaction.clear(); + this.longestSpeechPerFaction.clear(); + this.proportionOfCommentaryTimePerFaction.clear(); + this.proportionOfSpeechTimePerFaction.clear(); + this.shortestSpeech = undefined; + this.longestSpeech = undefined; + + for (const speechTime of speechTimes) { + const speech = speechTime.payload.val(); + if (speech == null) { + continue; + } + + if (speech.type == SpeechType.SPEECH) { + this.totalSpeechTime += speech.timeInMilliseconds; + const speechTime = this.speechTimesPerFaction.get(speech.factionKey); + this.speechTimesPerFaction.set(speech.factionKey, speech.timeInMilliseconds + (speechTime ? speechTime : 0)); + if (this.shortestSpeech != null && speech.timeInMilliseconds < this.shortestSpeech.timeInMilliseconds) { + this.shortestSpeech = speech; + } else if (this.shortestSpeech == null) { + this.shortestSpeech = speech; + } + if (this.longestSpeech != null && speech.timeInMilliseconds > this.longestSpeech.timeInMilliseconds) { + this.longestSpeech = speech; + } else if (this.longestSpeech == null) { + this.longestSpeech = speech; + } + const shortestSpeechFaction = this.shortestSpeechPerFaction.get(speech.factionKey); + if (shortestSpeechFaction != null && speech.timeInMilliseconds < shortestSpeechFaction.timeInMilliseconds) { + this.shortestSpeechPerFaction.set(speech.factionKey, speech); + } else if (shortestSpeechFaction == null) { + this.shortestSpeechPerFaction.set(speech.factionKey, speech); + } + const longestSpeechFaction = this.longestSpeechPerFaction.get(speech.factionKey); + if (longestSpeechFaction != null && speech.timeInMilliseconds > longestSpeechFaction.timeInMilliseconds) { + this.longestSpeechPerFaction.set(speech.factionKey, speech); + } else if (longestSpeechFaction == null) { + this.longestSpeechPerFaction.set(speech.factionKey, speech); + } + } else if (speech.type == SpeechType.COMMENTARY) { + this.totalCommentaryTime += speech.timeInMilliseconds; + const commentaryTime = this.commentaryTimesPerFaction.get(speech.factionKey); + this.commentaryTimesPerFaction.set(speech.factionKey, speech.timeInMilliseconds + (commentaryTime ? commentaryTime : 0)); + } + } + + for (const factionKey of this.speechTimesPerFaction.keys()) { + const speechTimeFaction = this.speechTimesPerFaction.get(factionKey); + this.proportionOfSpeechTimePerFaction.set(factionKey, (speechTimeFaction ? speechTimeFaction : 0) / this.totalSpeechTime); + } + for (const factionKey of this.commentaryTimesPerFaction.keys()) { + const commentaryTimeFaction = this.commentaryTimesPerFaction.get(factionKey); + this.proportionOfCommentaryTimePerFaction.set(factionKey, (commentaryTimeFaction ? commentaryTimeFaction : 0) / this.totalCommentaryTime); + } + } +} diff --git a/projects/speech-statistics/src/app/statistics/statistics-routing.module.ts b/projects/speech-statistics/src/app/statistics/statistics-routing.module.ts index 12d311a..4c716b9 100644 --- a/projects/speech-statistics/src/app/statistics/statistics-routing.module.ts +++ b/projects/speech-statistics/src/app/statistics/statistics-routing.module.ts @@ -1,9 +1,14 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import {StatisticsComponent} from './statistics.component'; +import {SessionStatisticsComponent} from './session-statistics/session-statistics.component'; const routes: Routes = [ - {path: '', component: StatisticsComponent}, + { + path: '', + component: StatisticsComponent, + }, + {path: ':sessionKey', component: SessionStatisticsComponent}, ]; @NgModule({ diff --git a/projects/speech-statistics/src/app/statistics/statistics.component.html b/projects/speech-statistics/src/app/statistics/statistics.component.html index 3871931..278b5e0 100644 --- a/projects/speech-statistics/src/app/statistics/statistics.component.html +++ b/projects/speech-statistics/src/app/statistics/statistics.component.html @@ -13,4 +13,11 @@ + diff --git a/projects/speech-statistics/src/app/statistics/statistics.module.ts b/projects/speech-statistics/src/app/statistics/statistics.module.ts index dc67699..ea6197b 100644 --- a/projects/speech-statistics/src/app/statistics/statistics.module.ts +++ b/projects/speech-statistics/src/app/statistics/statistics.module.ts @@ -4,11 +4,15 @@ import {CommonModule} from '@angular/common'; import {StatisticsRoutingModule} from './statistics-routing.module'; import {NavbarModule} from '../navbar/navbar.module'; import {StatisticsComponent} from './statistics.component'; +import { SessionStatisticsComponent } from './session-statistics/session-statistics.component'; +import {ToMinuteSecondsPipe} from '../shared/to-minute-seconds.pipe'; @NgModule({ declarations: [ StatisticsComponent, + SessionStatisticsComponent, + ToMinuteSecondsPipe, ], imports: [ CommonModule,