html5 media
This commit is contained in:
parent
ccd1830da9
commit
d8a1f2b85e
10 changed files with 142 additions and 17 deletions
|
@ -0,0 +1,7 @@
|
||||||
|
<mat-card class="callInfo" appearance="outlined">
|
||||||
|
<div class="inc-heading">
|
||||||
|
<div class="field field-label">Time</div>
|
||||||
|
<div class="field field-data">{{ call.call_date }}</div>
|
||||||
|
</div>
|
||||||
|
<audio controls [src]="call.audioURL! | safe: 'resourceUrl'"></audio>
|
||||||
|
</mat-card>
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CallInfoComponent } from './call-info.component';
|
||||||
|
|
||||||
|
describe('CallInfoComponent', () => {
|
||||||
|
let component: CallInfoComponent;
|
||||||
|
let fixture: ComponentFixture<CallInfoComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [CallInfoComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(CallInfoComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { CallRecord } from '../../calls';
|
||||||
|
import { Share } from '../../shares';
|
||||||
|
import { SafePipe } from '../calls.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-call-info',
|
||||||
|
imports: [MatCardModule, SafePipe],
|
||||||
|
templateUrl: './call-info.component.html',
|
||||||
|
styleUrl: './call-info.component.scss',
|
||||||
|
})
|
||||||
|
export class CallInfoComponent {
|
||||||
|
@Input() share!: Share;
|
||||||
|
call!: CallRecord;
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.call = this.share.sharedItem as CallRecord;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,14 @@ import { environment } from '.././../environments/environment';
|
||||||
import { TalkgroupService } from '../talkgroups/talkgroups.service';
|
import { TalkgroupService } from '../talkgroups/talkgroups.service';
|
||||||
import { Talkgroup } from '../talkgroup';
|
import { Talkgroup } from '../talkgroup';
|
||||||
import { Share } from '../shares';
|
import { Share } from '../shares';
|
||||||
|
import {
|
||||||
|
DomSanitizer,
|
||||||
|
SafeHtml,
|
||||||
|
SafeResourceUrl,
|
||||||
|
SafeScript,
|
||||||
|
SafeStyle,
|
||||||
|
SafeUrl,
|
||||||
|
} from '@angular/platform-browser';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'grabDate',
|
name: 'grabDate',
|
||||||
|
@ -43,7 +51,11 @@ export class TimePipe implements PipeTransform {
|
||||||
export class TalkgroupPipe implements PipeTransform {
|
export class TalkgroupPipe implements PipeTransform {
|
||||||
constructor(private tgService: TalkgroupService) {}
|
constructor(private tgService: TalkgroupService) {}
|
||||||
|
|
||||||
transform(call: CallRecord, field: string, share: Share|null = null): Observable<string> {
|
transform(
|
||||||
|
call: CallRecord,
|
||||||
|
field: string,
|
||||||
|
share: Share | null = null,
|
||||||
|
): Observable<string> {
|
||||||
return this.tgService.getTalkgroup(call.system_id, call.tgid).pipe(
|
return this.tgService.getTalkgroup(call.system_id, call.tgid).pipe(
|
||||||
map((tg: Talkgroup) => {
|
map((tg: Talkgroup) => {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
|
@ -82,6 +94,50 @@ export class FixedPointPipe implements PipeTransform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize HTML
|
||||||
|
*/
|
||||||
|
@Pipe({
|
||||||
|
name: 'safe',
|
||||||
|
})
|
||||||
|
export class SafePipe implements PipeTransform {
|
||||||
|
/**
|
||||||
|
* Pipe Constructor
|
||||||
|
*
|
||||||
|
* @param _sanitizer: DomSanitezer
|
||||||
|
*/
|
||||||
|
// tslint:disable-next-line
|
||||||
|
constructor(protected _sanitizer: DomSanitizer) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform
|
||||||
|
*
|
||||||
|
* @param value: string
|
||||||
|
* @param type: string
|
||||||
|
*/
|
||||||
|
transform(
|
||||||
|
value: string,
|
||||||
|
type: string,
|
||||||
|
): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
|
||||||
|
switch (type) {
|
||||||
|
case 'html':
|
||||||
|
return this._sanitizer.bypassSecurityTrustHtml(value);
|
||||||
|
case 'style':
|
||||||
|
return this._sanitizer.bypassSecurityTrustStyle(value);
|
||||||
|
case 'script':
|
||||||
|
return this._sanitizer.bypassSecurityTrustScript(value);
|
||||||
|
case 'url':
|
||||||
|
return this._sanitizer.bypassSecurityTrustUrl(value);
|
||||||
|
case 'resourceUrl':
|
||||||
|
let res = this._sanitizer.bypassSecurityTrustResourceUrl(value);
|
||||||
|
console.log(res);
|
||||||
|
return res;
|
||||||
|
default:
|
||||||
|
return this._sanitizer.bypassSecurityTrustHtml(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'audioDownloadURL',
|
name: 'audioDownloadURL',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
|
|
@ -76,13 +76,13 @@
|
||||||
<ng-container matColumnDef="system">
|
<ng-container matColumnDef="system">
|
||||||
<th mat-header-cell *matHeaderCellDef>System</th>
|
<th mat-header-cell *matHeaderCellDef>System</th>
|
||||||
<td mat-cell *matCellDef="let call">
|
<td mat-cell *matCellDef="let call">
|
||||||
{{ call | talkgroup: "system":incident | async }}
|
{{ call | talkgroup: "system" : share | async }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="group">
|
<ng-container matColumnDef="group">
|
||||||
<th mat-header-cell *matHeaderCellDef>Group</th>
|
<th mat-header-cell *matHeaderCellDef>Group</th>
|
||||||
<td mat-cell *matCellDef="let call">
|
<td mat-cell *matCellDef="let call">
|
||||||
{{ call | talkgroup: "group":incident | async }}
|
{{ call | talkgroup: "group" : share | async }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container matColumnDef="talkgroup">
|
<ng-container matColumnDef="talkgroup">
|
||||||
|
|
|
@ -154,7 +154,7 @@ export class IncidentEditDialogComponent {
|
||||||
export class IncidentComponent {
|
export class IncidentComponent {
|
||||||
incPrime = new Subject<IncidentRecord>();
|
incPrime = new Subject<IncidentRecord>();
|
||||||
inc$!: Observable<IncidentRecord>;
|
inc$!: Observable<IncidentRecord>;
|
||||||
@Input() incident?: Share;
|
@Input() share?: Share;
|
||||||
subscriptions: Subscription = new Subscription();
|
subscriptions: Subscription = new Subscription();
|
||||||
dialog = inject(MatDialog);
|
dialog = inject(MatDialog);
|
||||||
incID!: string;
|
incID!: string;
|
||||||
|
@ -187,11 +187,11 @@ export class IncidentComponent {
|
||||||
this.incID = this.route.snapshot.paramMap.get('id')!;
|
this.incID = this.route.snapshot.paramMap.get('id')!;
|
||||||
incOb = this.incSvc.getIncident(this.incID);
|
incOb = this.incSvc.getIncident(this.incID);
|
||||||
} else {
|
} else {
|
||||||
if (!this.incident) {
|
if (!this.share) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.incID = (this.incident.sharedItem as IncidentRecord).id;
|
this.incID = (this.share.sharedItem as IncidentRecord).id;
|
||||||
incOb = new BehaviorSubject(this.incident.sharedItem as IncidentRecord);
|
incOb = new BehaviorSubject(this.share.sharedItem as IncidentRecord);
|
||||||
}
|
}
|
||||||
this.inc$ = merge(incOb, this.incPrime).pipe(
|
this.inc$ = merge(incOb, this.incPrime).pipe(
|
||||||
tap((inc) => {
|
tap((inc) => {
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
@let sh = share | async;
|
@let sh = share | async;
|
||||||
@if (sh == null) {
|
@switch (sh?.type) {
|
||||||
<h1 class="error">Share invalid!</h1>
|
@case ("incident") {
|
||||||
} @else if (sh.type == "incident") {
|
<app-incident [share]="sh!"></app-incident>
|
||||||
<app-incident [incident]="sh"></app-incident>
|
}
|
||||||
} @else if (sh.type == "call") {
|
@case ("call") {
|
||||||
} @else {
|
<app-call-info [share]="sh!" player="true"></app-call-info>
|
||||||
<h1 class="error">Share type {{ sh.type }} unknown</h1>
|
}
|
||||||
|
@case (null) {
|
||||||
|
<div class="spinner">
|
||||||
|
<mat-spinner></mat-spinner>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@default {
|
||||||
|
<h1 class="error">Share type {{ sh?.type }} unknown</h1>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,23 @@ import { ActivatedRoute } from '@angular/router';
|
||||||
import { Observable, Subscription, switchMap } from 'rxjs';
|
import { Observable, Subscription, switchMap } from 'rxjs';
|
||||||
import { IncidentComponent } from '../incidents/incident/incident.component';
|
import { IncidentComponent } from '../incidents/incident/incident.component';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
|
import { CallInfoComponent } from '../calls/call-info/call-info.component';
|
||||||
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-share',
|
selector: 'app-share',
|
||||||
imports: [AsyncPipe, IncidentComponent],
|
imports: [
|
||||||
|
AsyncPipe,
|
||||||
|
IncidentComponent,
|
||||||
|
CallInfoComponent,
|
||||||
|
MatProgressSpinnerModule,
|
||||||
|
],
|
||||||
templateUrl: './share.component.html',
|
templateUrl: './share.component.html',
|
||||||
styleUrl: './share.component.scss',
|
styleUrl: './share.component.scss',
|
||||||
})
|
})
|
||||||
export class ShareComponent {
|
export class ShareComponent {
|
||||||
shareID!: string;
|
shareID!: string;
|
||||||
share!: Observable<Share | null>;
|
share!: Observable<Share>;
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private shareSvc: ShareService,
|
private shareSvc: ShareService,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
switchMap,
|
switchMap,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
import { Talkgroup, TalkgroupUpdate, TGID } from '../talkgroup';
|
import { Talkgroup, TalkgroupUpdate, TGID } from '../talkgroup';
|
||||||
|
import { Share } from '../shares';
|
||||||
|
|
||||||
export interface Pagination {
|
export interface Pagination {
|
||||||
page: number;
|
page: number;
|
||||||
|
@ -54,7 +55,11 @@ export class TalkgroupService {
|
||||||
return this.http.get<Talkgroup[]>('/api/talkgroup/');
|
return this.http.get<Talkgroup[]>('/api/talkgroup/');
|
||||||
}
|
}
|
||||||
|
|
||||||
getTalkgroup(sys: number, tg: number): Observable<Talkgroup> {
|
getTalkgroup(
|
||||||
|
sys: number,
|
||||||
|
tg: number,
|
||||||
|
share: Share | null = null,
|
||||||
|
): Observable<Talkgroup> {
|
||||||
const key = this.tgKey(sys, tg);
|
const key = this.tgKey(sys, tg);
|
||||||
if (!this._getTalkgroup.get(key)) {
|
if (!this._getTalkgroup.get(key)) {
|
||||||
let rs = new ReplaySubject<Talkgroup>();
|
let rs = new ReplaySubject<Talkgroup>();
|
||||||
|
|
Loading…
Add table
Reference in a new issue