ov-components: add landscape orientation warning and improve loading animations

master
Carlos Santos 2025-09-22 12:39:07 +02:00
parent d48e44ea55
commit f11f0933b4
13 changed files with 110 additions and 48 deletions

View File

@ -1,31 +1,42 @@
<div id="spinner" *ngIf="loading" @sessionAnimation> @if (loading) {
<mat-spinner [diameter]="50"></mat-spinner> <div id="spinner" [@inOutAnimation]>
<span>{{ 'ROOM.JOINING' | translate }}</span> <mat-spinner [diameter]="50"></mat-spinner>
</div> <span>{{ 'ROOM.JOINING' | translate }}</span>
<div id="session-container" *ngIf="!loading" @sessionAnimation>
<mat-sidenav-container #container #videoContainer class="sidenav-container">
<mat-sidenav
#sidenav
mode="{{ sidenavMode }}"
position="end"
class="sidenav-menu"
[ngClass]="{big: settingsPanelOpened}"
fixedInViewport="true"
fixedTopGap="0"
fixedBottomGap="0"
>
<ng-container *ngTemplateOutlet="panelTemplate"></ng-container>
</mat-sidenav>
<mat-sidenav-content class="sidenav-main">
<div id="layout-container" #layoutContainer>
<ng-container *ngTemplateOutlet="layoutTemplate"></ng-container>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
<div id="footer-container" *ngIf="toolbarTemplate">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
</div> </div>
</div> } @else {
@if (viewportService.orientation() === 'landscape') {
<!-- Landscape orientation warning -->
<div id="landscape-warning" [@inOutAnimation]>
<div class="warning-message">
<mat-icon class="warning-icon">screen_rotation</mat-icon>
<span>{{ 'ROOM.LANDSCAPE_WARNING' | translate }}</span>
</div>
</div>
}
<div id="session-container" [@inOutAnimation]>
<mat-sidenav-container #container #videoContainer class="sidenav-container">
<mat-sidenav
#sidenav
mode="{{ sidenavMode }}"
position="end"
class="sidenav-menu"
[ngClass]="{ big: settingsPanelOpened }"
fixedInViewport="true"
fixedTopGap="0"
fixedBottomGap="0"
>
<ng-container *ngTemplateOutlet="panelTemplate"></ng-container>
</mat-sidenav>
<mat-sidenav-content class="sidenav-main">
<div id="layout-container" #layoutContainer>
<ng-container *ngTemplateOutlet="layoutTemplate"></ng-container>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
<div id="footer-container" *ngIf="toolbarTemplate">
<ng-container *ngTemplateOutlet="toolbarTemplate"></ng-container>
</div>
</div>
}

View File

@ -3,6 +3,40 @@
/* min-width: 400px; */ /* min-width: 400px; */
height: 100%; height: 100%;
} }
#landscape-warning {
width: 100%;
height: 100%;
background-color: var(--ov-background-color);
opacity: 95%;
align-content: space-evenly;
text-align: center;
color: var(--ov-text-primary-color);
.warning-message {
display: inline-grid;
display: -moz-inline-grid;
place-items: center;
}
mat-icon {
width: 50px;
height: 50px;
font-size: 50px;
margin: auto;
margin-bottom: 10px;
animation: boomerang 1.2s ease-in-out infinite alternate;
@keyframes boomerang {
from {
transform: rotate(0deg);
}
to {
transform: rotate(45deg);
}
}
}
}
#spinner { #spinner {
position: absolute; position: absolute;
top: 40%; top: 40%;

View File

@ -49,6 +49,7 @@ import {
import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model'; import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model';
import { RecordingStatus } from '../../models/recording.model'; import { RecordingStatus } from '../../models/recording.model';
import { TemplateManagerService, SessionTemplateConfiguration } from '../../services/template/template-manager.service'; import { TemplateManagerService, SessionTemplateConfiguration } from '../../services/template/template-manager.service';
import { ViewportService } from '../../services/viewport/viewport.service';
/** /**
* @internal * @internal
@ -58,14 +59,19 @@ import { TemplateManagerService, SessionTemplateConfiguration } from '../../serv
selector: 'ov-session', selector: 'ov-session',
templateUrl: './session.component.html', templateUrl: './session.component.html',
styleUrls: ['./session.component.scss'], styleUrls: ['./session.component.scss'],
animations: [trigger('sessionAnimation', [transition(':enter', [style({ opacity: 0 }), animate('50ms', style({ opacity: 1 }))])])], animations: [
trigger('inOutAnimation', [
transition(':enter', [style({ opacity: 0 }), animate('200ms', style({ opacity: 1 }))]),
transition(':leave', [animate('200ms', style({ opacity: 0 }))])
])
],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false standalone: false
}) })
export class SessionComponent implements OnInit, OnDestroy { export class SessionComponent implements OnInit, OnDestroy {
@ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any>; @ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate: TemplateRef<any> | undefined;
@ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any>; @ContentChild('panel', { read: TemplateRef }) panelTemplate: TemplateRef<any> | undefined;
@ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any>; @ContentChild('layout', { read: TemplateRef }) layoutTemplate: TemplateRef<any> | undefined;
/** /**
* Provides event notifications that fire when Room is created for the local participant. * Provides event notifications that fire when Room is created for the local participant.
*/ */
@ -97,7 +103,7 @@ export class SessionComponent implements OnInit, OnDestroy {
*/ */
@Output() onParticipantLeft: EventEmitter<ParticipantLeftEvent> = new EventEmitter<ParticipantLeftEvent>(); @Output() onParticipantLeft: EventEmitter<ParticipantLeftEvent> = new EventEmitter<ParticipantLeftEvent>();
room: Room; room!: Room;
sideMenu: MatSidenav; sideMenu: MatSidenav;
sidenavMode: SidenavMode = SidenavMode.SIDE; sidenavMode: SidenavMode = SidenavMode.SIDE;
settingsPanelOpened: boolean; settingsPanelOpened: boolean;
@ -131,7 +137,8 @@ export class SessionComponent implements OnInit, OnDestroy {
// private captionService: CaptionService, // private captionService: CaptionService,
private backgroundService: VirtualBackgroundService, private backgroundService: VirtualBackgroundService,
private cd: ChangeDetectorRef, private cd: ChangeDetectorRef,
private templateManagerService: TemplateManagerService private templateManagerService: TemplateManagerService,
protected viewportService: ViewportService
) { ) {
this.log = this.loggerSrv.get('SessionComponent'); this.log = this.loggerSrv.get('SessionComponent');
this.setupTemplates(); this.setupTemplates();
@ -236,11 +243,11 @@ export class SessionComponent implements OnInit, OnDestroy {
this.subscribeToVirtualBackground(); this.subscribeToVirtualBackground();
// if (this.libService.isRecordingEnabled()) { // if (this.libService.isRecordingEnabled()) {
// this.subscribeToRecordingEvents(); // this.subscribeToRecordingEvents();
// } // }
// if (this.libService.isBroadcastingEnabled()) { // if (this.libService.isBroadcastingEnabled()) {
// this.subscribeToBroadcastingEvents(); // this.subscribeToBroadcastingEvents();
// } // }
try { try {
await this.participantService.connect(); await this.participantService.connect();

View File

@ -22,7 +22,8 @@
"POWERED_BY": "动力 b" "POWERED_BY": "动力 b"
}, },
"ROOM": { "ROOM": {
"JOINING": "正在加入房间..." "JOINING": "正在加入房间...",
"LANDSCAPE_WARNING": "请将设备旋转到纵向以获得最佳体验"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "设置你的绰号", "NICKNAME_SECTION": "设置你的绰号",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Unterstützt von" "POWERED_BY": "Unterstützt von"
}, },
"ROOM": { "ROOM": {
"JOINING": "Raum beitreten..." "JOINING": "Raum beitreten...",
"LANDSCAPE_WARNING": "Bitte drehen Sie Ihr Gerät für eine bessere Erfahrung in den Hochformatmodus"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "Legen Sie Ihren Spitznamen fest", "NICKNAME_SECTION": "Legen Sie Ihren Spitznamen fest",

View File

@ -34,7 +34,8 @@
"PREPARING": "Preparing room..." "PREPARING": "Preparing room..."
}, },
"ROOM": { "ROOM": {
"JOINING": "Joining room..." "JOINING": "Joining room...",
"LANDSCAPE_WARNING": "Please rotate your device to portrait for a better experience"
}, },
"TOOLBAR": { "TOOLBAR": {
"MUTE_AUDIO": "Mute your audio", "MUTE_AUDIO": "Mute your audio",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Construido por" "POWERED_BY": "Construido por"
}, },
"ROOM": { "ROOM": {
"JOINING": "Uniéndose a la sala..." "JOINING": "Uniéndose a la sala...",
"LANDSCAPE_WARNING": "Por favor, gira tu dispositivo a modo retrato para una mejor experiencia"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "Elige tu nombre", "NICKNAME_SECTION": "Elige tu nombre",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Alimenté par" "POWERED_BY": "Alimenté par"
}, },
"ROOM": { "ROOM": {
"JOINING": "Rejoindre la salle..." "JOINING": "Rejoindre la salle...",
"LANDSCAPE_WARNING": "Veuillez faire pivoter votre appareil en mode portrait pour une meilleure expérience"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "Définir votre surnom", "NICKNAME_SECTION": "Définir votre surnom",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "द्वारा संचालित" "POWERED_BY": "द्वारा संचालित"
}, },
"ROOM": { "ROOM": {
"JOINING": "कक्ष में शामिल हो रहा है..." "JOINING": "कक्ष में शामिल हो रहा है...",
"LANDSCAPE_WARNING": "कृपया बेहतर अनुभव के लिए अपने डिवाइस को पोर्ट्रेट मोड में घुमाएँ"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "अपना निकनेम सेट करें", "NICKNAME_SECTION": "अपना निकनेम सेट करें",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Offerto da" "POWERED_BY": "Offerto da"
}, },
"ROOM": { "ROOM": {
"JOINING": "Unendosi alla stanza..." "JOINING": "Unendosi alla stanza...",
"LANDSCAPE_WARNING": "Per una migliore esperienza, ruota il dispositivo in modalità verticale"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "Imposta il tuo soprannome", "NICKNAME_SECTION": "Imposta il tuo soprannome",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Powered by" "POWERED_BY": "Powered by"
}, },
"ROOM": { "ROOM": {
"JOINING": "ルームに参加しています..." "JOINING": "ルームに参加しています...",
"LANDSCAPE_WARNING": "より良い体験のために、デバイスを縦向きに回転させてください"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "ニックネームを設定してください", "NICKNAME_SECTION": "ニックネームを設定してください",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Aangedreven door" "POWERED_BY": "Aangedreven door"
}, },
"ROOM": { "ROOM": {
"JOINING": "De ruimte betreden..." "JOINING": "De ruimte betreden...",
"LANDSCAPE_WARNING": "Draai uw apparaat voor een betere ervaring naar portretmodus"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "Stel je bijnaam in", "NICKNAME_SECTION": "Stel je bijnaam in",

View File

@ -22,7 +22,8 @@
"POWERED_BY": "Distribuído por" "POWERED_BY": "Distribuído por"
}, },
"ROOM": { "ROOM": {
"JOINING": "Entrando na sala..." "JOINING": "Entrando na sala...",
"LANDSCAPE_WARNING": "Por favor, gire seu dispositivo para o modo retrato para uma melhor experiência"
}, },
"PREJOIN": { "PREJOIN": {
"NICKNAME_SECTION": "Defina seu apelido", "NICKNAME_SECTION": "Defina seu apelido",