diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.html new file mode 100644 index 00000000..02b926ee --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.html @@ -0,0 +1,188 @@ + +@if (showCameraButton) { + +} + + +@if (showMicrophoneButton) { + +} + + +@if (!isMinimal && showScreenshareButton) { + + + + + + + + +} + + + + + + +@if (!isMinimal && showMoreOptionsButton) { + + + + @if (showFullscreenButton) { + + } + + + @if (showRecordingButton) { + + } + + + @if (showViewRecordingsButton) { + + } + + + @if (showBroadcastingButton) { + + } + + + @if (showBackgroundEffectsButton) { + + } + + + + + + @if (showSettingsButton) { + + } + + + @if (showSettingsButton) { + + } + +} + + + + + + + +@if (showLeaveButton) { + +} diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.scss b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.scss new file mode 100644 index 00000000..dbb5f9b0 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.scss @@ -0,0 +1,123 @@ +:host { + display: flex; + justify-content: center; + align-items: center; + + .mat-mdc-icon-button { + --mat-mdc-button-persistent-ripple-color: transparent !important; + --mat-mdc-button-ripple-color: transparent !important; + } + + mat-icon { + font-size: 24px; + } + + button { + border-radius: var(--ov-toolbar-buttons-radius); + color: var(--ov-secondary-action-color); + + &.disabled { + background-color: var(--ov-error-color) !important; + color: #fff !important; + } + } + + button:not(mat-menu-item), + button:not(.mat-mdc-menu-item) ::ng-deep button:not(mat-menu-item), + ::ng-deep button:not(#screenshare-menu) { + background-color: var(--ov-primary-action-color); + color: var(--ov-secondary-action-color); + margin: 6px; + } + + #screenshare-menu { + } + + #disable-screen-button > mat-icon { + color: var(--ov-error-color) !important; + } + + .active-btn, + ::ng-deep .active-btn { + background-color: var(--ov-accent-action-color) !important; + } + + #leave-btn { + background-color: var(--ov-error-color) !important; + border-radius: var(--ov-leave-button-radius) !important; + width: 65px !important; + color: #ffffff !important; + } + + .mat-mdc-icon-button[disabled] { + color: #fff; + } + + .divider { + margin: 8px 0px; + } + + .blink { + animation: blinker 1.5s linear infinite; + } + + /* Animation for general blinking */ + @keyframes blinker { + 50% { + opacity: 0.3; + } + } + + ::ng-deep .mat-badge-content { + background-color: var(--ov-warn-color); + } + + ::ng-deep .mat-mdc-menu-item { + height: 40px; + line-height: 40px; + color: var(--ov-text-surface-color) !important; + } + + ::ng-deep .mat-mdc-menu-item mat-icon { + color: var(--ov-text-surface-color) !important; + } + + ::ng-deep #toolbar-broadcasting-btn > .mat-icon { + color: var(--ov-broadcasting-color) !important; + } + + ::ng-deep #recording-btn > .mat-icon { + color: var(--ov-recording-color) !important; + } + + ::ng-deep .mat-mdc-menu-panel { + border-radius: var(--ov-surface-radius) !important; + background-color: var(--ov-surface-color) !important; + box-shadow: var(--ov-border-shadow) !important; + } + + /* Styles for XS screens */ + @media (max-width: 599px) { + /* Animation for recording blinking */ + @keyframes blinker-recording { + 50% { + background-color: var(--ov-recording-color); + } + } + + /* Animation for broadcasting blinking */ + @keyframes blinker-broadcasting { + 50% { + background-color: var(--ov-broadcasting-color); + } + } + + /* Apply blinking animations to buttons */ + .blinking-broadcasting-button { + animation: blinker-broadcasting 1.5s linear infinite; + } + .blinking-recording-button { + animation: blinker-recording 1.5s linear infinite; + } + } +} diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.spec.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.spec.ts new file mode 100644 index 00000000..b3767c04 --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ToolbarMediaButtonsComponent } from './toolbar-media-buttons.component'; + +describe('ToolbarMediaButtonsComponent', () => { + let component: ToolbarMediaButtonsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ToolbarMediaButtonsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ToolbarMediaButtonsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.ts new file mode 100644 index 00000000..05ebfa2b --- /dev/null +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component.ts @@ -0,0 +1,140 @@ +import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core'; +import { RecordingStatus } from '../../../models/recording.model'; +import { BroadcastingStatus } from '../../../models/broadcasting.model'; +import { ToolbarAdditionalButtonsPosition } from '../../../models/toolbar.model'; + +@Component({ + selector: 'ov-toolbar-media-buttons', + templateUrl: './toolbar-media-buttons.component.html', + styleUrl: './toolbar-media-buttons.component.scss', + standalone: false +}) +export class ToolbarMediaButtonsComponent { + + // Camera related inputs + @Input() showCameraButton: boolean = true; + @Input() isCameraEnabled: boolean = true; + @Input() cameraMuteChanging: boolean = false; + + // Microphone related inputs + @Input() showMicrophoneButton: boolean = true; + @Input() isMicrophoneEnabled: boolean = true; + @Input() microphoneMuteChanging: boolean = false; + + // Screenshare related inputs + @Input() showScreenshareButton: boolean = true; + @Input() isScreenShareEnabled: boolean = false; + + // Device availability inputs + @Input() hasVideoDevices: boolean = true; + @Input() hasAudioDevices: boolean = true; + + // Connection state inputs + @Input() isConnectionLost: boolean = false; + + // UI state inputs + @Input() isMinimal: boolean = false; + + // More options menu inputs + @Input() showMoreOptionsButton: boolean = true; + @Input() showFullscreenButton: boolean = true; + @Input() showRecordingButton: boolean = true; + @Input() showViewRecordingsButton: boolean = false; + @Input() showBroadcastingButton: boolean = true; + @Input() showBackgroundEffectsButton: boolean = true; + @Input() showCaptionsButton: boolean = true; + @Input() showSettingsButton: boolean = true; + + // Fullscreen state + @Input() isFullscreenActive: boolean = false; + + // Recording related inputs + @Input() recordingStatus: RecordingStatus = RecordingStatus.STOPPED; + @Input() hasRoomTracksPublished: boolean = false; + + // Broadcasting related inputs + @Input() broadcastingStatus: BroadcastingStatus = BroadcastingStatus.STOPPED; + + // Captions + @Input() captionsEnabled: boolean = false; + + // Leave button + @Input() showLeaveButton: boolean = true; + + // Additional buttons template + @Input() toolbarAdditionalButtonsTemplate: TemplateRef | null = null; + @Input() additionalButtonsPosition: ToolbarAdditionalButtonsPosition | undefined; + + // Status enums for template usage + _recordingStatus = RecordingStatus; + _broadcastingStatus = BroadcastingStatus; + + // Media button outputs + @Output() cameraToggled = new EventEmitter(); + @Output() microphoneToggled = new EventEmitter(); + @Output() screenShareToggled = new EventEmitter(); + @Output() screenTrackReplaced = new EventEmitter(); + + // More options menu outputs + @Output() fullscreenToggled = new EventEmitter(); + @Output() recordingToggled = new EventEmitter(); + @Output() viewRecordingsClicked = new EventEmitter(); + @Output() broadcastingToggled = new EventEmitter(); + @Output() backgroundEffectsToggled = new EventEmitter(); + @Output() captionsToggled = new EventEmitter(); + @Output() settingsToggled = new EventEmitter(); + + // Leave button output + @Output() leaveClicked = new EventEmitter(); + + // Event handler methods + onCameraToggle(): void { + this.cameraToggled.emit(); + } + + onMicrophoneToggle(): void { + this.microphoneToggled.emit(); + } + + onScreenShareToggle(): void { + this.screenShareToggled.emit(); + } + + onScreenTrackReplace(): void { + this.screenTrackReplaced.emit(); + } + + onFullscreenToggle(): void { + this.fullscreenToggled.emit(); + } + + onRecordingToggle(): void { + this.recordingToggled.emit(); + } + + onViewRecordingsClick(): void { + this.viewRecordingsClicked.emit(); + } + + onBroadcastingToggle(): void { + this.broadcastingToggled.emit(); + } + + onBackgroundEffectsToggle(): void { + this.backgroundEffectsToggled.emit(); + } + + onCaptionsToggle(): void { + this.captionsToggled.emit(); + } + + onSettingsToggle(): void { + this.settingsToggled.emit(); + } + + onLeaveClick(): void { + this.leaveClicked.emit(); + } + + +} diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.html index 53b51885..8034f36a 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.html +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.html @@ -40,203 +40,48 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @if (!isMinimal && showViewRecordingsButton) { - - } - - - - - - - - - - - - - - - - - - - - - - - +
diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.scss b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.scss index 7c9a7e37..65704079 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.scss +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.scss @@ -30,6 +30,13 @@ display: flex; justify-content: center; align-items: center; + + // ov-toolbar-media-buttons { + // display: flex; + // justify-content: center; + // align-items: center; + // flex: 1; + // } } .menu-buttons-container { flex: 20%; @@ -47,40 +54,9 @@ max-height: 100% !important; } - #media-buttons-container mat-icon { - font-size: 24px; - } - - #media-buttons-container button, #menu-buttons-container button { border-radius: var(--ov-toolbar-buttons-radius); color: var(--ov-secondary-action-color); - - &.disabled { - background-color: var(--ov-error-color) !important; - color: #fff !important; - } - } - - #media-buttons-container > button, - ::ng-deep #media-buttons-container > button, - #media-buttons-container:not(#media-buttons-container > button) button, - /* Applying css for external additional buttons*/ - ::ng-deep #media-buttons-container:not(#media-buttons-container > button) button { - // width: 40px; - // height: 40px; - background-color: var(--ov-primary-action-color); - color: var(--ov-secondary-action-color); - margin: 6px; - } - - #disable-screen-button > mat-icon { - color: var(--ov-error-color) !important; - } - - .active-btn, - ::ng-deep .active-btn { - background-color: var(--ov-accent-action-color) !important; } #branding-logo { @@ -146,34 +122,11 @@ animation: blinker 1.5s linear infinite; } - #leave-btn { - background-color: var(--ov-error-color) !important; - border-radius: var(--ov-leave-button-radius) !important; - width: 65px !important; - color: #ffffff !important; - } - .mat-mdc-icon-button[disabled] { - color: #fff; - } + ::ng-deep .mat-badge-content { background-color: var(--ov-warn-color); } - .divider { - margin: 8px 0px; - } - ::ng-deep .mat-mdc-menu-item { - /* margin-bottom: 10px; */ - height: 40px; - line-height: 40px; - } - - /* Animation for general blinking */ - @keyframes blinker { - 50% { - opacity: 0.3; - } - } /* Styles for XS screens */ @media (max-width: 599px) { diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts index 52e15c5e..4eeb85aa 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar.component.ts @@ -651,16 +651,16 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { /** * @ignore */ - // toggleCaptions() { - // if (this.openviduService.isOpenViduPro()) { - // this.layoutService.toggleCaptions(); - // } else { - // this.actionService.openProFeatureDialog( - // this.translateService.translate('PANEL.SETTINGS.CAPTIONS'), - // this.translateService.translate('PANEL.PRO_FEATURE') - // ); - // } - // } + onCaptionsToggle() { + // if (this.openviduService.isOpenViduPro()) { + // this.layoutService.toggleCaptions(); + // } else { + // this.actionService.openProFeatureDialog( + // this.translateService.translate('PANEL.SETTINGS.CAPTIONS'), + // this.translateService.translate('PANEL.PRO_FEATURE') + // ); + // } + } /** * @ignore diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts index 97b4e01a..6a391d56 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/openvidu-components-angular-ui.module.ts @@ -11,6 +11,7 @@ import { ChatPanelComponent } from './components/panel/chat-panel/chat-panel.com import { SessionComponent } from './components/session/session.component'; import { StreamComponent } from './components/stream/stream.component'; import { ToolbarComponent } from './components/toolbar/toolbar.component'; +import { ToolbarMediaButtonsComponent } from './components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component'; import { MediaElementComponent } from './components/media-element/media-element.component'; import { LinkifyPipe } from './pipes/linkify.pipe'; @@ -76,7 +77,8 @@ const privateComponents = [ VideoDevicesComponent, AudioDevicesComponent, ParticipantNameInputComponent, - LangSelectorComponent + LangSelectorComponent, + ToolbarMediaButtonsComponent ]; @NgModule({ diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts index 217d849c..3a87cb87 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/public-api.ts @@ -15,6 +15,7 @@ export * from './lib/components/panel/participants-panel/participant-panel-item/ export * from './lib/components/panel/participants-panel/participants-panel/participants-panel.component'; export * from './lib/components/stream/stream.component'; export * from './lib/components/toolbar/toolbar.component'; +export * from './lib/components/toolbar/toolbar-media-buttons/toolbar-media-buttons.component'; export * from './lib/components/videoconference/videoconference.component'; export * from './lib/config/openvidu-components-angular.config'; // Directives