From 703403f18207a1d7286fc910011cc47036e0c40a Mon Sep 17 00:00:00 2001 From: Carlos Santos <4a.santos@gmail.com> Date: Mon, 22 Dec 2025 19:42:49 +0100 Subject: [PATCH] ov-components: refactor toolbar panel buttons to use Angular signals for state management and enhance badge styles --- .../toolbar-panel-buttons.component.html | 74 ++++++++++--------- .../toolbar-panel-buttons.component.scss | 31 +++++--- .../toolbar-panel-buttons.component.ts | 64 ++++++++-------- .../components/toolbar/toolbar.component.html | 1 + .../components/toolbar/toolbar.component.ts | 25 +++++-- 5 files changed, 113 insertions(+), 82 deletions(-) diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.html b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.html index 510a85487..9d66de782 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.html +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.html @@ -1,12 +1,12 @@ -
+
- - + +
@@ -75,11 +77,11 @@ mat-icon-button id="activities-panel-btn" class="panel-button" - *ngIf="!isMinimal && showActivitiesPanelButton" + *ngIf="!isMinimal() && showActivitiesPanelButton()" matTooltip="{{ 'TOOLBAR.ACTIVITIES' | translate }}" (click)="onToggleActivities()" - [disabled]="isConnectionLost" - [class.active-btn]="isActivitiesOpened" + [disabled]="isConnectionLost()" + [class.active-btn]="isActivitiesOpened()" > category @@ -89,13 +91,20 @@ mat-icon-button class="panel-button" id="participants-panel-btn" - *ngIf="!isMinimal && showParticipantsPanelButton" + *ngIf="!isMinimal() && showParticipantsPanelButton()" matTooltip="{{ 'TOOLBAR.PARTICIPANTS' | translate }}" (click)="onToggleParticipants()" - [disabled]="isConnectionLost" - [class.active-btn]="isParticipantsOpened" + [disabled]="isConnectionLost()" + [class.active-btn]="isParticipantsOpened()" > - people + people @@ -103,18 +112,17 @@ mat-icon-button class="panel-button" id="chat-panel-btn" - *ngIf="!isMinimal && showChatPanelButton" + *ngIf="!isMinimal() && showChatPanelButton()" matTooltip="{{ 'TOOLBAR.CHAT' | translate }}" (click)="onToggleChat()" - [disabled]="isConnectionLost" - [class.active-btn]="isChatOpened" + [disabled]="isConnectionLost()" + [class.active-btn]="isChatOpened()" > chat @@ -122,7 +130,7 @@ - - + + diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.scss b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.scss index 8639d221c..b355dcd5a 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.scss +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.scss @@ -2,6 +2,24 @@ .panel-button { border-radius: var(--ov-toolbar-buttons-radius); color: var(--ov-text-primary-color); + + // Custom badge styles for participants and chat buttons + ::ng-deep .mat-badge-content { + background-color: var(--ov-accent-action-color) !important; + color: var(--ov-text-primary-color) !important; + font-weight: 600; + font-size: 10px; + min-width: 16px; + height: 16px; + line-height: 16px; + } + + ::ng-deep .mat-badge-small .mat-badge-content { + font-size: 9px; + min-width: 14px; + height: 14px; + line-height: 14px; + } } .active-btn, @@ -93,18 +111,11 @@ } // Chat badge adjustments for menu - .mat-badge { - mat-icon { - font-size: 18px !important; - width: 18px !important; - height: 18px !important; - } - } - - .mat-badge-content { - background-color: var(--ov-warn-color) !important; + ::ng-deep .mat-badge-content { + background-color: var(--ov-accent-action-color) !important; color: var(--ov-text-primary-color) !important; font-size: 10px !important; + font-weight: 600 !important; min-width: 14px !important; height: 14px !important; line-height: 14px !important; diff --git a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.ts b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.ts index d22e5f079..390bbde61 100644 --- a/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.ts +++ b/openvidu-components-angular/projects/openvidu-components-angular/src/lib/components/toolbar/toolbar-panel-buttons/toolbar-panel-buttons.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core'; +import { Component, TemplateRef, computed, input, output } from '@angular/core'; import { ViewportService } from '../../../services/viewport/viewport.service'; @Component({ @@ -8,24 +8,38 @@ import { ViewportService } from '../../../services/viewport/viewport.service'; standalone: false }) export class ToolbarPanelButtonsComponent { - // Inputs from toolbar - @Input() isMinimal: boolean = false; - @Input() isConnectionLost: boolean = false; - @Input() isActivitiesOpened: boolean = false; - @Input() isParticipantsOpened: boolean = false; - @Input() isChatOpened: boolean = false; - @Input() unreadMessages: number = 0; - @Input() showActivitiesPanelButton: boolean = true; - @Input() showParticipantsPanelButton: boolean = true; - @Input() showChatPanelButton: boolean = true; - @Input() recordingStatus: any; - @Input() broadcastingStatus: any; - @Input() toolbarAdditionalPanelButtonsTemplate: TemplateRef | undefined; + // Signal inputs from toolbar + isMinimal = input(false); + isConnectionLost = input(false); + isActivitiesOpened = input(false); + isParticipantsOpened = input(false); + isChatOpened = input(false); + unreadMessages = input(0); + showActivitiesPanelButton = input(true); + showParticipantsPanelButton = input(true); + showChatPanelButton = input(true); + recordingStatus = input(); + broadcastingStatus = input(); + toolbarAdditionalPanelButtonsTemplate = input | undefined>(); + totalParticipants = input(0); - // Outputs back to toolbar - @Output() toggleActivitiesPanel: EventEmitter = new EventEmitter(); - @Output() toggleParticipantsPanel: EventEmitter = new EventEmitter(); - @Output() toggleChatPanel: EventEmitter = new EventEmitter(); + // Signal outputs back to toolbar + toggleActivitiesPanel = output(); + toggleParticipantsPanel = output(); + toggleChatPanel = output(); + + // Computed signals + visibleButtonsCount = computed(() => { + let count = 0; + if (!this.isMinimal() && this.showActivitiesPanelButton()) count++; + if (!this.isMinimal() && this.showParticipantsPanelButton()) count++; + if (!this.isMinimal() && this.showChatPanelButton()) count++; + return count; + }); + + isAnyPanelOpened = computed(() => { + return this.isActivitiesOpened() || this.isParticipantsOpened() || this.isChatOpened(); + }); constructor(public viewportService: ViewportService) {} @@ -34,20 +48,6 @@ export class ToolbarPanelButtonsComponent { return this.viewportService.isMobileView() } - // Get count of visible buttons - get visibleButtonsCount(): number { - let count = 0; - if (!this.isMinimal && this.showActivitiesPanelButton) count++; - if (!this.isMinimal && this.showParticipantsPanelButton) count++; - if (!this.isMinimal && this.showChatPanelButton) count++; - return count; - } - - // Check if any panel is currently opened - get isAnyPanelOpened(): boolean { - return this.isActivitiesOpened || this.isParticipantsOpened || this.isChatOpened; - } - // Local methods that emit events onToggleActivities(expand?: string) { this.toggleActivitiesPanel.emit(expand); 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 cdbe146fc..b6ec50db2 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 @@ -104,6 +104,7 @@ [showChatPanelButton]="showChatPanelButton" [recordingStatus]="recordingStatus" [broadcastingStatus]="broadcastingStatus" + [totalParticipants]="totalParticipants()" [toolbarAdditionalPanelButtonsTemplate]="toolbarAdditionalPanelButtonsTemplate" (toggleActivitiesPanel)="toggleActivitiesPanel($event)" (toggleParticipantsPanel)="toggleParticipantsPanel()" 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 8673b5825..958e70f6c 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 @@ -3,6 +3,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + computed, ContentChild, EventEmitter, HostListener, @@ -18,6 +19,8 @@ import { DocumentService } from '../../services/document/document.service'; import { PanelService } from '../../services/panel/panel.service'; import { MatMenuTrigger } from '@angular/material/menu'; +import { Room, RoomEvent } from 'livekit-client'; +import { LeaveButtonDirective, ToolbarMoreOptionsAdditionalMenuItemsDirective } from '../../directives/template/internals.directive'; import { ToolbarAdditionalButtonsDirective, ToolbarAdditionalPanelButtonsDirective @@ -26,6 +29,7 @@ import { BroadcastingStatus, BroadcastingStatusInfo, BroadcastingStopRequestedEv import { ChatMessage } from '../../models/chat.model'; import { ILogger } from '../../models/logger.model'; import { PanelStatusInfo, PanelType } from '../../models/panel.model'; +import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model'; import { RecordingInfo, RecordingStartRequestedEvent, @@ -33,8 +37,10 @@ import { RecordingStatusInfo, RecordingStopRequestedEvent } from '../../models/recording.model'; +import { ToolbarAdditionalButtonsPosition } from '../../models/toolbar.model'; import { ActionService } from '../../services/action/action.service'; import { BroadcastingService } from '../../services/broadcasting/broadcasting.service'; +import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service'; import { OpenViduComponentsConfigService } from '../../services/config/directive-config.service'; import { DeviceService } from '../../services/device/device.service'; import { LayoutService } from '../../services/layout/layout.service'; @@ -46,11 +52,6 @@ import { RecordingService } from '../../services/recording/recording.service'; import { StorageService } from '../../services/storage/storage.service'; import { TemplateManagerService, ToolbarTemplateConfiguration } from '../../services/template/template-manager.service'; import { TranslateService } from '../../services/translate/translate.service'; -import { CdkOverlayService } from '../../services/cdk-overlay/cdk-overlay.service'; -import { ParticipantLeftEvent, ParticipantLeftReason, ParticipantModel } from '../../models/participant.model'; -import { Room, RoomEvent } from 'livekit-client'; -import { ToolbarAdditionalButtonsPosition } from '../../models/toolbar.model'; -import { LeaveButtonDirective, ToolbarMoreOptionsAdditionalMenuItemsDirective } from '../../directives/template/internals.directive'; /** * The **ToolbarComponent** is hosted inside of the {@link VideoconferenceComponent}. @@ -405,6 +406,16 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { */ templateConfig: ToolbarTemplateConfiguration = {}; + /** + * @internal + * Computed signal for total participants count (local + remote) + */ + totalParticipants = computed(() => { + const local = this.participantService.localParticipantSignal(); + const remotes = this.participantService.remoteParticipantsSignal(); + return (local ? 1 : 0) + remotes.length; + }); + // Store directive references for template setup private _externalAdditionalButtons?: ToolbarAdditionalButtonsDirective; private _externalLeaveButton?: LeaveButtonDirective; @@ -624,8 +635,8 @@ export class ToolbarComponent implements OnInit, OnDestroy, AfterViewInit { await this.openviduService.disconnectRoom(() => { this.onParticipantLeft.emit({ roomName: this.openviduService.getRoomName(), - participantName: this.participantService.getLocalParticipant()?.name || '', - identity: this.participantService.getLocalParticipant()?.identity || '', + participantName: this.participantService.localParticipantSignal()!.name || '', + identity: this.participantService.localParticipantSignal()!.identity || '', reason: ParticipantLeftReason.LEAVE }); this.onRoomDisconnected.emit();