mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Update device selection logic and improve UI handling for audio and video devices
parent
03fb7c0a93
commit
ee30c3ce95
|
@ -89,7 +89,7 @@ describe('Testing API Directives', () => {
|
||||||
|
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
|
|
||||||
await utils.waitForElement('#lang-btn-compact');
|
await utils.waitForElement('.language-selector');
|
||||||
|
|
||||||
const element = await utils.waitForElement('#join-button');
|
const element = await utils.waitForElement('#join-button');
|
||||||
expect(await element.getText()).toEqual('Unirme ahora');
|
expect(await element.getText()).toEqual('Unirme ahora');
|
||||||
|
@ -108,20 +108,20 @@ describe('Testing API Directives', () => {
|
||||||
const panelTitle = await utils.waitForElement('.panel-title');
|
const panelTitle = await utils.waitForElement('.panel-title');
|
||||||
expect(await panelTitle.getText()).toEqual('Configuración');
|
expect(await panelTitle.getText()).toEqual('Configuración');
|
||||||
|
|
||||||
const element = await utils.waitForElement('#lang-selected-name');
|
const element = await utils.waitForElement('.lang-name');
|
||||||
expect(await element.getAttribute('innerText')).toEqual('Español');
|
expect(await element.getAttribute('innerText')).toEqual('Español expand_more');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should override the LANG OPTIONS', async () => {
|
it('should override the LANG OPTIONS', async () => {
|
||||||
await browser.get(`${url}&prejoin=true&langOptions=true`);
|
await browser.get(`${url}&prejoin=true&langOptions=true`);
|
||||||
|
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
await utils.waitForElement('#lang-btn-compact');
|
await utils.waitForElement('.language-selector');
|
||||||
await utils.clickOn('#lang-btn-compact');
|
await utils.clickOn('.language-selector');
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
expect(await utils.getNumberOfElements('.lang-menu-opt')).toEqual(2);
|
expect(await utils.getNumberOfElements('.language-option')).toEqual(2);
|
||||||
|
|
||||||
await utils.clickOn('.lang-menu-opt');
|
await utils.clickOn('.language-option');
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
|
|
||||||
await utils.clickOn('#join-button');
|
await utils.clickOn('#join-button');
|
||||||
|
@ -136,12 +136,12 @@ describe('Testing API Directives', () => {
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
|
|
||||||
await utils.waitForElement('#settings-container');
|
await utils.waitForElement('#settings-container');
|
||||||
await utils.waitForElement('.lang-button');
|
await utils.waitForElement('.full-lang-button');
|
||||||
await utils.clickOn('.lang-button');
|
await utils.clickOn('.full-lang-button');
|
||||||
|
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
|
|
||||||
expect(await utils.getNumberOfElements('.lang-menu-opt')).toEqual(2);
|
expect(await utils.getNumberOfElements('.language-option')).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the PREJOIN page', async () => {
|
it('should show the PREJOIN page', async () => {
|
||||||
|
|
|
@ -92,35 +92,12 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
expect(await utils.isPresent('#onVideoEnabledChanged-true')).toBeTrue();
|
expect(await utils.isPresent('#onVideoEnabledChanged-true')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should receive the onVideoEnabledChanged event when clicking on the settings panel', async () => {
|
|
||||||
await browser.get(`${url}&prejoin=false`);
|
|
||||||
|
|
||||||
await utils.checkSessionIsPresent();
|
|
||||||
|
|
||||||
await utils.checkToolbarIsPresent();
|
|
||||||
await utils.togglePanel('settings');
|
|
||||||
await browser.sleep(500);
|
|
||||||
|
|
||||||
await utils.waitForElement('#settings-container');
|
|
||||||
await utils.clickOn('#video-opt');
|
|
||||||
|
|
||||||
await utils.waitForElement('ov-video-devices-select');
|
|
||||||
await utils.clickOn('ov-video-devices-select #camera-button');
|
|
||||||
// Checking if onVideoEnabledChanged has been received
|
|
||||||
await utils.waitForElement('#onVideoEnabledChanged-false');
|
|
||||||
expect(await utils.isPresent('#onVideoEnabledChanged-false')).toBeTrue();
|
|
||||||
|
|
||||||
await utils.clickOn('ov-video-devices-select #camera-button');
|
|
||||||
await utils.waitForElement('#onVideoEnabledChanged-true');
|
|
||||||
expect(await utils.isPresent('#onVideoEnabledChanged-true')).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should receive the onVideoDeviceChanged event on prejoin', async () => {
|
it('should receive the onVideoDeviceChanged event on prejoin', async () => {
|
||||||
await browser.get(`${url}&fakeDevices=true`);
|
await browser.get(`${url}&fakeDevices=true`);
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
|
|
||||||
await utils.waitForElement('#video-devices-form');
|
await utils.waitForElement('#video-dropdown');
|
||||||
await utils.clickOn('#video-devices-form');
|
await utils.clickOn('#video-dropdown');
|
||||||
|
|
||||||
await utils.waitForElement('#option-custom_fake_video_1');
|
await utils.waitForElement('#option-custom_fake_video_1');
|
||||||
await utils.clickOn('#option-custom_fake_video_1');
|
await utils.clickOn('#option-custom_fake_video_1');
|
||||||
|
@ -142,8 +119,8 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
await utils.clickOn('#video-opt');
|
await utils.clickOn('#video-opt');
|
||||||
|
|
||||||
await utils.waitForElement('ov-video-devices-select');
|
await utils.waitForElement('ov-video-devices-select');
|
||||||
await utils.waitForElement('#video-devices-form');
|
await utils.waitForElement('#video-dropdown');
|
||||||
await utils.clickOn('#video-devices-form');
|
await utils.clickOn('#video-dropdown');
|
||||||
|
|
||||||
await utils.waitForElement('#option-custom_fake_video_1');
|
await utils.waitForElement('#option-custom_fake_video_1');
|
||||||
await utils.clickOn('#option-custom_fake_video_1');
|
await utils.clickOn('#option-custom_fake_video_1');
|
||||||
|
@ -184,35 +161,12 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
expect(await utils.isPresent('#onAudioEnabledChanged-true')).toBeTrue();
|
expect(await utils.isPresent('#onAudioEnabledChanged-true')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should receive the onAudioEnabledChanged event when clicking on the settings panel', async () => {
|
|
||||||
await browser.get(`${url}&prejoin=false`);
|
|
||||||
|
|
||||||
await utils.checkSessionIsPresent();
|
|
||||||
|
|
||||||
await utils.checkToolbarIsPresent();
|
|
||||||
await utils.togglePanel('settings');
|
|
||||||
await browser.sleep(500);
|
|
||||||
|
|
||||||
await utils.waitForElement('#settings-container');
|
|
||||||
await utils.clickOn('#audio-opt');
|
|
||||||
|
|
||||||
await utils.waitForElement('ov-audio-devices-select');
|
|
||||||
await utils.clickOn('ov-audio-devices-select #microphone-button');
|
|
||||||
// Checking if onAudioEnabledChanged has been received
|
|
||||||
await utils.waitForElement('#onAudioEnabledChanged-false');
|
|
||||||
expect(await utils.isPresent('#onAudioEnabledChanged-false')).toBeTrue();
|
|
||||||
|
|
||||||
await utils.clickOn('ov-audio-devices-select #microphone-button');
|
|
||||||
await utils.waitForElement('#onAudioEnabledChanged-true');
|
|
||||||
expect(await utils.isPresent('#onAudioEnabledChanged-true')).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should receive the onAudioDeviceChanged event on prejoin', async () => {
|
it('should receive the onAudioDeviceChanged event on prejoin', async () => {
|
||||||
await browser.get(`${url}&fakeDevices=true`);
|
await browser.get(`${url}&fakeDevices=true`);
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
|
|
||||||
await utils.waitForElement('#audio-devices-form');
|
await utils.waitForElement('#audio-dropdown');
|
||||||
await utils.clickOn('#audio-devices-form');
|
await utils.clickOn('#audio-dropdown');
|
||||||
|
|
||||||
await utils.waitForElement('#option-custom_fake_audio_1');
|
await utils.waitForElement('#option-custom_fake_audio_1');
|
||||||
await utils.clickOn('#option-custom_fake_audio_1');
|
await utils.clickOn('#option-custom_fake_audio_1');
|
||||||
|
@ -234,8 +188,8 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
await utils.clickOn('#audio-opt');
|
await utils.clickOn('#audio-opt');
|
||||||
|
|
||||||
await utils.waitForElement('ov-audio-devices-select');
|
await utils.waitForElement('ov-audio-devices-select');
|
||||||
await utils.waitForElement('#audio-devices-form');
|
await utils.waitForElement('#audio-dropdown');
|
||||||
await utils.clickOn('#audio-devices-form');
|
await utils.clickOn('#audio-dropdown');
|
||||||
|
|
||||||
await utils.waitForElement('#option-custom_fake_audio_1');
|
await utils.waitForElement('#option-custom_fake_audio_1');
|
||||||
await utils.clickOn('#option-custom_fake_audio_1');
|
await utils.clickOn('#option-custom_fake_audio_1');
|
||||||
|
@ -248,8 +202,8 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
await browser.get(`${url}`);
|
await browser.get(`${url}`);
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
|
|
||||||
await utils.waitForElement('#lang-btn-compact');
|
await utils.waitForElement('.language-selector');
|
||||||
await utils.clickOn('#lang-btn-compact');
|
await utils.clickOn('.language-selector');
|
||||||
|
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
await utils.clickOn('#lang-opt-es');
|
await utils.clickOn('#lang-opt-es');
|
||||||
|
@ -269,8 +223,8 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
|
|
||||||
await utils.waitForElement('#settings-container');
|
await utils.waitForElement('#settings-container');
|
||||||
await utils.waitForElement('.lang-button');
|
await utils.waitForElement('.full-lang-button');
|
||||||
await utils.clickOn('.lang-button');
|
await utils.clickOn('.full-lang-button');
|
||||||
|
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
await utils.clickOn('#lang-opt-es');
|
await utils.clickOn('#lang-opt-es');
|
||||||
|
@ -398,7 +352,7 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
expect(await utils.isPresent('#onSettingsPanelStatusChanged-false')).toBeTrue();
|
expect(await utils.isPresent('#onSettingsPanelStatusChanged-false')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should receive the onRecordingStartRequested event when clicking toolbar button', async () => {
|
fit('should receive the onRecordingStartRequested and onRecordingStopRequested event when clicking toolbar button', async () => {
|
||||||
const roomName = 'recordingToolbarEvent';
|
const roomName = 'recordingToolbarEvent';
|
||||||
await browser.get(`${url}&prejoin=false&roomName=${roomName}`);
|
await browser.get(`${url}&prejoin=false&roomName=${roomName}`);
|
||||||
|
|
||||||
|
@ -410,9 +364,15 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
// Checking if onRecordingStartRequested has been received
|
// Checking if onRecordingStartRequested has been received
|
||||||
await utils.waitForElement(`#onRecordingStartRequested-${roomName}`);
|
await utils.waitForElement(`#onRecordingStartRequested-${roomName}`);
|
||||||
expect(await utils.isPresent(`#onRecordingStartRequested-${roomName}`)).toBeTrue();
|
expect(await utils.isPresent(`#onRecordingStartRequested-${roomName}`)).toBeTrue();
|
||||||
});
|
|
||||||
|
|
||||||
xit('should receive the onRecordingStopRequested event when clicking toolbar button', async () => {});
|
await utils.waitForElement('.activity-status.started');
|
||||||
|
|
||||||
|
await utils.toggleRecordingFromToolbar();
|
||||||
|
|
||||||
|
// Checking if onRecordingStopRequested has been received
|
||||||
|
await utils.waitForElement(`#onRecordingStopRequested-${roomName}`);
|
||||||
|
expect(await utils.isPresent(`#onRecordingStopRequested-${roomName}`)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
xit('should receive the onBroadcastingStopRequested event when clicking toolbar button', async () => {
|
xit('should receive the onBroadcastingStopRequested event when clicking toolbar button', async () => {
|
||||||
await browser.get(`${url}&prejoin=false`);
|
await browser.get(`${url}&prejoin=false`);
|
||||||
|
@ -446,7 +406,7 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
expect(await utils.isPresent('#onBroadcastingStopRequested')).toBeTrue();
|
expect(await utils.isPresent('#onBroadcastingStopRequested')).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should receive the onRecordingStartRequested when clicking from activities panel', async () => {
|
it('should receive the onRecordingStartRequested and onRecordingStopRequested when clicking from activities panel', async () => {
|
||||||
const roomName = 'recordingActivitiesEvent';
|
const roomName = 'recordingActivitiesEvent';
|
||||||
await browser.get(`${url}&prejoin=false&roomName=${roomName}`);
|
await browser.get(`${url}&prejoin=false&roomName=${roomName}`);
|
||||||
|
|
||||||
|
@ -472,8 +432,6 @@ describe('Testing videoconference EVENTS', () => {
|
||||||
expect(await utils.isPresent(`#onRecordingStartRequested-${roomName}`)).toBeTrue();
|
expect(await utils.isPresent(`#onRecordingStartRequested-${roomName}`)).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
xit('should receive the onRecordingStopRequested when clicking from activities panel', async () => {});
|
|
||||||
|
|
||||||
xit('should receive the onRecordingDeleteRequested event', async () => {
|
xit('should receive the onRecordingDeleteRequested event', async () => {
|
||||||
let element;
|
let element;
|
||||||
const roomName = 'deleteRecordingEvent';
|
const roomName = 'deleteRecordingEvent';
|
||||||
|
|
|
@ -33,7 +33,7 @@ describe('Media Devices: Virtual Device Replacement and Permissions Handling', (
|
||||||
|
|
||||||
await browser.get(`${url}&fakeDevices=true`);
|
await browser.get(`${url}&fakeDevices=true`);
|
||||||
|
|
||||||
let videoDevices = await utils.waitForElement('#video-devices-form');
|
let videoDevices = await utils.waitForElement('#video-dropdown');
|
||||||
await videoDevices.click();
|
await videoDevices.click();
|
||||||
let element = await utils.waitForElement('#option-custom_fake_video_1');
|
let element = await utils.waitForElement('#option-custom_fake_video_1');
|
||||||
await element.click();
|
await element.click();
|
||||||
|
@ -63,7 +63,7 @@ describe('Media Devices: Virtual Device Replacement and Permissions Handling', (
|
||||||
await browser.sleep(500);
|
await browser.sleep(500);
|
||||||
await utils.clickOn('#video-opt');
|
await utils.clickOn('#video-opt');
|
||||||
expect(await utils.isPresent('ov-video-devices-select')).toBeTrue();
|
expect(await utils.isPresent('ov-video-devices-select')).toBeTrue();
|
||||||
let videoDevices = await utils.waitForElement('#video-devices-form');
|
let videoDevices = await utils.waitForElement('#video-dropdown');
|
||||||
await videoDevices.click();
|
await videoDevices.click();
|
||||||
let element = await utils.waitForElement('#option-custom_fake_video_1');
|
let element = await utils.waitForElement('#option-custom_fake_video_1');
|
||||||
await element.click();
|
await element.click();
|
||||||
|
@ -130,16 +130,15 @@ describe('Media Devices: UI Behavior Without Media Device Permissions', () => {
|
||||||
await browser.quit();
|
await browser.quit();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable camera and microphone buttons in the prejoin page when permissions are denied', async () => {
|
it('should camera and microphone buttons be disabled in the prejoin page when permissions are denied', async () => {
|
||||||
await browser.get(`${url}`);
|
await browser.get(`${url}`);
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
let button = await utils.waitForElement('#camera-button');
|
await utils.waitForElement('#no-video-device-message');
|
||||||
expect(await button.isEnabled()).toBeFalse();
|
await utils.waitForElement('#no-audio-device-message');
|
||||||
button = await utils.waitForElement('#microphone-button');
|
expect(await utils.isPresent('#backgrounds-button')).toBeFalse();
|
||||||
expect(await button.isEnabled()).toBeFalse();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable camera and microphone buttons in the room page when permissions are denied', async () => {
|
it('should camera and microphone buttons be disabled in the room page when permissions are denied', async () => {
|
||||||
await browser.get(`${url}`);
|
await browser.get(`${url}`);
|
||||||
await utils.checkPrejoinIsPresent();
|
await utils.checkPrejoinIsPresent();
|
||||||
await utils.clickOn('#join-button');
|
await utils.clickOn('#join-button');
|
||||||
|
@ -151,7 +150,7 @@ describe('Media Devices: UI Behavior Without Media Device Permissions', () => {
|
||||||
expect(await button.isEnabled()).toBeFalse();
|
expect(await button.isEnabled()).toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable camera and microphone buttons in the room page without prejoin when permissions are denied', async () => {
|
it('should camera and microphone buttons be disabled in the room page without prejoin when permissions are denied', async () => {
|
||||||
await browser.get(`${url}&prejoin=false`);
|
await browser.get(`${url}&prejoin=false`);
|
||||||
await utils.checkSessionIsPresent();
|
await utils.checkSessionIsPresent();
|
||||||
await utils.checkToolbarIsPresent();
|
await utils.checkToolbarIsPresent();
|
||||||
|
@ -161,7 +160,7 @@ describe('Media Devices: UI Behavior Without Media Device Permissions', () => {
|
||||||
expect(await button.isEnabled()).toBeFalse();
|
expect(await button.isEnabled()).toBeFalse();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should disable camera and microphone device selection buttons in settings when permissions are denied', async () => {
|
it('should show an audio and video device warning in settings when permissions are denied', async () => {
|
||||||
await browser.get(`${url}&prejoin=false`);
|
await browser.get(`${url}&prejoin=false`);
|
||||||
await utils.checkToolbarIsPresent();
|
await utils.checkToolbarIsPresent();
|
||||||
await utils.togglePanel('settings');
|
await utils.togglePanel('settings');
|
||||||
|
@ -170,11 +169,9 @@ describe('Media Devices: UI Behavior Without Media Device Permissions', () => {
|
||||||
expect(await utils.isPresent('.settings-container')).toBeTrue();
|
expect(await utils.isPresent('.settings-container')).toBeTrue();
|
||||||
await utils.clickOn('#video-opt');
|
await utils.clickOn('#video-opt');
|
||||||
expect(await utils.isPresent('ov-video-devices-select')).toBeTrue();
|
expect(await utils.isPresent('ov-video-devices-select')).toBeTrue();
|
||||||
let button = await utils.waitForElement('#camera-button');
|
await utils.waitForElement('#no-video-device-message');
|
||||||
expect(await button.isEnabled()).toBeFalse();
|
|
||||||
await utils.clickOn('#audio-opt');
|
await utils.clickOn('#audio-opt');
|
||||||
expect(await utils.isPresent('ov-audio-devices-select')).toBeTrue();
|
expect(await utils.isPresent('ov-audio-devices-select')).toBeTrue();
|
||||||
button = await utils.waitForElement('#microphone-button');
|
await utils.waitForElement('#no-audio-device-message');
|
||||||
expect(await button.isEnabled()).toBeFalse();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="prejoin-container" id="prejoin-container">
|
<div class="prejoin-container" id="prejoin-container" [class.name-error]="!!_error">
|
||||||
<!-- Top Language Toolbar -->
|
<!-- Top Language Toolbar -->
|
||||||
<div class="top-toolbar" *ngIf="!isMinimal">
|
<div class="top-toolbar" *ngIf="!isMinimal">
|
||||||
<ov-lang-selector [compact]="false" class="language-selector" (onLangChanged)="onLangChanged.emit($event)"> </ov-lang-selector>
|
<ov-lang-selector [compact]="false" class="language-selector" (onLangChanged)="onLangChanged.emit($event)"> </ov-lang-selector>
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
[compact]="true"
|
[compact]="true"
|
||||||
(onVideoDeviceChanged)="onVideoDeviceChanged.emit($event)"
|
(onVideoDeviceChanged)="onVideoDeviceChanged.emit($event)"
|
||||||
(onVideoEnabledChanged)="videoEnabledChanged($event)"
|
(onVideoEnabledChanged)="videoEnabledChanged($event)"
|
||||||
|
(onVideoDevicesLoaded)="onVideoDevicesLoaded($event)"
|
||||||
class="device-selector"
|
class="device-selector"
|
||||||
>
|
>
|
||||||
</ov-video-devices-select>
|
</ov-video-devices-select>
|
||||||
|
@ -57,17 +58,20 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Virtual Background Button -->
|
<!-- Virtual Background Button -->
|
||||||
<div class="background-control" *ngIf="backgroundEffectEnabled">
|
@if (backgroundEffectEnabled && hasVideoDevices) {
|
||||||
<button
|
<div class="background-control">
|
||||||
mat-icon-button
|
<button
|
||||||
class="background-button"
|
mat-icon-button
|
||||||
(click)="toggleBackgroundPanel()"
|
class="background-button"
|
||||||
[matTooltip]="'Virtual Backgrounds'"
|
(click)="toggleBackgroundPanel()"
|
||||||
[disabled]="!isVideoEnabled"
|
[matTooltip]="'Virtual Backgrounds'"
|
||||||
>
|
[disabled]="!isVideoEnabled"
|
||||||
<mat-icon class="material-symbols-outlined">background_replace</mat-icon>
|
id="backgrounds-button"
|
||||||
</button>
|
>
|
||||||
</div>
|
<mat-icon class="material-symbols-outlined">background_replace</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -81,7 +85,7 @@
|
||||||
<!-- Configuration Section -->
|
<!-- Configuration Section -->
|
||||||
<div class="configuration-section">
|
<div class="configuration-section">
|
||||||
<!-- Participant Name Input -->
|
<!-- Participant Name Input -->
|
||||||
<div class="input-section" *ngIf="showParticipantName">
|
<div class="participant-name-container input-section" *ngIf="showParticipantName">
|
||||||
<ov-participant-name-input
|
<ov-participant-name-input
|
||||||
[isPrejoinPage]="true"
|
[isPrejoinPage]="true"
|
||||||
[error]="!!_error"
|
[error]="!!_error"
|
||||||
|
@ -93,7 +97,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error Message -->
|
<!-- Error Message -->
|
||||||
<div *ngIf="!!_error" class="error-message">
|
<div *ngIf="!!_error" class="error-message" id="token-error">
|
||||||
<mat-icon class="error-icon">error_outline</mat-icon>
|
<mat-icon class="error-icon">error_outline</mat-icon>
|
||||||
<span class="error-text">{{ _error }}</span>
|
<span class="error-text">{{ _error }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,9 +108,9 @@
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
(click)="join()"
|
(click)="join()"
|
||||||
class="join-button"
|
class="join-button"
|
||||||
|
id="join-button"
|
||||||
[disabled]="showParticipantName && !participantName"
|
[disabled]="showParticipantName && !participantName"
|
||||||
>
|
>
|
||||||
<mat-icon class="join-icon">videocam</mat-icon>
|
|
||||||
{{ 'PREJOIN.JOIN' | translate }}
|
{{ 'PREJOIN.JOIN' | translate }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -14,6 +14,12 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.name-error {
|
||||||
|
.prejoin-main {
|
||||||
|
min-height: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.prejoin-content {
|
.prejoin-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
|
@ -103,6 +103,7 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
videoTrack: LocalTrack | undefined;
|
videoTrack: LocalTrack | undefined;
|
||||||
audioTrack: LocalTrack | undefined;
|
audioTrack: LocalTrack | undefined;
|
||||||
isVideoEnabled: boolean = false;
|
isVideoEnabled: boolean = false;
|
||||||
|
hasVideoDevices: boolean = true;
|
||||||
private tracks: LocalTrack[];
|
private tracks: LocalTrack[];
|
||||||
private log: ILogger;
|
private log: ILogger;
|
||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
@ -247,6 +248,10 @@ export class PreJoinComponent implements OnInit, OnDestroy {
|
||||||
this.onVideoEnabledChanged.emit(enabled);
|
this.onVideoEnabledChanged.emit(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onVideoDevicesLoaded(devices: CustomDevice[]) {
|
||||||
|
this.hasVideoDevices = devices.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
async audioEnabledChanged(enabled: boolean) {
|
async audioEnabledChanged(enabled: boolean) {
|
||||||
if (enabled && !this.audioTrack) {
|
if (enabled && !this.audioTrack) {
|
||||||
const newAudioTrack = await this.openviduService.createLocalTracks(false, true);
|
const newAudioTrack = await this.openviduService.createLocalTracks(false, true);
|
||||||
|
|
|
@ -1,28 +1,43 @@
|
||||||
<div class="audio-device-selector" [class.compact]="compact">
|
<div class="audio-device-selector" [class.compact]="compact">
|
||||||
<!-- Unified Device Button (Compact Mode) -->
|
<!-- Unified Device Button (Compact Mode) -->
|
||||||
@if (compact) {
|
@if (compact) {
|
||||||
<div class="unified-device-button">
|
@if (hasAudioDevices) {
|
||||||
<!-- Main toggle button -->
|
<div class="unified-device-button">
|
||||||
<button
|
<!-- Main toggle button -->
|
||||||
mat-flat-button
|
<button
|
||||||
class="toggle-section"
|
mat-flat-button
|
||||||
[disabled]="!hasAudioDevices || microphoneStatusChanging"
|
class="toggle-section"
|
||||||
[class.device-enabled]="isMicrophoneEnabled"
|
[disabled]="!hasAudioDevices || microphoneStatusChanging"
|
||||||
[class.device-disabled]="!isMicrophoneEnabled"
|
[class.device-enabled]="isMicrophoneEnabled"
|
||||||
(click)="toggleMic($event)"
|
[class.device-disabled]="!isMicrophoneEnabled"
|
||||||
[matTooltip]="isMicrophoneEnabled ? ('TOOLBAR.MUTE_AUDIO' | translate) : ('TOOLBAR.UNMUTE_AUDIO' | translate)"
|
(click)="toggleMic($event)"
|
||||||
[matTooltipDisabled]="!hasAudioDevices"
|
[matTooltip]="isMicrophoneEnabled ? ('TOOLBAR.MUTE_AUDIO' | translate) : ('TOOLBAR.UNMUTE_AUDIO' | translate)"
|
||||||
>
|
[matTooltipDisabled]="!hasAudioDevices"
|
||||||
<mat-icon>{{ isMicrophoneEnabled ? 'mic' : 'mic_off' }}</mat-icon>
|
id="microphone-button"
|
||||||
</button>
|
>
|
||||||
|
<mat-icon [id]="isMicrophoneEnabled ? 'mic' : 'mic_off'">{{ isMicrophoneEnabled ? 'mic' : 'mic_off' }}</mat-icon>
|
||||||
<!-- Dropdown section -->
|
|
||||||
@if (microphones.length > 1 && isMicrophoneEnabled) {
|
|
||||||
<button mat-flat-button class="dropdown-section" [matMenuTriggerFor]="microphoneMenu" [disabled]="microphoneStatusChanging">
|
|
||||||
<mat-icon>expand_more</mat-icon>
|
|
||||||
</button>
|
</button>
|
||||||
}
|
|
||||||
</div>
|
<!-- Dropdown section -->
|
||||||
|
@if (isMicrophoneEnabled) {
|
||||||
|
<button
|
||||||
|
mat-flat-button
|
||||||
|
id="audio-dropdown"
|
||||||
|
class="dropdown-section"
|
||||||
|
[matMenuTriggerFor]="microphoneMenu"
|
||||||
|
[disabled]="microphoneStatusChanging"
|
||||||
|
>
|
||||||
|
<mat-icon>expand_more</mat-icon>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<!-- No Microphone Available -->
|
||||||
|
<div id="no-audio-device-message" class="no-device-message">
|
||||||
|
<mat-icon class="warning-icon">warning</mat-icon>
|
||||||
|
<span>{{ 'PREJOIN.NO_AUDIO_DEVICE' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
} @else {
|
} @else {
|
||||||
<!-- Normal Mode - Input Style Selector -->
|
<!-- Normal Mode - Input Style Selector -->
|
||||||
<div class="normal-device-selector">
|
<div class="normal-device-selector">
|
||||||
|
@ -33,6 +48,7 @@
|
||||||
<div class="device-input-selector">
|
<div class="device-input-selector">
|
||||||
<button
|
<button
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
|
id="audio-dropdown"
|
||||||
class="selector-button"
|
class="selector-button"
|
||||||
[disabled]="microphoneStatusChanging || microphones.length <= 1"
|
[disabled]="microphoneStatusChanging || microphones.length <= 1"
|
||||||
[matMenuTriggerFor]="microphoneMenu"
|
[matMenuTriggerFor]="microphoneMenu"
|
||||||
|
@ -44,24 +60,34 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<!-- When microphone is disabled -->
|
@if (hasAudioDevices) {
|
||||||
<div class="device-input-selector disabled">
|
<!-- When microphone is disabled -->
|
||||||
<div class="selector-button disabled">
|
<div class="device-input-selector disabled">
|
||||||
<mat-icon class="device-icon">mic_off</mat-icon>
|
<div class="selector-button disabled">
|
||||||
<span class="selected-device-name">
|
<mat-icon class="device-icon">mic_off</mat-icon>
|
||||||
{{ !hasAudioDevices ? ('PREJOIN.NO_AUDIO_DEVICE' | translate) : 'Microphone disabled' }}
|
<span class="selected-device-name">
|
||||||
</span>
|
{{ !hasAudioDevices ? ('PREJOIN.NO_AUDIO_DEVICE' | translate) : 'Microphone disabled' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @else {
|
||||||
|
<!-- No Microphone Available -->
|
||||||
|
<div id="no-audio-device-message" class="no-device-message">
|
||||||
|
<mat-icon class="warning-icon">warning</mat-icon>
|
||||||
|
<span>{{ 'PREJOIN.NO_AUDIO_DEVICE' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<!-- Device Selection Menu (Shared) -->
|
<!-- Device Selection Menu (Shared) -->
|
||||||
<mat-menu #microphoneMenu="matMenu" class="device-menu">
|
<mat-menu #microphoneMenu="matMenu" class="device-menu">
|
||||||
@for (microphone of microphones; track microphone.device) {
|
@for (microphone of microphones; track microphone.device) {
|
||||||
<button
|
<button
|
||||||
mat-menu-item
|
mat-menu-item
|
||||||
|
id="option-{{ microphone.label }}"
|
||||||
(click)="onMicrophoneSelected({ value: microphone })"
|
(click)="onMicrophoneSelected({ value: microphone })"
|
||||||
[class.selected]="microphone.device === microphoneSelected.device"
|
[class.selected]="microphone.device === microphoneSelected.device"
|
||||||
>
|
>
|
||||||
|
@ -70,12 +96,4 @@
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<!-- No Microphone Available -->
|
|
||||||
@if (microphones.length === 0) {
|
|
||||||
<div class="no-device-message">
|
|
||||||
<mat-icon class="warning-icon">warning</mat-icon>
|
|
||||||
<span>{{ 'PREJOIN.NO_AUDIO_DEVICE' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,28 +1,45 @@
|
||||||
<div class="video-device-selector" [class.compact]="compact">
|
<div class="video-device-selector" [class.compact]="compact">
|
||||||
<!-- Unified Device Button (Compact Mode) -->
|
<!-- Unified Device Button (Compact Mode) -->
|
||||||
@if (compact) {
|
@if (compact) {
|
||||||
<div class="unified-device-button">
|
@if (hasVideoDevices) {
|
||||||
<!-- Main toggle button -->
|
<div class="unified-device-button">
|
||||||
<button
|
<!-- Main toggle button -->
|
||||||
mat-flat-button
|
<button
|
||||||
class="toggle-section"
|
mat-flat-button
|
||||||
[disabled]="!hasVideoDevices || cameraStatusChanging"
|
class="toggle-section"
|
||||||
[class.device-enabled]="isCameraEnabled"
|
[disabled]="!hasVideoDevices || cameraStatusChanging"
|
||||||
[class.device-disabled]="!isCameraEnabled"
|
[class.device-enabled]="isCameraEnabled"
|
||||||
(click)="toggleCam($event)"
|
[class.device-disabled]="!isCameraEnabled"
|
||||||
[matTooltip]="isCameraEnabled ? ('TOOLBAR.STOP_VIDEO' | translate) : ('TOOLBAR.START_VIDEO' | translate)"
|
(click)="toggleCam($event)"
|
||||||
[matTooltipDisabled]="!hasVideoDevices"
|
[matTooltip]="isCameraEnabled ? ('TOOLBAR.STOP_VIDEO' | translate) : ('TOOLBAR.START_VIDEO' | translate)"
|
||||||
>
|
[matTooltipDisabled]="!hasVideoDevices"
|
||||||
<mat-icon>{{ isCameraEnabled ? 'videocam' : 'videocam_off' }}</mat-icon>
|
id="camera-button"
|
||||||
</button>
|
>
|
||||||
|
<mat-icon [id]="isCameraEnabled ? 'videocam' : 'videocam_off'">
|
||||||
<!-- Dropdown section -->
|
{{ isCameraEnabled ? 'videocam' : 'videocam_off' }}
|
||||||
@if (isCameraEnabled && cameras.length > 1) {
|
</mat-icon>
|
||||||
<button mat-flat-button class="dropdown-section" [matMenuTriggerFor]="cameraMenu" [disabled]="cameraStatusChanging">
|
|
||||||
<mat-icon>expand_more</mat-icon>
|
|
||||||
</button>
|
</button>
|
||||||
}
|
|
||||||
</div>
|
<!-- Dropdown section -->
|
||||||
|
@if (isCameraEnabled) {
|
||||||
|
<button
|
||||||
|
mat-flat-button
|
||||||
|
id="video-dropdown"
|
||||||
|
class="dropdown-section"
|
||||||
|
[matMenuTriggerFor]="cameraMenu"
|
||||||
|
[disabled]="cameraStatusChanging"
|
||||||
|
>
|
||||||
|
<mat-icon>expand_more</mat-icon>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
} @else {
|
||||||
|
<!-- No Camera Available -->
|
||||||
|
<div id="no-video-device-message" class="no-device-message">
|
||||||
|
<mat-icon class="warning-icon">warning</mat-icon>
|
||||||
|
<span>{{ 'PREJOIN.NO_VIDEO_DEVICE' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
} @else {
|
} @else {
|
||||||
<!-- Normal Mode - Input-style Selector -->
|
<!-- Normal Mode - Input-style Selector -->
|
||||||
<div class="normal-device-selector">
|
<div class="normal-device-selector">
|
||||||
|
@ -31,6 +48,7 @@
|
||||||
<div class="device-input-selector">
|
<div class="device-input-selector">
|
||||||
<button
|
<button
|
||||||
mat-flat-button
|
mat-flat-button
|
||||||
|
id="video-dropdown"
|
||||||
class="selector-button"
|
class="selector-button"
|
||||||
[matMenuTriggerFor]="cameraMenu"
|
[matMenuTriggerFor]="cameraMenu"
|
||||||
[disabled]="cameraStatusChanging || cameras.length <= 1"
|
[disabled]="cameraStatusChanging || cameras.length <= 1"
|
||||||
|
@ -41,13 +59,21 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<!-- Disabled state message -->
|
@if (hasVideoDevices) {
|
||||||
<div class="device-input-selector disabled">
|
<!-- Disabled state message -->
|
||||||
<div class="selector-button disabled">
|
<div class="device-input-selector disabled">
|
||||||
<mat-icon class="device-icon">videocam_off</mat-icon>
|
<div class="selector-button disabled">
|
||||||
<span class="selected-device-name">{{ 'PANEL.SETTINGS.DISABLED_VIDEO' | translate }}</span>
|
<mat-icon class="device-icon">videocam_off</mat-icon>
|
||||||
|
<span class="selected-device-name">{{ 'PANEL.SETTINGS.DISABLED_VIDEO' | translate }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
} @else {
|
||||||
|
<!-- No Camera Available -->
|
||||||
|
<div id="no-video-device-message" class="no-device-message">
|
||||||
|
<mat-icon class="warning-icon">warning</mat-icon>
|
||||||
|
<span>{{ 'PREJOIN.NO_VIDEO_DEVICE' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -55,18 +81,15 @@
|
||||||
<!-- Device Selection Menu (Shared) -->
|
<!-- Device Selection Menu (Shared) -->
|
||||||
<mat-menu #cameraMenu="matMenu" class="device-menu">
|
<mat-menu #cameraMenu="matMenu" class="device-menu">
|
||||||
@for (camera of cameras; track camera.device) {
|
@for (camera of cameras; track camera.device) {
|
||||||
<button mat-menu-item (click)="onCameraSelected({ value: camera })" [class.selected]="camera.device === cameraSelected?.device">
|
<button
|
||||||
|
mat-menu-item
|
||||||
|
id="option-{{ camera.label }}"
|
||||||
|
(click)="onCameraSelected({ value: camera })"
|
||||||
|
[class.selected]="camera.device === cameraSelected?.device"
|
||||||
|
>
|
||||||
<mat-icon *ngIf="camera.device === cameraSelected?.device" class="check-icon">check</mat-icon>
|
<mat-icon *ngIf="camera.device === cameraSelected?.device" class="check-icon">check</mat-icon>
|
||||||
<span>{{ camera.label }}</span>
|
<span>{{ camera.label }}</span>
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
|
|
||||||
<!-- No Camera Available -->
|
|
||||||
@if (cameras.length === 0) {
|
|
||||||
<div class="no-device-message">
|
|
||||||
<mat-icon class="warning-icon">warning</mat-icon>
|
|
||||||
<span>{{ 'PREJOIN.NO_VIDEO_DEVICE' | translate }}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -19,6 +19,7 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
|
||||||
@Input() compact: boolean = false;
|
@Input() compact: boolean = false;
|
||||||
@Output() onVideoDeviceChanged = new EventEmitter<CustomDevice>();
|
@Output() onVideoDeviceChanged = new EventEmitter<CustomDevice>();
|
||||||
@Output() onVideoEnabledChanged = new EventEmitter<boolean>();
|
@Output() onVideoEnabledChanged = new EventEmitter<boolean>();
|
||||||
|
@Output() onVideoDevicesLoaded = new EventEmitter<CustomDevice[]>();
|
||||||
|
|
||||||
cameraStatusChanging: boolean;
|
cameraStatusChanging: boolean;
|
||||||
isCameraEnabled: boolean;
|
isCameraEnabled: boolean;
|
||||||
|
@ -42,6 +43,7 @@ export class VideoDevicesComponent implements OnInit, OnDestroy {
|
||||||
this.cameraSelected = this.deviceSrv.getCameraSelected();
|
this.cameraSelected = this.deviceSrv.getCameraSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.onVideoDevicesLoaded.emit(this.cameras);
|
||||||
this.isCameraEnabled = this.participantService.isMyCameraEnabled();
|
this.isCameraEnabled = this.participantService.isMyCameraEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue