Skip to content

Commit

Permalink
feat(toolbox/native): custom overflow menu buttons (#14594)
Browse files Browse the repository at this point in the history
* feat(toolbox/native): custom buttons for the OverflowMenu
  • Loading branch information
Calinteodor authored Apr 10, 2024
1 parent b54cec8 commit 36671d7
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ public enum Type {
CHAT_TOGGLED("org.jitsi.meet.CHAT_TOGGLED"),
VIDEO_MUTED_CHANGED("org.jitsi.meet.VIDEO_MUTED_CHANGED"),
READY_TO_CLOSE("org.jitsi.meet.READY_TO_CLOSE"),
TRANSCRIPTION_CHUNK_RECEIVED("org.jitsi.meet.TRANSCRIPTION_CHUNK_RECEIVED");
TRANSCRIPTION_CHUNK_RECEIVED("org.jitsi.meet.TRANSCRIPTION_CHUNK_RECEIVED"),
CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED("org.jitsi.meet.CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED");

private static final String CONFERENCE_BLURRED_NAME = "CONFERENCE_BLURRED";
private static final String CONFERENCE_FOCUSED_NAME = "CONFERENCE_FOCUSED";
Expand All @@ -108,6 +109,7 @@ public enum Type {
private static final String VIDEO_MUTED_CHANGED_NAME = "VIDEO_MUTED_CHANGED";
private static final String READY_TO_CLOSE_NAME = "READY_TO_CLOSE";
private static final String TRANSCRIPTION_CHUNK_RECEIVED_NAME = "TRANSCRIPTION_CHUNK_RECEIVED";
private static final String CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED_NAME = "CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED";

private final String action;

Expand Down Expand Up @@ -162,6 +164,8 @@ private static Type buildTypeFromName(String name) {
return READY_TO_CLOSE;
case TRANSCRIPTION_CHUNK_RECEIVED_NAME:
return TRANSCRIPTION_CHUNK_RECEIVED;
case CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED_NAME:
return CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED;
}

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ protected void onReadyToClose() {

// protected void onTranscriptionChunkReceived(HashMap<String, Object> extraData) {
// JitsiMeetLogger.i("Transcription chunk received: " + extraData);
// }

// protected void onCustomOverflowMenuButtonPressed(HashMap<String, Object> extraData) {
// JitsiMeetLogger.i("Custom overflow menu button pressed: " + extraData);
// }

// Activity lifecycle methods
Expand Down Expand Up @@ -344,6 +348,9 @@ private void onBroadcastReceived(Intent intent) {
break;
// case TRANSCRIPTION_CHUNK_RECEIVED:
// onTranscriptionChunkReceived(event.getData());
// break;
// case CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED:
// onCustomOverflowMenuButtonPressed(event.getData());
// break;
}
}
Expand Down
4 changes: 4 additions & 0 deletions ios/app/src/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ - (void)conferenceWillJoin:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"CONFERENCE_WILL_JOIN" withData:data];
}

// - (void)customOverflowMenuButtonPressed:(NSDictionary *)data {
// [self _onJitsiMeetViewDelegateEvent:@"CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED" withData:data];
// }

#if 0
- (void)enterPictureInPicture:(NSDictionary *)data {
[self _onJitsiMeetViewDelegateEvent:@"ENTER_PICTURE_IN_PICTURE" withData:data];
Expand Down
7 changes: 7 additions & 0 deletions ios/sdk/src/JitsiMeetViewDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,11 @@
*/
- (void)transcriptionChunkReceived:(NSDictionary *)data;

/**
* Called when the custom overflow menu button is pressed.
*
* The `data` dictionary contains a `id`, `text` key.
*/
- (void)customOverflowMenuButtonPressed:(NSDictionary *)data;

@end
11 changes: 11 additions & 0 deletions react/features/mobile/external-api/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@ export const READY_TO_CLOSE = 'READY_TO_CLOSE';
*/
export const SCREEN_SHARE_PARTICIPANTS_UPDATED
= 'SCREEN_SHARE_PARTICIPANTS_UPDATED';

/**
* The type of (redux) action which signals that a custom button from the overflow menu was pressed.
*
* @returns {{
* type: CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED,
* id: string,
* text: string
* }}
*/
export const CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED = 'CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED';
21 changes: 21 additions & 0 deletions react/features/mobile/external-api/actions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED,
READY_TO_CLOSE,
SCREEN_SHARE_PARTICIPANTS_UPDATED
} from './actionTypes';


/**
* Creates a (redux) action which signals that the SDK is ready to be closed.
*
Expand Down Expand Up @@ -33,3 +35,22 @@ export function setParticipantsWithScreenShare(participantIds: Array<string>) {
participantIds
};
}

/**
* Creates a (redux) action which that a custom overflow menu button was pressed.
*
* @param {string} id - The id for the custom button.
* @param {string} text - The label for the custom button.
* @returns {{
* type: CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED,
* id: string,
* text: string
* }}
*/
export function customOverflowMenuButtonPressed(id: string, text: string) {
return {
type: CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED,
id,
text
};
}
25 changes: 24 additions & 1 deletion react/features/mobile/external-api/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture/actionTypes';
// @ts-ignore
import { isExternalAPIAvailable } from '../react-native-sdk/functions';

import { READY_TO_CLOSE } from './actionTypes';
import {
CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED,
READY_TO_CLOSE
} from './actionTypes';
import { setParticipantsWithScreenShare } from './actions';
import { participantToParticipantInfo, sendEvent } from './functions';
import logger from './logger';
Expand All @@ -79,6 +82,12 @@ const CHAT_TOGGLED = 'CHAT_TOGGLED';
*/
const CONFERENCE_TERMINATED = 'CONFERENCE_TERMINATED';

/**
* Event which will be emitted on the native side to indicate that the custom overflow menu button was pressed.
*/
const CUSTOM_MENU_BUTTON_PRESSED = 'CUSTOM_MENU_BUTTON_PRESSED';


/**
* Event which will be emitted on the native side to indicate a message was received
* through the channel.
Expand Down Expand Up @@ -185,6 +194,20 @@ externalAPIEnabled && MiddlewareRegistry.register(store => next => action => {
break;
}

case CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED: {
const { id, text } = action;

sendEvent(
store,
CUSTOM_MENU_BUTTON_PRESSED,
{
id,
text
});

break;
}

case ENDPOINT_MESSAGE_RECEIVED: {
const { participant, data } = action;

Expand Down
42 changes: 42 additions & 0 deletions react/features/toolbox/components/native/CustomOptionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import { Image } from 'react-native';
import { connect } from 'react-redux';

import { translate } from '../../../base/i18n/functions';
import AbstractButton, { IProps as AbstractButtonProps }
from '../../../base/toolbox/components/AbstractButton';

import styles from './styles';


interface IProps extends AbstractButtonProps {
icon: any;
id?: string;
text: string;
}

/**
* Component that renders a custom button.
*
* @returns {Component}
*/
class CustomOptionButton extends AbstractButton<IProps> {
iconSrc = this.props.icon;
id = this.props.id;
text = this.props.text;

/**
* Custom icon component.
*
* @returns {React.Component}
*/
icon = () => (
<Image
source = {{ uri: this.iconSrc }}
style = { styles.iconImageStyles } />
);

label = this.text;
}

export default translate(connect()(CustomOptionButton));
47 changes: 46 additions & 1 deletion react/features/toolbox/components/native/OverflowMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import SettingsButton from '../../../base/settings/components/native/SettingsBut
import BreakoutRoomsButton
from '../../../breakout-rooms/components/native/BreakoutRoomsButton';
import SharedDocumentButton from '../../../etherpad/components/SharedDocumentButton.native';
import { customOverflowMenuButtonPressed } from '../../../mobile/external-api/actions';
import ReactionMenu from '../../../reactions/components/native/ReactionMenu';
import { shouldDisplayReactionsButtons } from '../../../reactions/functions.any';
import LiveStreamButton from '../../../recording/components/LiveStream/native/LiveStreamButton';
Expand All @@ -27,6 +28,7 @@ import WhiteboardButton from '../../../whiteboard/components/native/WhiteboardBu
import { getMovableButtons } from '../../functions.native';

import AudioOnlyButton from './AudioOnlyButton';
import CustomOptionButton from './CustomOptionButton';
import LinkToSalesforceButton from './LinkToSalesforceButton';
import OpenCarmodeButton from './OpenCarmodeButton';
import RaiseHandButton from './RaiseHandButton';
Expand All @@ -38,6 +40,11 @@ import ScreenSharingButton from './ScreenSharingButton';
*/
interface IProps {

/**
* Custom Toolbar buttons.
*/
_customToolbarButtons?: Array<{ backgroundColor?: string; icon: string; id: string; text: string; }>;

/**
* True if breakout rooms feature is available, false otherwise.
*/
Expand Down Expand Up @@ -145,6 +152,7 @@ class OverflowMenu extends PureComponent<IProps, IState> {
renderFooter = { _shouldDisplayReactionsButtons && !toolbarButtons.has('raisehand')
? this._renderReactionMenu
: undefined }>
{ this._renderCustomOverflowMenuButtons(topButtonProps) }
<OpenCarmodeButton { ...topButtonProps } />
<AudioOnlyButton { ...buttonProps } />
{
Expand Down Expand Up @@ -187,7 +195,7 @@ class OverflowMenu extends PureComponent<IProps, IState> {
/**
* Function to render the reaction menu as the footer of the bottom sheet.
*
* @returns {React$Element}
* @returns {React.ReactElement}
*/
_renderReactionMenu() {
return (
Expand All @@ -196,6 +204,41 @@ class OverflowMenu extends PureComponent<IProps, IState> {
overflowMenu = { true } />
);
}

/**
* Function to render the custom buttons for the overflow menu.
*
* @param {Object} topButtonProps - Button properties.
* @returns {React.ReactElement}
*/
_renderCustomOverflowMenuButtons(topButtonProps: Object) {
const { _customToolbarButtons, dispatch } = this.props;

if (!_customToolbarButtons?.length) {
return;
}

return (
<>
{
_customToolbarButtons.map(({ id, text, icon, ...rest }) => (
<CustomOptionButton
{ ...rest }
{ ...topButtonProps }

/* eslint-disable react/jsx-no-bind */
handleClick = { () =>
dispatch(customOverflowMenuButtonPressed(id, text))
}
icon = { icon }
key = { id }
text = { text } />
))
}
<Divider style = { styles.divider as ViewStyle } />
</>
);
}
}

/**
Expand All @@ -207,8 +250,10 @@ class OverflowMenu extends PureComponent<IProps, IState> {
*/
function _mapStateToProps(state: IReduxState) {
const { conference } = state['features/base/conference'];
const { customToolbarButtons } = state['features/base/config'];

return {
_customToolbarButtons: customToolbarButtons,
_isBreakoutRoomsSupported: conference?.getBreakoutRooms()?.isSupported(),
_isSpeakerStatsDisabled: isSpeakerStatsDisabled(state),
_shouldDisplayReactionsButtons: shouldDisplayReactionsButtons(state),
Expand Down
5 changes: 5 additions & 0 deletions react/features/toolbox/components/native/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ const styles = {
marginLeft: 'auto',
marginRight: 'auto',
width: '100%'
},

iconImageStyles: {
height: BaseTheme.spacing[5],
width: BaseTheme.spacing[5]
}
};

Expand Down

0 comments on commit 36671d7

Please sign in to comment.