Skip to content

Commit

Permalink
feat(toolbox/native): reorganizing buttons in the toolbox and overflo…
Browse files Browse the repository at this point in the history
…w menu (jitsi#15543)

Configures what buttons can be visible inside Toolbox and OverflowMenu, based on priority and config overrides, just like web does.
  • Loading branch information
Calinteodor authored Feb 11, 2025
1 parent a6d333c commit 405af3a
Show file tree
Hide file tree
Showing 26 changed files with 695 additions and 356 deletions.
2 changes: 1 addition & 1 deletion ios/app/src/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ - (BOOL)application:(UIApplication *)application
jitsiMeet.defaultConferenceOptions = [JitsiMeetConferenceOptions fromBuilder:^(JitsiMeetConferenceOptionsBuilder *builder) {

// For testing configOverrides a room needs to be set
// builder.room = @"test0988test";
// builder.room = @"https://meet.jit.si/test0988test";

[builder setFeatureFlag:@"welcomepage.enabled" withBoolean:YES];
[builder setFeatureFlag:@"ios.screensharing.enabled" withBoolean:YES];
Expand Down
1 change: 1 addition & 0 deletions react/features/app/middlewares.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import '../mobile/react-native-sdk/middleware';
import '../mobile/watchos/middleware';
import '../share-room/middleware';
import '../shared-video/middleware';
import '../toolbox/middleware.native';
import '../whiteboard/middleware.native';

import './middlewares.any';
11 changes: 10 additions & 1 deletion react/features/base/devices/functions.web.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable require-jsdoc */

import { IReduxState, IStore } from '../../app/types';
import JitsiMeetJS from '../lib-jitsi-meet';
import { updateSettings } from '../settings/actions';
Expand Down Expand Up @@ -157,7 +159,8 @@ export function getDevicesFromURL(state: IReduxState) {
* @returns {Object} An object with the media devices split by type. The keys
* are device type and the values are arrays with devices matching the device
* type.
*/
*/
// @ts-ignore
export function groupDevicesByKind(devices: MediaDeviceInfo[]): IDevicesState['availableDevices'] {
return {
audioInput: devices.filter(device => device.kind === 'audioinput'),
Expand All @@ -172,7 +175,10 @@ export function groupDevicesByKind(devices: MediaDeviceInfo[]): IDevicesState['a
* @param {MediaDeviceInfo[]} devices - The devices to be filtered.
* @returns {MediaDeviceInfo[]} - The filtered devices.
*/
// @ts-ignore
export function filterIgnoredDevices(devices: MediaDeviceInfo[] = []) {

// @ts-ignore
const ignoredDevices: MediaDeviceInfo[] = [];
const filteredDevices = devices.filter(device => {
if (!device.label) {
Expand Down Expand Up @@ -201,6 +207,7 @@ export function filterIgnoredDevices(devices: MediaDeviceInfo[] = []) {
* @param {MediaDeviceInfo[]} devices2 - Array with devices to be compared.
* @returns {boolean} - True if the device arrays are different and false otherwise.
*/
// @ts-ignore
export function areDevicesDifferent(devices1: MediaDeviceInfo[] = [], devices2: MediaDeviceInfo[] = []) {
if (devices1.length !== devices2.length) {
return true;
Expand Down Expand Up @@ -304,6 +311,7 @@ export function getVideoDeviceIds(state: IReduxState) {
* @param {MediaDeviceInfo[]} devices - The devices.
* @returns {string}
*/
// @ts-ignore
function devicesToStr(devices?: MediaDeviceInfo[]) {
return devices?.map(device => `\t\t${device.label}[${device.deviceId}]`).join('\n');
}
Expand All @@ -315,6 +323,7 @@ function devicesToStr(devices?: MediaDeviceInfo[]) {
* @param {string} title - The title that will be printed in the log.
* @returns {void}
*/
// @ts-ignore
export function logDevices(devices: MediaDeviceInfo[], title = '') {
const deviceList = groupDevicesByKind(devices);
const audioInputs = devicesToStr(deviceList.audioInput);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { makeStyles } from 'tss-react/mui';

import { IReduxState } from '../../../../app/types';
import DeviceStatus from '../../../../prejoin/components/web/preview/DeviceStatus';
import { isRoomNameEnabled } from '../../../../prejoin/functions';
import { isRoomNameEnabled } from '../../../../prejoin/functions.web';
import Toolbox from '../../../../toolbox/components/web/Toolbox';
import { isButtonEnabled } from '../../../../toolbox/functions.web';
import { getConferenceName } from '../../../conference/functions';
Expand Down
2 changes: 1 addition & 1 deletion react/features/chat/components/web/MessageContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ interface IState {
/**
* The id of the last read message.
*/
lastReadMessageId: string;
lastReadMessageId: string | null;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions react/features/filmstrip/components/native/Filmstrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import { getLocalParticipant } from '../../../base/participants/functions';
import Platform from '../../../base/react/Platform.native';
import { ASPECT_RATIO_NARROW } from '../../../base/responsive-ui/constants';
import { getHideSelfView } from '../../../base/settings/functions.any';
import { isToolboxVisible } from '../../../toolbox/functions';
import { setVisibleRemoteParticipants } from '../../actions';
import { isToolboxVisible } from '../../../toolbox/functions.native';
import { setVisibleRemoteParticipants } from '../../actions.native';
import {
getFilmstripDimensions,
isFilmstripVisible,
Expand Down
6 changes: 3 additions & 3 deletions react/features/filmstrip/components/web/Filmstrip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
setUserFilmstripWidth,
setUserIsResizing,
setVisibleRemoteParticipants
} from '../../actions';
} from '../../actions.web';
import {
ASPECT_RATIO_BREAKPOINT,
DEFAULT_FILMSTRIP_WIDTH,
Expand All @@ -39,10 +39,10 @@ import {
} from '../../constants';
import {
getVerticalViewMaxWidth,
isFilmstripDisabled,
isStageFilmstripTopPanel,
shouldRemoteVideosBeVisible
} from '../../functions';
import { isFilmstripDisabled } from '../../functions.web';
} from '../../functions.web';

import AudioTracksContainer from './AudioTracksContainer';
import Thumbnail from './Thumbnail';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
import RaiseHandButton from '../../../toolbox/components/native/RaiseHandButton';
import { shouldDisplayReactionsButtons } from '../../functions.native';

import ReactionsMenuButton from './ReactionsMenuButton';

const RaiseHandContainerButtons = (props: AbstractButtonProps) => {
const _shouldDisplayReactionsButtons = useSelector(shouldDisplayReactionsButtons);

return _shouldDisplayReactionsButtons
? <ReactionsMenuButton
{ ...props }
showRaiseHand = { true } />
: <RaiseHandButton { ...props } />;
};

export default RaiseHandContainerButtons;
53 changes: 53 additions & 0 deletions react/features/toolbox/actions.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import { setVideoMuted } from '../base/media/actions';
import { VIDEO_MUTISM_AUTHORITY } from '../base/media/constants';

import {
SET_MAIN_TOOLBAR_BUTTONS_THRESHOLDS,
SET_TOOLBOX_ENABLED,
SET_TOOLBOX_SHIFT_UP,
SET_TOOLBOX_VISIBLE,
TOGGLE_TOOLBOX_VISIBLE
} from './actionTypes';
import { IMainToolbarButtonThresholds } from './types';

/**
* Enables/disables the toolbox.
Expand Down Expand Up @@ -118,3 +120,54 @@ export function setShiftUp(shiftUp: boolean) {
shiftUp
};
}

/**
* Sets the mainToolbarButtonsThresholds.
*
* @param {IMainToolbarButtonThresholds} thresholds - Thresholds for screen size and visible main toolbar buttons.
* @returns {Function}
*/
export function setMainToolbarThresholds(thresholds: IMainToolbarButtonThresholds) {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { mainToolbarButtons } = getState()['features/base/config'];

if (!Array.isArray(mainToolbarButtons) || mainToolbarButtons.length === 0) {
return;
}

const mainToolbarButtonsThresholds: IMainToolbarButtonThresholds = [];

const mainToolbarButtonsLengthMap = new Map();
let orderIsChanged = false;

mainToolbarButtons.forEach(buttons => {
if (!Array.isArray(buttons) || buttons.length === 0) {
return;
}

mainToolbarButtonsLengthMap.set(buttons.length, buttons);
});

thresholds.forEach(({ width, order }) => {
let finalOrder = mainToolbarButtonsLengthMap.get(order.length);

if (finalOrder) {
orderIsChanged = true;
} else {
finalOrder = order;
}

mainToolbarButtonsThresholds.push({
order: finalOrder,
width
});
});

if (orderIsChanged) {
dispatch({
type: SET_MAIN_TOOLBAR_BUTTONS_THRESHOLDS,
mainToolbarButtonsThresholds
});
}
};
}
2 changes: 1 addition & 1 deletion react/features/toolbox/actions.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function setOverflowMenuVisible(_visible: boolean): any {
* text: string
* }}
*/
export function customButtonPressed(id: string, text: string) {
export function customButtonPressed(id: string, text: string | undefined) {
return {
type: CUSTOM_BUTTON_PRESSED,
id,
Expand Down
53 changes: 0 additions & 53 deletions react/features/toolbox/actions.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ import {
FULL_SCREEN_CHANGED,
SET_FULL_SCREEN,
SET_HANGUP_MENU_VISIBLE,
SET_MAIN_TOOLBAR_BUTTONS_THRESHOLDS,
SET_OVERFLOW_DRAWER,
SET_OVERFLOW_MENU_VISIBLE,
SET_TOOLBAR_HOVERED,
SET_TOOLBOX_TIMEOUT
} from './actionTypes';
import { setToolboxVisible } from './actions.web';
import { THRESHOLDS } from './constants';
import { getToolbarTimeout } from './functions.web';
import { IMainToolbarButtonThresholds } from './types';

export * from './actions.any';

Expand Down Expand Up @@ -124,56 +121,6 @@ export function setFullScreen(fullScreen: boolean) {
};
}

/**
* Sets the mainToolbarButtonsThresholds.
*
* @returns {Function}
*/
export function setMainToolbarThresholds() {
return (dispatch: IStore['dispatch'], getState: IStore['getState']) => {
const { mainToolbarButtons } = getState()['features/base/config'];

if (!mainToolbarButtons || !Array.isArray(mainToolbarButtons) || mainToolbarButtons.length === 0) {
return;
}

const mainToolbarButtonsThresholds: IMainToolbarButtonThresholds = [];

const mainToolbarButtonsLenghtMap = new Map();
let orderIsChanged = false;

mainToolbarButtons.forEach(buttons => {
if (!Array.isArray(buttons) || buttons.length === 0) {
return;
}

mainToolbarButtonsLenghtMap.set(buttons.length, buttons);
});

THRESHOLDS.forEach(({ width, order }) => {
let finalOrder = mainToolbarButtonsLenghtMap.get(order.length);

if (finalOrder) {
orderIsChanged = true;
} else {
finalOrder = order;
}

mainToolbarButtonsThresholds.push({
order: finalOrder,
width
});
});

if (orderIsChanged) {
dispatch({
type: SET_MAIN_TOOLBAR_BUTTONS_THRESHOLDS,
mainToolbarButtonsThresholds
});
}
};
}

/**
* Shows the toolbox for specified timeout.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import styles from './styles';


interface IProps extends AbstractButtonProps {
export interface ICustomOptionButton extends AbstractButtonProps {
backgroundColor?: string;
icon: any;
id?: string;
isToolboxButton?: boolean;
text?: string;
text: string;
}

/**
* Component that renders a custom button.
*
* @returns {Component}
*/
class CustomOptionButton extends AbstractButton<IProps> {
class CustomOptionButton extends AbstractButton<ICustomOptionButton> {
backgroundColor = this.props.backgroundColor;
iconSrc = this.props.icon;
id = this.props.id;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { IReduxState } from '../../../app/types';
import { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
import HangupButton from '../HangupButton';

import HangupMenuButton from './HangupMenuButton';

const HangupContainerButtons = (props: AbstractButtonProps) => {
const { conference } = useSelector((state: IReduxState) => state['features/base/conference']);
const endConferenceSupported = conference?.isEndConferenceSupported();

return endConferenceSupported

// @ts-ignore
? <HangupMenuButton { ...props } />
: <HangupButton { ...props } />;
};

export default HangupContainerButtons;
Loading

0 comments on commit 405af3a

Please sign in to comment.