mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2025-12-30 03:12:29 +00:00
feat(toolbox/native): custom overflow menu buttons (#14594)
* feat(toolbox/native): custom buttons for the OverflowMenu
This commit is contained in:
@@ -90,7 +90,8 @@ public class BroadcastEvent {
|
||||
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";
|
||||
@@ -108,6 +109,7 @@ public class BroadcastEvent {
|
||||
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;
|
||||
|
||||
@@ -162,6 +164,8 @@ public class BroadcastEvent {
|
||||
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;
|
||||
|
||||
@@ -257,6 +257,10 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
|
||||
// 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
|
||||
@@ -344,6 +348,9 @@ public class JitsiMeetActivity extends AppCompatActivity
|
||||
break;
|
||||
// case TRANSCRIPTION_CHUNK_RECEIVED:
|
||||
// onTranscriptionChunkReceived(event.getData());
|
||||
// break;
|
||||
// case CUSTOM_OVERFLOW_MENU_BUTTON_PRESSED:
|
||||
// onCustomOverflowMenuButtonPressed(event.getData());
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@
|
||||
[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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
@@ -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.
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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));
|
||||
@@ -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';
|
||||
@@ -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';
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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 } />
|
||||
{
|
||||
@@ -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 (
|
||||
@@ -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 } />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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),
|
||||
|
||||
@@ -103,6 +103,11 @@ const styles = {
|
||||
marginLeft: 'auto',
|
||||
marginRight: 'auto',
|
||||
width: '100%'
|
||||
},
|
||||
|
||||
iconImageStyles: {
|
||||
height: BaseTheme.spacing[5],
|
||||
width: BaseTheme.spacing[5]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user