ov-components: implement showThemeSelector directive and integrate theme selector functionality

master
Carlos Santos 2025-09-25 17:03:07 +02:00
parent 0cdb46a79c
commit fe97022182
8 changed files with 87 additions and 11 deletions

View File

@ -81,4 +81,17 @@ describe('Testing Internal Directives', () => {
await utils.clickOn('#recording-activity'); await utils.clickOn('#recording-activity');
expect(await utils.isPresent('#start-recording-btn')).toBeTrue(); expect(await utils.isPresent('#start-recording-btn')).toBeTrue();
}); });
it('should show/hide theme selector with showThemeSelector directive', async () => {
await browser.get(`${url}&prejoin=false&showThemeSelector=true`);
await utils.checkSessionIsPresent();
await utils.toggleToolbarMoreOptions();
expect(await utils.isPresent('.theme-selector-container')).toBeTrue();
await browser.get(`${url}&prejoin=false`);
await browser.navigate().refresh();
await utils.checkSessionIsPresent();
await utils.toggleToolbarMoreOptions();
expect(await utils.isPresent('.theme-selector-container')).toBeFalse();
});
}); });

View File

@ -82,6 +82,7 @@
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>
</div> </div>
@if (showThemeSelector) {
<div class="theme-section"> <div class="theme-section">
<mat-list> <mat-list>
<mat-list-item class="theme-selector"> <mat-list-item class="theme-selector">
@ -91,6 +92,7 @@
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>
</div> </div>
}
</div> </div>
<div *ngIf="showCameraButton && selectedOption === settingsOptions.VIDEO" class="video-settings"> <div *ngIf="showCameraButton && selectedOption === settingsOptions.VIDEO" class="video-settings">
<ov-video-devices-select <ov-video-devices-select

View File

@ -28,6 +28,7 @@ export class SettingsPanelComponent implements OnInit {
showCameraButton: boolean = true; showCameraButton: boolean = true;
showMicrophoneButton: boolean = true; showMicrophoneButton: boolean = true;
showCaptions: boolean = true; showCaptions: boolean = true;
showThemeSelector: boolean = false;
isMobile: boolean = false; isMobile: boolean = false;
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
@ -72,6 +73,7 @@ export class SettingsPanelComponent implements OnInit {
this.libService.cameraButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showCameraButton = value)); this.libService.cameraButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showCameraButton = value));
this.libService.microphoneButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showMicrophoneButton = value)); this.libService.microphoneButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showMicrophoneButton = value));
this.libService.captionsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showCaptions = value)); this.libService.captionsButton$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showCaptions = value));
this.libService.showThemeSelector$.pipe(takeUntil(this.destroy$)).subscribe((value: boolean) => (this.showThemeSelector = value));
} }
private subscribeToPanelToggling() { private subscribeToPanelToggling() {

View File

@ -17,7 +17,8 @@ import {
StartStopRecordingButtonsDirective, StartStopRecordingButtonsDirective,
RecordingActivityViewRecordingsButtonDirective, RecordingActivityViewRecordingsButtonDirective,
RecordingActivityShowRecordingsListDirective, RecordingActivityShowRecordingsListDirective,
ToolbarRoomNameDirective ToolbarRoomNameDirective,
ShowThemeSelectorDirective
} from './internals.directive'; } from './internals.directive';
import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive'; import { ParticipantPanelItemMuteButtonDirective } from './participant-panel-item.directive';
import { import {
@ -111,7 +112,8 @@ const directives = [
StartStopRecordingButtonsDirective, StartStopRecordingButtonsDirective,
RecordingActivityViewRecordingsButtonDirective, RecordingActivityViewRecordingsButtonDirective,
RecordingActivityShowRecordingsListDirective, RecordingActivityShowRecordingsListDirective,
ToolbarRoomNameDirective ToolbarRoomNameDirective,
ShowThemeSelectorDirective
]; ];
@NgModule({ @NgModule({

View File

@ -524,3 +524,49 @@ export class ToolbarRoomNameDirective implements AfterViewInit, OnDestroy {
this.libService.updateToolbarConfig({ roomName: this._roomName || '' }); this.libService.updateToolbarConfig({ roomName: this._roomName || '' });
} }
} }
/**
* @internal
*
* The **showThemeSelector** directive allows to enable or disable the theme selector control.
* When disabled, users won't be able to change the UI theme.
*
* Default: `false`
*
* Usage:
* <ov-videoconference [showThemeSelector]="false"></ov-videoconference>
*/
@Directive({
selector: 'ov-videoconference[showThemeSelector]',
standalone: false
})
export class ShowThemeSelectorDirective implements AfterViewInit, OnDestroy {
@Input() set showThemeSelector(value: boolean) {
this._value = value;
this.update(this._value);
}
private _value: boolean = false;
constructor(
public elementRef: ElementRef,
private libService: OpenViduComponentsConfigService
) {}
ngAfterViewInit() {
this.update(this._value);
}
ngOnDestroy(): void {
this.clear();
}
private clear() {
this._value = true;
this.update(this._value);
}
private update(value: boolean) {
this.libService.updateGeneralConfig({ showThemeSelector: value });
}
}

View File

@ -94,6 +94,7 @@ interface GeneralConfig {
prejoin: boolean; prejoin: boolean;
prejoinDisplayParticipantName: boolean; prejoinDisplayParticipantName: boolean;
showDisconnectionDialog: boolean; showDisconnectionDialog: boolean;
showThemeSelector: boolean;
recordingStreamBaseUrl: string; recordingStreamBaseUrl: string;
} }
@ -300,6 +301,7 @@ export class OpenViduComponentsConfigService {
prejoin: true, prejoin: true,
prejoinDisplayParticipantName: true, prejoinDisplayParticipantName: true,
showDisconnectionDialog: true, showDisconnectionDialog: true,
showThemeSelector: false,
recordingStreamBaseUrl: 'call/api/recordings' recordingStreamBaseUrl: 'call/api/recordings'
}); });
@ -400,6 +402,12 @@ export class OpenViduComponentsConfigService {
distinctUntilChanged(), distinctUntilChanged(),
shareReplay(1) shareReplay(1)
); );
showThemeSelector$: Observable<boolean> = this.generalConfig.observable$.pipe(
map((config) => config.showThemeSelector),
distinctUntilChanged(),
shareReplay(1)
);
recordingStreamBaseUrl$: Observable<string> = this.generalConfig.observable$.pipe( recordingStreamBaseUrl$: Observable<string> = this.generalConfig.observable$.pipe(
map((config) => config.recordingStreamBaseUrl), map((config) => config.recordingStreamBaseUrl),
distinctUntilChanged(), distinctUntilChanged(),

View File

@ -12,6 +12,7 @@
[participantName]="participantName" [participantName]="participantName"
[videoEnabled]="videoEnabled" [videoEnabled]="videoEnabled"
[audioEnabled]="audioEnabled" [audioEnabled]="audioEnabled"
[showThemeSelector]="showThemeSelector"
[toolbarCameraButton]="toolbarCameraButton" [toolbarCameraButton]="toolbarCameraButton"
[toolbarMicrophoneButton]="toolbarMicrophoneButton" [toolbarMicrophoneButton]="toolbarMicrophoneButton"
[toolbarScreenshareButton]="toolbarScreenshareButton" [toolbarScreenshareButton]="toolbarScreenshareButton"

View File

@ -66,6 +66,7 @@ export class CallComponent implements OnInit {
public recordingActivityStartStopRecordingButton: boolean = true; public recordingActivityStartStopRecordingButton: boolean = true;
toolbarViewRecordingsButton: boolean = false; toolbarViewRecordingsButton: boolean = false;
private redirectToHomeOnLeaves: boolean = true; private redirectToHomeOnLeaves: boolean = true;
private showThemeSelector: boolean = false;
private staticVideos = [ private staticVideos = [
'https://videos.pexels.com/video-files/4089575/4089575-hd_1280_720_50fps.mp4', 'https://videos.pexels.com/video-files/4089575/4089575-hd_1280_720_50fps.mp4',
@ -159,6 +160,7 @@ export class CallComponent implements OnInit {
} else { } else {
this.redirectToHomeOnLeaves = params['redirectToHome'] === 'true'; this.redirectToHomeOnLeaves = params['redirectToHome'] === 'true';
} }
if(params['showThemeSelector'] !== undefined) this.showThemeSelector = params['showThemeSelector'] === 'true';
this.configReady = true; this.configReady = true;
if (this.areStaticVideosEnabled) { if (this.areStaticVideosEnabled) {