frontend: add view recording component
This commit is contained in:
parent
fff7fb957c
commit
ea1b84d72b
@ -12,3 +12,4 @@ export * from './error/error.component';
|
|||||||
export * from './login/login.component';
|
export * from './login/login.component';
|
||||||
export * from './room-recordings/room-recordings.component';
|
export * from './room-recordings/room-recordings.component';
|
||||||
export * from './video-room/video-room.component';
|
export * from './video-room/video-room.component';
|
||||||
|
export * from './view-recording/view-recording.component';
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
@if (recording && recordingUrl) {
|
||||||
|
<mat-card class="recording-container">
|
||||||
|
<div class="video-container">
|
||||||
|
<video controls class="video-player">
|
||||||
|
<source [src]="recordingUrl" type="video/mp4" />
|
||||||
|
Your browser does not support the video tag.
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mat-card-content>
|
||||||
|
<h2 class="title">{{ recording.roomId }}</h2>
|
||||||
|
<div class="info-actions">
|
||||||
|
<span class="date">{{ recording.startDate | date: 'M/d/yy, H:mm' }}</span>
|
||||||
|
<div class="actions">
|
||||||
|
<button mat-icon-button color="primary" (click)="downloadRecording()" aria-label="Download">
|
||||||
|
<mat-icon>download</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button color="accent" (click)="openShareDialog()" aria-label="Share">
|
||||||
|
<mat-icon>share</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
.recording-container {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 20px auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 56.25%; /* 16:9 aspect ratio */
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-player {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 16px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.info-actions {
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ViewRecordingComponent } from './view-recording.component';
|
||||||
|
|
||||||
|
describe('ViewRecordingComponent', () => {
|
||||||
|
let component: ViewRecordingComponent;
|
||||||
|
let fixture: ComponentFixture<ViewRecordingComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ViewRecordingComponent]
|
||||||
|
}).compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(ViewRecordingComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import { DatePipe } from '@angular/common';
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { ShareRecordingDialogComponent } from '@lib/components';
|
||||||
|
import { HttpService } from '@lib/services';
|
||||||
|
import { ActionService, MeetRecordingInfo } from 'shared-meet-components';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-view-recording',
|
||||||
|
templateUrl: './view-recording.component.html',
|
||||||
|
styleUrls: ['./view-recording.component.scss'],
|
||||||
|
standalone: true,
|
||||||
|
imports: [MatCardModule, MatButtonModule, MatIconModule, DatePipe]
|
||||||
|
})
|
||||||
|
export class ViewRecordingComponent implements OnInit {
|
||||||
|
recording: MeetRecordingInfo | undefined;
|
||||||
|
recordingUrl: string | undefined;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected httpService: HttpService,
|
||||||
|
protected actionService: ActionService,
|
||||||
|
protected route: ActivatedRoute,
|
||||||
|
protected dialog: MatDialog
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
const recordingId = this.route.snapshot.paramMap.get('recording-id');
|
||||||
|
const secret = this.route.snapshot.queryParams['secret'];
|
||||||
|
|
||||||
|
this.recording = await this.httpService.getRecording(recordingId!, secret!);
|
||||||
|
this.playRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
playRecording() {
|
||||||
|
this.recordingUrl = this.httpService.getRecordingMediaUrl(this.recording!.recordingId);
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadRecording() {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = this.recordingUrl!;
|
||||||
|
link.download = this.recording!.filename || 'openvidu-recording.mp4';
|
||||||
|
link.dispatchEvent(
|
||||||
|
new MouseEvent('click', {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
view: window
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// For Firefox it is necessary to delay revoking the ObjectURL
|
||||||
|
setTimeout(() => link.remove(), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
openShareDialog() {
|
||||||
|
this.dialog.open(ShareRecordingDialogComponent, {
|
||||||
|
width: '400px',
|
||||||
|
data: { recordingId: this.recording!.recordingId }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user