feat(layout): add userdata bbb_hide_controls (#21410)

* feat(layout): add `hideTopRow` to nav bar context

Adds the `hideTopRow` property to the navbar in the layout context, allowing
the top row of the navigation bar to be hidden. Only the row with the
talking indicators and timer indicator will remain visible when this
option is used.

* feat(layout): add userdata `bbb_hide_controls`

Introduces the userdata join parameter `bbb_hide_controls`, which hides
the action bar and the top row of the navigation bar (including the close
sidebar button, room title, connectivity indicator, and leave meeting button)
while keeping the row with the talking indicator and timer indicator visible.

* fix(layout): has actions bar boolean expression
This commit is contained in:
Arthur B. Grossi 2024-10-23 09:06:44 -03:00 committed by GitHub
parent 84dba0c251
commit 4aab1b21d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 90 additions and 56 deletions

View File

@ -95,7 +95,8 @@ const AppContainer = (props) => {
? ( ? (
<App <App
{...{ {...{
hideActionsBar: getFromUserSettings('bbb_hide_actions_bar', false), hideActionsBar: getFromUserSettings('bbb_hide_actions_bar', false)
|| getFromUserSettings('bbb_hide_controls', false),
currentUserAway: currentUser.away, currentUserAway: currentUser.away,
currentUserRaiseHand: currentUser.raiseHand, currentUserRaiseHand: currentUser.raiseHand,
captionsStyle, captionsStyle,

View File

@ -242,6 +242,23 @@ const reducer = (state, action) => {
}; };
} }
case ACTIONS.SET_HIDE_NAVBAR_TOP_ROW: {
const { navBar } = state.output;
if (navBar.hideTopRow === action.value) {
return state;
}
return {
...state,
output: {
...state.output,
navBar: {
...navBar,
hideTopRow: action.value,
},
},
};
}
case ACTIONS.SET_NAVBAR_OUTPUT: { case ACTIONS.SET_NAVBAR_OUTPUT: {
const { const {
display, width, height, top, left, tabOrder, zIndex, display, width, height, top, left, tabOrder, zIndex,

View File

@ -56,6 +56,7 @@ export const ACTIONS = {
SET_HIDE_NOTIFICATION_TOASTS: 'setHideNotificationToasts', SET_HIDE_NOTIFICATION_TOASTS: 'setHideNotificationToasts',
SET_HAS_NAVBAR: 'setHasNavBar', SET_HAS_NAVBAR: 'setHasNavBar',
SET_HIDE_NAVBAR_TOP_ROW: 'setHideNavBarTopRow',
SET_NAVBAR_OUTPUT: 'setNavBarOutput', SET_NAVBAR_OUTPUT: 'setNavBarOutput',
SET_HAS_ACTIONBAR: 'setHasActionBar', SET_HAS_ACTIONBAR: 'setHasActionBar',

View File

@ -115,6 +115,7 @@ export const INITIAL_INPUT_STATE = {
export const INITIAL_OUTPUT_STATE = { export const INITIAL_OUTPUT_STATE = {
navBar: { navBar: {
display: false, display: false,
hideTopRow: false,
width: 0, width: 0,
height: 0, height: 0,
top: 0, top: 0,

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { layoutSelect, layoutSelectInput } from '/imports/ui/components/layout/context'; import { layoutSelect, layoutSelectInput, layoutSelectOutput } from '/imports/ui/components/layout/context';
import DEFAULT_VALUES from '/imports/ui/components/layout/defaultValues'; import DEFAULT_VALUES from '/imports/ui/components/layout/defaultValues';
import { LAYOUT_TYPE, DEVICE_TYPE } from '/imports/ui/components/layout/enums'; import { LAYOUT_TYPE, DEVICE_TYPE } from '/imports/ui/components/layout/enums';
@ -22,6 +22,7 @@ const LayoutEngine = () => {
const presentationInput = layoutSelectInput((i) => i.presentation); const presentationInput = layoutSelectInput((i) => i.presentation);
const actionbarInput = layoutSelectInput((i) => i.actionBar); const actionbarInput = layoutSelectInput((i) => i.actionBar);
const navBarInput = layoutSelectInput((i) => i.navBar); const navBarInput = layoutSelectInput((i) => i.navBar);
const navBarOutput = layoutSelectOutput((i) => i.navBar);
const sidebarNavigationInput = layoutSelectInput((i) => i.sidebarNavigation); const sidebarNavigationInput = layoutSelectInput((i) => i.sidebarNavigation);
const sidebarContentInput = layoutSelectInput((i) => i.sidebarContent); const sidebarContentInput = layoutSelectInput((i) => i.sidebarContent);
const externalVideoInput = layoutSelectInput((i) => i.externalVideo); const externalVideoInput = layoutSelectInput((i) => i.externalVideo);
@ -106,7 +107,9 @@ const LayoutEngine = () => {
const calculatesNavbarHeight = () => { const calculatesNavbarHeight = () => {
const { navBarHeight } = DEFAULT_VALUES; const { navBarHeight } = DEFAULT_VALUES;
return navBarInput.hasNavBar ? navBarHeight : 0; const finalHeight = navBarOutput.hideTopRow ? navBarHeight / 2 : navBarHeight;
return navBarInput.hasNavBar ? finalHeight : 0;
}; };
const calculatesNavbarBounds = (mediaAreaBounds) => { const calculatesNavbarBounds = (mediaAreaBounds) => {

View File

@ -97,6 +97,7 @@ export interface GenericContentMainArea {
} }
interface NavBar { interface NavBar {
hasNavBar?: boolean; hasNavBar?: boolean;
hideTopRow: boolean;
height: number; height: number;
display?: boolean; display?: boolean;
left?: number; left?: number;

View File

@ -101,7 +101,13 @@ const LayoutObserver: React.FC = () => {
layoutContextDispatch({ layoutContextDispatch({
type: ACTIONS.SET_HAS_ACTIONBAR, type: ACTIONS.SET_HAS_ACTIONBAR,
value: !getFromUserSettings('bbb_hide_actions_bar', false), value: !(getFromUserSettings('bbb_hide_actions_bar', false)
|| getFromUserSettings('bbb_hide_controls', false)),
});
layoutContextDispatch({
type: ACTIONS.SET_HIDE_NAVBAR_TOP_ROW,
value: getFromUserSettings('bbb_hide_controls', false),
}); });
layoutContextDispatch({ layoutContextDispatch({

View File

@ -272,6 +272,7 @@ class NavBar extends Component {
currentUserId, currentUserId,
isDirectLeaveButtonEnabled, isDirectLeaveButtonEnabled,
isMeteorConnected, isMeteorConnected,
hideTopRow,
} = this.props; } = this.props;
const hasNotification = hasUnreadMessages || (hasUnreadNotes && !isPinned); const hasNotification = hasUnreadMessages || (hasUnreadNotes && !isPinned);
@ -312,58 +313,60 @@ class NavBar extends Component {
} }
} }
> >
<Styled.Top> {!hideTopRow && (
<Styled.Left> <Styled.Top>
{shouldShowNavBarToggleButton && isExpanded && document.dir === 'ltr' <Styled.Left>
&& <Styled.ArrowLeft iconName="left_arrow" />} {shouldShowNavBarToggleButton && isExpanded && document.dir === 'ltr'
{shouldShowNavBarToggleButton && !isExpanded && document.dir === 'rtl' && <Styled.ArrowLeft iconName="left_arrow" />}
&& <Styled.ArrowLeft iconName="left_arrow" />} {shouldShowNavBarToggleButton && !isExpanded && document.dir === 'rtl'
{shouldShowNavBarToggleButton && ( && <Styled.ArrowLeft iconName="left_arrow" />}
<Styled.NavbarToggleButton {shouldShowNavBarToggleButton && (
tooltipplacement="right" <Styled.NavbarToggleButton
onClick={this.handleToggleUserList} tooltipplacement="right"
color={isPhone && isExpanded ? 'primary' : 'dark'} onClick={this.handleToggleUserList}
size='md' color={isPhone && isExpanded ? 'primary' : 'dark'}
circle size='md'
hideLabel circle
data-test={hasNotification ? 'hasUnreadMessages' : 'toggleUserList'} hideLabel
label={intl.formatMessage(intlMessages.toggleUserListLabel)} data-test={hasNotification ? 'hasUnreadMessages' : 'toggleUserList'}
tooltipLabel={intl.formatMessage(intlMessages.toggleUserListLabel)} label={intl.formatMessage(intlMessages.toggleUserListLabel)}
aria-label={ariaLabel} tooltipLabel={intl.formatMessage(intlMessages.toggleUserListLabel)}
icon="user" aria-label={ariaLabel}
aria-expanded={isExpanded} icon="user"
accessKey={TOGGLE_USERLIST_AK} aria-expanded={isExpanded}
hasNotification={hasNotification} accessKey={TOGGLE_USERLIST_AK}
hasNotification={hasNotification}
/>
)}
{shouldShowNavBarToggleButton && !isExpanded && document.dir === 'ltr'
&& <Styled.ArrowRight iconName="right_arrow" />}
{shouldShowNavBarToggleButton && isExpanded && document.dir === 'rtl'
&& <Styled.ArrowRight iconName="right_arrow" />}
{renderPluginItems(leftPluginItems)}
</Styled.Left>
<Styled.Center>
<Styled.PresentationTitle data-test="presentationTitle">
{presentationTitle}
</Styled.PresentationTitle>
<RecordingIndicator
amIModerator={amIModerator}
currentUserId={currentUserId}
/> />
)} {renderPluginItems(centerPluginItems)}
{shouldShowNavBarToggleButton && !isExpanded && document.dir === 'ltr' </Styled.Center>
&& <Styled.ArrowRight iconName="right_arrow" />} <Styled.Right>
{shouldShowNavBarToggleButton && isExpanded && document.dir === 'rtl' {renderPluginItems(rightPluginItems)}
&& <Styled.ArrowRight iconName="right_arrow" />} {ConnectionStatusService.isEnabled() ? <ConnectionStatusButton /> : null}
{renderPluginItems(leftPluginItems)} {ConnectionStatusService.isEnabled() ? <ConnectionStatus /> : null}
</Styled.Left> {isDirectLeaveButtonEnabled && isMeteorConnected
<Styled.Center> ? <LeaveMeetingButtonContainer amIModerator={amIModerator} /> : null}
<Styled.PresentationTitle data-test="presentationTitle"> <OptionsDropdownContainer
{presentationTitle} amIModerator={amIModerator}
</Styled.PresentationTitle> isDirectLeaveButtonEnabled={isDirectLeaveButtonEnabled}
<RecordingIndicator />
amIModerator={amIModerator} </Styled.Right>
currentUserId={currentUserId} </Styled.Top>
/> )}
{renderPluginItems(centerPluginItems)}
</Styled.Center>
<Styled.Right>
{renderPluginItems(rightPluginItems)}
{ConnectionStatusService.isEnabled() ? <ConnectionStatusButton /> : null}
{ConnectionStatusService.isEnabled() ? <ConnectionStatus /> : null}
{isDirectLeaveButtonEnabled && isMeteorConnected
? <LeaveMeetingButtonContainer amIModerator={amIModerator} /> : null}
<OptionsDropdownContainer
amIModerator={amIModerator}
isDirectLeaveButtonEnabled={isDirectLeaveButtonEnabled}
/>
</Styled.Right>
</Styled.Top>
<Styled.Bottom> <Styled.Bottom>
{enableTalkingIndicator ? <TalkingIndicator amIModerator={amIModerator} /> : null} {enableTalkingIndicator ? <TalkingIndicator amIModerator={amIModerator} /> : null}
<TimerIndicatorContainer /> <TimerIndicatorContainer />

View File

@ -3,7 +3,7 @@ import { defineMessages, useIntl } from 'react-intl';
import Auth from '/imports/ui/services/auth'; import Auth from '/imports/ui/services/auth';
import getFromUserSettings from '/imports/ui/services/users-settings'; import getFromUserSettings from '/imports/ui/services/users-settings';
import NavBar from './component'; import NavBar from './component';
import { layoutSelectInput, layoutSelectOutput, layoutDispatch } from '../layout/context'; import { layoutSelectInput, layoutDispatch, layoutSelectOutput } from '../layout/context';
import { PluginsContext } from '/imports/ui/components/components-data/plugin-context/context'; import { PluginsContext } from '/imports/ui/components/components-data/plugin-context/context';
import { PANELS } from '/imports/ui/components/layout/enums'; import { PANELS } from '/imports/ui/components/layout/enums';
import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser'; import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser';
@ -121,6 +121,7 @@ const NavBarContainer = ({ children, ...props }) => {
isDirectLeaveButtonEnabled: IS_DIRECT_LEAVE_BUTTON_ENABLED, isDirectLeaveButtonEnabled: IS_DIRECT_LEAVE_BUTTON_ENABLED,
// TODO: Remove/Replace // TODO: Remove/Replace
isMeteorConnected: true, isMeteorConnected: true,
hideTopRow: navBar.hideTopRow,
...props, ...props,
}} }}
style={{ ...navBar }} style={{ ...navBar }}