openvidu-components: Updated layout elements transitons

pull/743/head
csantosm 2022-07-05 17:48:25 +02:00
parent 4fd2fc8595
commit 25972260ac
11 changed files with 49 additions and 58 deletions

View File

@ -1,6 +1,6 @@
<div class="container" [class.withSubtitles]="subtitlesEnabled"> <div class="container" [class.withSubtitles]="subtitlesEnabled">
<div id="layout" class="layout"> <div id="layout" class="layout" #layout>
<div class="OT_root OT_publisher" *ngFor="let stream of localParticipant | streams" [ngClass]="{ OV_big: stream.videoEnlarged }"> <div *ngFor="let stream of localParticipant | streams" [ngClass]="{ OV_big: stream.videoEnlarged }" class="OT_root OT_publisher">
<ng-container *ngTemplateOutlet="streamTemplate; context: { $implicit: stream }"></ng-container> <ng-container *ngTemplateOutlet="streamTemplate; context: { $implicit: stream }"></ng-container>
</div> </div>

View File

@ -6,7 +6,9 @@ import {
ContentChild, ContentChild,
OnDestroy, OnDestroy,
OnInit, OnInit,
TemplateRef TemplateRef,
ViewChild,
ViewContainerRef
} from '@angular/core'; } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { ParticipantService } from '../../services/participant/participant.service'; import { ParticipantService } from '../../services/participant/participant.service';
@ -59,6 +61,10 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
*/ */
@ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>; @ContentChild('stream', { read: TemplateRef }) streamTemplate: TemplateRef<any>;
/**
* @ignore
*/
@ViewChild('layout', { static: false, read: ViewContainerRef }) layoutContainer: ViewContainerRef;
/** /**
* @ignore * @ignore
*/ */
@ -93,9 +99,7 @@ export class LayoutComponent implements OnInit, OnDestroy, AfterViewInit {
} }
ngAfterViewInit() { ngAfterViewInit() {
let timeout: number = 100; this.layoutService.initialize(this.layoutContainer.element.nativeElement);
this.layoutService.initialize(timeout);
this.layoutService.update(timeout);
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -107,7 +107,7 @@
height: 100%; height: 100%;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
background-color: #000000; background-color: transparent;
border-radius: var(--ov-video-radius); border-radius: var(--ov-video-radius);
} }

View File

@ -1,6 +1,7 @@
<div <div
*ngIf="this._stream" *ngIf="this._stream"
class="OV_stream no-size" class="OV_stream"
[ngClass]="{'no-size': !showVideo}"
[id]="'container-' + this._stream.streamManager?.stream?.streamId" [id]="'container-' + this._stream.streamManager?.stream?.streamId"
#streamContainer #streamContainer
> >
@ -65,14 +66,6 @@
<mat-icon *ngIf="_stream.participant.isMutedForcibly">volume_off</mat-icon> <mat-icon *ngIf="_stream.participant.isMutedForcibly">volume_off</mat-icon>
<span *ngIf="_stream.participant.isMutedForcibly">{{ 'STREAM.UNMUTE_SOUND' | translate }}</span> <span *ngIf="_stream.participant.isMutedForcibly">{{ 'STREAM.UNMUTE_SOUND' | translate }}</span>
</button> </button>
<!-- <button mat-menu-item *ngIf="this._stream.streamManager?.stream?.videoActive" id="fullscreenButton" (click)="toggleFullscreen()">
<mat-icon *ngIf="!isFullscreenEnabled">fullscreen</mat-icon>
<span *ngIf="!isFullscreenEnabled">Fullscreen</span>
<mat-icon *ngIf="isFullscreenEnabled">fullscreen_exit</mat-icon>
<span *ngIf="isFullscreenEnabled">Exit fullscreen</span>
</button> -->
<button <button
mat-menu-item mat-menu-item
(click)="replaceScreenTrack()" (click)="replaceScreenTrack()"

View File

@ -3,7 +3,6 @@ import { Subscription } from 'rxjs';
import { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu'; import { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu';
import { VideoSizeIcon } from '../../models/icon.model'; import { VideoSizeIcon } from '../../models/icon.model';
import { ScreenType, VideoType } from '../../models/video-type.model'; import { ScreenType, VideoType } from '../../models/video-type.model';
import { DocumentService } from '../../services/document/document.service';
import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service'; import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service';
import { OpenViduService } from '../../services/openvidu/openvidu.service'; import { OpenViduService } from '../../services/openvidu/openvidu.service';
import { LayoutService } from '../../services/layout/layout.service'; import { LayoutService } from '../../services/layout/layout.service';
@ -109,6 +108,7 @@ export class StreamComponent implements OnInit {
* @ignore * @ignore
*/ */
showSettingsButton: boolean = true; showSettingsButton: boolean = true;
showVideo: boolean;
/** /**
* @ignore * @ignore
@ -118,9 +118,10 @@ export class StreamComponent implements OnInit {
setTimeout(() => { setTimeout(() => {
if (streamContainer) { if (streamContainer) {
this._streamContainer = streamContainer; this._streamContainer = streamContainer;
// Remove 'no-size' css class for showing the element in the view.
// This is a workaround for fixing a layout bug which provide a bad UX with each new elements created. // This is a workaround for fixing a layout bug which provide a bad UX with each new elements created.
this.documentService.removeNoSizeElementClass(this._streamContainer.nativeElement); setTimeout(() => {
this.showVideo = true;
}, 100);
} }
}, 0); }, 0);
} }
@ -154,7 +155,6 @@ export class StreamComponent implements OnInit {
* @ignore * @ignore
*/ */
constructor( constructor(
protected documentService: DocumentService,
protected openviduService: OpenViduService, protected openviduService: OpenViduService,
protected layoutService: LayoutService, protected layoutService: LayoutService,
protected participantService: ParticipantService, protected participantService: ParticipantService,

View File

@ -1,6 +1,9 @@
#call-container, #session-container { #call-container, #session-container {
height: 100%; height: 100%;
} }
#session-container {
background-color: var(--ov-primary-color);
}
#pre-join-container { #pre-join-container {
height: inherit; height: inherit;

View File

@ -1,20 +1,20 @@
<div id="call-container"> <div id="call-container">
<div id="pre-join-container" *ngIf="showPrejoin && tokensReceived && participantReady"> <div id="spinner" *ngIf="loading" >
<ov-pre-join (onJoinButtonClicked)="_onJoinButtonClicked()"></ov-pre-join>
</div>
<div id="spinner" *ngIf="!participantReady && !streamPlaying && !error">
<mat-spinner [diameter]="50"></mat-spinner> <mat-spinner [diameter]="50"></mat-spinner>
<span>{{ 'PREJOIN.PREPARING' | translate }}</span> <span>{{ 'PREJOIN.PREPARING' | translate }}</span>
</div> </div>
<div id="spinner" *ngIf="!participantReady && error"> <div [@inOutAnimation] id="pre-join-container" *ngIf="showPrejoin && participantReady && !loading">
<ov-pre-join (onJoinButtonClicked)="_onJoinButtonClicked()"></ov-pre-join>
</div>
<div id="spinner" *ngIf="!loading && error">
<mat-icon class="error-icon">error</mat-icon> <mat-icon class="error-icon">error</mat-icon>
<span>{{ errorMessage }}</span> <span>{{ errorMessage }}</span>
</div> </div>
<div id="session-container" *ngIf="showVideoconference || (!showPrejoin && participantReady && tokensReceived && !error)"> <div [@inOutAnimation] id="session-container" *ngIf="showVideoconference || (!showPrejoin && !loading && !error)">
<ov-session (onSessionCreated)="_onSessionCreated($event)"> <ov-session (onSessionCreated)="_onSessionCreated($event)">
<ng-template #toolbar> <ng-template #toolbar>
<ng-container *ngIf="openviduAngularToolbarTemplate"> <ng-container *ngIf="openviduAngularToolbarTemplate">

View File

@ -1,3 +1,4 @@
import { trigger, state, style, transition, animate } from '@angular/animations';
import { import {
AfterViewInit, AfterViewInit,
Component, Component,
@ -110,7 +111,13 @@ import { TranslateService } from '../../services/translate/translate.service';
@Component({ @Component({
selector: 'ov-videoconference', selector: 'ov-videoconference',
templateUrl: './videoconference.component.html', templateUrl: './videoconference.component.html',
styleUrls: ['./videoconference.component.css'] styleUrls: ['./videoconference.component.css'],
animations: [
trigger('inOutAnimation', [
transition(':enter', [style({ opacity: 0 }), animate('300ms ease-out', style({ opacity: 1 }))]),
// transition(':leave', [style({ opacity: 1 }), animate('50ms ease-in', style({ opacity: 0.9 }))])
])
]
}) })
export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewInit { export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewInit {
// *** Toolbar *** // *** Toolbar ***
@ -186,7 +193,6 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
*/ */
@ViewChild('defaultParticipantsPanel', { static: false, read: TemplateRef }) defaultParticipantsPanelTemplate: TemplateRef<any>; @ViewChild('defaultParticipantsPanel', { static: false, read: TemplateRef }) defaultParticipantsPanelTemplate: TemplateRef<any>;
/** /**
* TODO: WIP
* @internal * @internal
*/ */
@ViewChild('defaultActivitiesPanel', { static: false, read: TemplateRef }) @ViewChild('defaultActivitiesPanel', { static: false, read: TemplateRef })
@ -214,7 +220,6 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
*/ */
openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>; openviduAngularToolbarAdditionalButtonsTemplate: TemplateRef<any>;
/** /**
* TODO: WIP
* @internal * @internal
*/ */
openviduAngularActivitiesPanelTemplate: TemplateRef<any>; openviduAngularActivitiesPanelTemplate: TemplateRef<any>;
@ -281,7 +286,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
} else { } else {
this.log.w('No screen token found. Screenshare feature will be disabled'); this.log.w('No screen token found. Screenshare feature will be disabled');
} }
this.tokensReceived = true; this.loading = false;
} }
} }
@ -382,10 +387,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
* @internal * @internal
*/ */
participantReady: boolean = false; participantReady: boolean = false;
/**
* @internal
*/
tokensReceived: boolean = false;
/** /**
* @internal * @internal
*/ */
@ -399,7 +401,10 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
*/ */
showPrejoin: boolean = true; showPrejoin: boolean = true;
streamPlaying = false; /**
* @internal
*/
loading = true;
private externalParticipantName: string; private externalParticipantName: string;
private prejoinSub: Subscription; private prejoinSub: Subscription;
private participantNameSub: Subscription; private participantNameSub: Subscription;
@ -449,7 +454,7 @@ export class VideoconferenceComponent implements OnInit, OnDestroy, AfterViewIni
await this.handlePublisherSuccess(); await this.handlePublisherSuccess();
this.participantReady = true; this.participantReady = true;
}); });
publisher.once('streamPlaying', () => (this.streamPlaying = true)); // publisher.once('streamPlaying', () => (this.streamPlaying = true));
} }
} catch (error) { } catch (error) {
this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true); this.actionService.openDialog(error.name.replace(/_/g, ' '), error.message, true);

View File

@ -233,6 +233,7 @@ export class OpenViduLayout {
// }); // });
this.opts = opts; this.opts = opts;
this.layoutContainer = container; this.layoutContainer = container;
this.updateLayout(container, opts);
} }
getLayoutContainer(): HTMLElement { getLayoutContainer(): HTMLElement {
@ -243,9 +244,9 @@ export class OpenViduLayout {
* Set the layout configuration * Set the layout configuration
* @param options * @param options
*/ */
private setLayoutOptions(options: OpenViduLayoutOptions) { // private setLayoutOptions(options: OpenViduLayoutOptions) {
this.opts = options; // this.opts = options;
} // }
private css(el: HTMLVideoElement | HTMLElement, propertyName: any, value?: string) { private css(el: HTMLVideoElement | HTMLElement, propertyName: any, value?: string) {
if (!!value) { if (!!value) {

View File

@ -58,10 +58,6 @@ export class DocumentService {
} }
} }
removeNoSizeElementClass(element: HTMLElement | Element) {
element?.classList.remove(LayoutClass.NO_SIZE_ELEMENT);
}
isSmallElement(element: HTMLElement | Element): boolean { isSmallElement(element: HTMLElement | Element): boolean {
return element?.className.includes(LayoutClass.SMALL_ELEMENT); return element?.className.includes(LayoutClass.SMALL_ELEMENT);
} }

View File

@ -25,25 +25,14 @@ export class LayoutService {
this.subtitlesTogglingObs = this.subtitlesToggling.asObservable(); this.subtitlesTogglingObs = this.subtitlesToggling.asObservable();
} }
initialize(timeout: number = null) { initialize(container: HTMLElement) {
if (typeof timeout === 'number' && timeout >= 0) { this.layoutContainer = container;
setTimeout(() => {
this._initialize();
this.sendLayoutWidthEvent();
}, timeout);
} else {
this._initialize();
this.sendLayoutWidthEvent();
}
}
private _initialize() {
this.openviduLayout = new OpenViduLayout(); this.openviduLayout = new OpenViduLayout();
this.openviduLayoutOptions = this.getOptions(); this.openviduLayoutOptions = this.getOptions();
this.layoutContainer = document.getElementById('layout');
if(this.layoutContainer){ if(this.layoutContainer){
this.openviduLayout.initLayoutContainer(this.layoutContainer, this.openviduLayoutOptions); this.openviduLayout.initLayoutContainer(this.layoutContainer, this.openviduLayoutOptions);
} }
this.sendLayoutWidthEvent();
} }
private getOptions(): OpenViduLayoutOptions { private getOptions(): OpenViduLayoutOptions {