mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2026-04-29 12:50:16 +00:00
Compare commits
8 Commits
android-ap
...
7241
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43be4324af | ||
|
|
c33baf4c96 | ||
|
|
f95a356025 | ||
|
|
1ba7765898 | ||
|
|
0346fca434 | ||
|
|
d267b2499d | ||
|
|
e3e5f1fbfa | ||
|
|
4697192b43 |
@@ -19,7 +19,7 @@ buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "31.0.0"
|
||||
compileSdkVersion = 32
|
||||
minSdkVersion = 23
|
||||
minSdkVersion = 24
|
||||
targetSdkVersion = 32
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
|
||||
@@ -74,10 +74,6 @@
|
||||
a:active {
|
||||
color: black;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-corner {
|
||||
background: #3a3a3a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -98,7 +98,6 @@ platform :ios do
|
||||
demo_account_required: false,
|
||||
distribute_external: true,
|
||||
groups: ENV["JITSI_BETA_TESTING_GROUPS"],
|
||||
reject_build_waiting_for_review: true,
|
||||
uses_non_exempt_encryption: false
|
||||
)
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ type Props = {
|
||||
/**
|
||||
* Function to render a bottom sheet footer element, if necessary.
|
||||
*/
|
||||
renderFooter?: Function;
|
||||
renderFooter?: () => React.ReactNode;
|
||||
|
||||
/**
|
||||
* Function to render a bottom sheet header element, if necessary.
|
||||
|
||||
@@ -18,7 +18,7 @@ interface IProps extends AbstractProps, WithTranslation {
|
||||
/**
|
||||
* The dialog descriptionKey.
|
||||
*/
|
||||
descriptionKey: string;
|
||||
descriptionKey?: string;
|
||||
|
||||
/**
|
||||
* An optional initial value to initiate the field with.
|
||||
|
||||
@@ -43,7 +43,7 @@ export default class ToolboxItem extends AbstractToolboxItem<IProps> {
|
||||
* @returns {void}
|
||||
*/
|
||||
_onKeyPress(event?: React.KeyboardEvent) {
|
||||
if (event?.key === 'Enter' || event?.key === ' ') {
|
||||
if (event?.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
this.props.onClick();
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ const useStyles = makeStyles()(theme => {
|
||||
'& input[type="checkbox"]': {
|
||||
appearance: 'none',
|
||||
backgroundColor: 'transparent',
|
||||
margin: 0,
|
||||
margin: '3px',
|
||||
font: 'inherit',
|
||||
color: theme.palette.icon03,
|
||||
width: '18px',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-disable react/no-multi-comp */
|
||||
|
||||
import { useIsFocused } from '@react-navigation/native';
|
||||
import { Route, useIsFocused } from '@react-navigation/native';
|
||||
import React, { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -9,7 +8,7 @@ import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter';
|
||||
import { closeChat } from '../../actions.native';
|
||||
import AbstractChat, {
|
||||
type Props as AbstractProps,
|
||||
IProps as AbstractProps,
|
||||
_mapStateToProps
|
||||
} from '../AbstractChat';
|
||||
|
||||
@@ -18,24 +17,24 @@ import MessageContainer from './MessageContainer';
|
||||
import MessageRecipient from './MessageRecipient';
|
||||
import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
interface IProps extends AbstractProps {
|
||||
|
||||
/**
|
||||
* Default prop for navigating between screen components(React Navigation).
|
||||
*/
|
||||
navigation: Object,
|
||||
navigation: any;
|
||||
|
||||
/**
|
||||
* Default prop for navigating between screen components(React Navigation).
|
||||
*/
|
||||
route: Object
|
||||
};
|
||||
route: Route<'', { privateMessageRecipient: { name: string; }; }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a React native component that renders the chat window (modal) of
|
||||
* the mobile client.
|
||||
*/
|
||||
class Chat extends AbstractChat<Props> {
|
||||
class Chat extends AbstractChat<IProps> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -51,17 +50,16 @@ class Chat extends AbstractChat<Props> {
|
||||
hasBottomTextInput = { true }
|
||||
hasTabNavigator = { true }
|
||||
style = { styles.chatContainer }>
|
||||
{/* @ts-ignore */}
|
||||
<MessageContainer messages = { _messages } />
|
||||
<MessageRecipient privateMessageRecipient = { privateMessageRecipient } />
|
||||
<ChatInputBar onSend = { this._onSendMessage } />
|
||||
</JitsiScreen>
|
||||
);
|
||||
}
|
||||
|
||||
_onSendMessage: (string) => void;
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps)(props => {
|
||||
export default translate(connect(_mapStateToProps)((props: IProps) => {
|
||||
const { _nbUnreadMessages, dispatch, navigation, t } = props;
|
||||
const unreadMessagesNr = _nbUnreadMessages > 0;
|
||||
|
||||
@@ -78,7 +76,9 @@ export default translate(connect(_mapStateToProps)(props => {
|
||||
)
|
||||
});
|
||||
|
||||
return () => isFocused && dispatch(closeChat());
|
||||
return () => {
|
||||
isFocused && dispatch(closeChat());
|
||||
};
|
||||
}, [ isFocused, _nbUnreadMessages ]);
|
||||
|
||||
return (
|
||||
@@ -1,5 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { CHAT_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -10,23 +11,23 @@ import { screen } from '../../../mobile/navigation/routes';
|
||||
import { getUnreadPollCount } from '../../../polls/functions';
|
||||
import { getUnreadCount } from '../../functions';
|
||||
|
||||
type Props = AbstractButtonProps & {
|
||||
interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* True if the polls feature is disabled.
|
||||
*/
|
||||
_isPollsDisabled: boolean,
|
||||
_isPollsDisabled?: boolean;
|
||||
|
||||
/**
|
||||
* The unread message count.
|
||||
*/
|
||||
_unreadMessageCount: number
|
||||
};
|
||||
_unreadMessageCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements an {@link AbstractButton} to open the chat screen on mobile.
|
||||
*/
|
||||
class ChatButton extends AbstractButton<Props, *> {
|
||||
class ChatButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.chat';
|
||||
icon = IconMessage;
|
||||
label = 'toolbar.chat';
|
||||
@@ -60,9 +61,9 @@ class ChatButton extends AbstractButton<Props, *> {
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The properties explicitly passed to the component instance.
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
|
||||
const { disablePolls } = state['features/base/config'];
|
||||
const { visible = enabled } = ownProps;
|
||||
@@ -25,10 +25,6 @@ class ChatPrivacyDialog extends AbstractChatPrivacyDialog {
|
||||
onSubmit = { this._onSendPrivateMessage } />
|
||||
);
|
||||
}
|
||||
|
||||
_onSendGroupMessage: () => boolean;
|
||||
|
||||
_onSendPrivateMessage: () => boolean;
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(ChatPrivacyDialog));
|
||||
@@ -1,63 +1,65 @@
|
||||
import React from 'react';
|
||||
import { Text, TouchableHighlight, View } from 'react-native';
|
||||
import { Text, TouchableHighlight, View, ViewStyle } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { IconCloseLarge } from '../../../base/icons/svg';
|
||||
import { ILocalParticipant } from '../../../base/participants/types';
|
||||
import {
|
||||
setParams
|
||||
} from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { setLobbyChatActiveState, setPrivateMessageRecipient } from '../../actions.any';
|
||||
import AbstractMessageRecipient, {
|
||||
type Props as AbstractProps
|
||||
IProps as AbstractProps
|
||||
} from '../AbstractMessageRecipient';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
type Props = AbstractProps & {
|
||||
interface IProps extends AbstractProps {
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
dispatch: IStore['dispatch'];
|
||||
|
||||
/**
|
||||
* Is lobby messaging active.
|
||||
*/
|
||||
isLobbyChatActive: boolean,
|
||||
isLobbyChatActive: boolean;
|
||||
|
||||
/**
|
||||
* The participant string for lobby chat messaging.
|
||||
*/
|
||||
lobbyMessageRecipient: Object,
|
||||
lobbyMessageRecipient?: {
|
||||
id: string;
|
||||
name: string;
|
||||
} | ILocalParticipant;
|
||||
|
||||
/**
|
||||
* The participant object set for private messaging.
|
||||
*/
|
||||
privateMessageRecipient: Object,
|
||||
};
|
||||
privateMessageRecipient: { name: string; };
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to implement the displaying of the recipient of the next message.
|
||||
*/
|
||||
class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
class MessageRecipient extends AbstractMessageRecipient<IProps> {
|
||||
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @param {IProps} props - The props of the component.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._onResetPrivateMessageRecipient = this._onResetPrivateMessageRecipient.bind(this);
|
||||
this._onResetLobbyMessageRecipient = this._onResetLobbyMessageRecipient.bind(this);
|
||||
}
|
||||
|
||||
_onResetLobbyMessageRecipient: () => void;
|
||||
|
||||
/**
|
||||
* Resets lobby message recipient from state.
|
||||
*
|
||||
@@ -69,8 +71,6 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
dispatch(setLobbyChatActiveState(false));
|
||||
}
|
||||
|
||||
_onResetPrivateMessageRecipient: () => void;
|
||||
|
||||
/**
|
||||
* Resets private message recipient from state.
|
||||
*
|
||||
@@ -102,10 +102,10 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
|
||||
if (isLobbyChatActive) {
|
||||
return (
|
||||
<View style = { styles.lobbyMessageRecipientContainer }>
|
||||
<View style = { styles.lobbyMessageRecipientContainer as ViewStyle }>
|
||||
<Text style = { styles.messageRecipientText }>
|
||||
{ t('chat.lobbyChatMessageTo', {
|
||||
recipient: lobbyMessageRecipient.name
|
||||
recipient: lobbyMessageRecipient?.name
|
||||
}) }
|
||||
</Text>
|
||||
<TouchableHighlight
|
||||
@@ -123,7 +123,7 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
}
|
||||
|
||||
return (
|
||||
<View style = { styles.messageRecipientContainer }>
|
||||
<View style = { styles.messageRecipientContainer as ViewStyle }>
|
||||
<Text style = { styles.messageRecipientText }>
|
||||
{ t('chat.messageTo', {
|
||||
recipient: privateMessageRecipient.name
|
||||
@@ -145,9 +145,10 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
|
||||
* Maps part of the redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
* @param {any} _ownProps - Component's own props.
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState, _ownProps: any) {
|
||||
const { lobbyMessageRecipient, isLobbyChatActive } = state['features/chat'];
|
||||
|
||||
return {
|
||||
@@ -23,17 +23,21 @@ interface IProps extends AbstractProps {
|
||||
const styles = (theme: Theme) => {
|
||||
return {
|
||||
chatMessageWrapper: {
|
||||
maxWidth: '100%'
|
||||
maxWidth: '100%',
|
||||
|
||||
'&.remote': {
|
||||
maxWidth: 'calc(100% - 40px)' // 100% - avatar and margin
|
||||
}
|
||||
},
|
||||
|
||||
chatMessage: {
|
||||
display: 'inline-flex',
|
||||
padding: '12px',
|
||||
marginRight: '12px',
|
||||
backgroundColor: theme.palette.ui02,
|
||||
borderRadius: '4px 12px 12px 12px',
|
||||
maxWidth: '100%',
|
||||
marginTop: '4px',
|
||||
boxSizing: 'border-box' as const,
|
||||
|
||||
'&.privatemessage': {
|
||||
backgroundColor: theme.palette.support05
|
||||
@@ -62,7 +66,8 @@ const styles = (theme: Theme) => {
|
||||
replyWrapper: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row' as const,
|
||||
alignItems: 'center'
|
||||
alignItems: 'center',
|
||||
maxWidth: '100%'
|
||||
},
|
||||
|
||||
messageContent: {
|
||||
@@ -126,7 +131,7 @@ class ChatMessage extends AbstractChatMessage<IProps> {
|
||||
|
||||
return (
|
||||
<div
|
||||
className = { classes.chatMessageWrapper }
|
||||
className = { clsx(classes.chatMessageWrapper, type) }
|
||||
id = { this.props.message.messageId }
|
||||
tabIndex = { -1 }>
|
||||
<div
|
||||
|
||||
@@ -28,6 +28,13 @@ const useStyles = makeStyles()(theme => {
|
||||
color: theme.palette.text01
|
||||
},
|
||||
|
||||
text: {
|
||||
maxWidth: 'calc(100% - 30px)',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'break-spaces',
|
||||
wordBreak: 'break-all'
|
||||
},
|
||||
|
||||
iconButton: {
|
||||
padding: '2px',
|
||||
|
||||
@@ -72,7 +79,7 @@ const MessageRecipient = ({
|
||||
className = { classes.container }
|
||||
id = 'chat-recipient'
|
||||
role = 'alert'>
|
||||
<span>
|
||||
<span className = { classes.text }>
|
||||
{t(_isLobbyChatActive ? 'chat.lobbyChatMessageTo' : 'chat.messageTo', {
|
||||
recipient: _isLobbyChatActive ? _lobbyMessageRecipient : _privateMessageRecipient
|
||||
})}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { translate } from '../../../../base/i18n/functions';
|
||||
import { navigate }
|
||||
from '../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../../mobile/navigation/routes';
|
||||
import { IProps } from '../../LiveStream/AbstractStartLiveStreamDialog';
|
||||
import { IProps, _mapStateToProps as abstractMapStateToProps } from '../../LiveStream/AbstractStartLiveStreamDialog';
|
||||
import AbstractRecordButton, {
|
||||
IProps as AbstractProps,
|
||||
_mapStateToProps as _abstractMapStateToProps
|
||||
@@ -58,6 +58,7 @@ export function mapStateToProps(state: IReduxState) {
|
||||
|
||||
return {
|
||||
...abstractProps,
|
||||
...abstractMapStateToProps(state),
|
||||
visible: enabled && iosEnabled && abstractProps.visible
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Text, TouchableHighlight, View } from 'react-native';
|
||||
import { GestureResponderEvent, Text, TextStyle, TouchableHighlight, View, ViewStyle } from 'react-native';
|
||||
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { RECORD_TYPE } from '../../constants';
|
||||
@@ -12,69 +10,71 @@ import styles from './styles';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link RecordItem}.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The id of the record.
|
||||
*/
|
||||
id: String,
|
||||
id?: string;
|
||||
|
||||
/**
|
||||
* The name of the record.
|
||||
*/
|
||||
name: String,
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* The handler for the click event.
|
||||
*/
|
||||
onClick: Function,
|
||||
onClick?: (e?: GestureResponderEvent | React.MouseEvent) => void;
|
||||
|
||||
/**
|
||||
* The type of the record.
|
||||
*/
|
||||
type: String
|
||||
type?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component to render Record data.
|
||||
*
|
||||
* @param {Props} props - The props of the component.
|
||||
* @param {IProps} props - The props of the component.
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
export const RecordItem = ({
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
/* eslint-disable-next-line no-empty-function */
|
||||
/* eslint-disable-next-line @typescript-eslint/no-empty-function */
|
||||
onClick = () => {}
|
||||
}: Props) => {
|
||||
}: IProps) => {
|
||||
const { t } = useTranslation();
|
||||
const IconRecord = RECORD_TYPE[type].icon;
|
||||
const IconRecord = RECORD_TYPE[type ?? ''].icon;
|
||||
|
||||
return (
|
||||
<TouchableHighlight onPress = { onClick }>
|
||||
<View
|
||||
key = { `record-${id}` }
|
||||
style = { styles.recordItem }
|
||||
style = { styles.recordItem as ViewStyle }
|
||||
|
||||
// @ts-ignore
|
||||
title = { name }>
|
||||
<View style = { styles.recordTypeIcon }>
|
||||
<View style = { styles.recordTypeIcon as ViewStyle }>
|
||||
{IconRecord && (
|
||||
<Icon
|
||||
src = { IconRecord }
|
||||
style = { styles.recordIcon } />
|
||||
)}
|
||||
</View>
|
||||
<View style = { styles.recordDetails }>
|
||||
<View style = { styles.recordDetails as ViewStyle }>
|
||||
<Text
|
||||
key = { name }
|
||||
numberOfLines = { 1 }
|
||||
style = { styles.recordName }>
|
||||
style = { styles.recordName as TextStyle }>
|
||||
{name}
|
||||
</Text>
|
||||
<Text
|
||||
key = { type }
|
||||
style = { styles.recordType }>
|
||||
{t(RECORD_TYPE[type].label)}
|
||||
{t(RECORD_TYPE[type ?? ''].label)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Platform, SafeAreaView, ScrollView, Text, View } from 'react-native';
|
||||
import { Platform, SafeAreaView, ScrollView, Text, View, ViewStyle } from 'react-native';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { IconSearch } from '../../../base/icons/svg';
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import LoadingIndicator from '../../../base/react/components/native/LoadingIndicator';
|
||||
@@ -24,7 +25,7 @@ import styles from './styles';
|
||||
*/
|
||||
const SalesforceLinkDialog = () => {
|
||||
const { t } = useTranslation();
|
||||
const { clientHeight } = useSelector(state => state['features/base/responsive-ui']);
|
||||
const { clientHeight } = useSelector((state: IReduxState) => state['features/base/responsive-ui']);
|
||||
const {
|
||||
hasDetailsErrors,
|
||||
hasRecordsErrors,
|
||||
@@ -48,7 +49,7 @@ const SalesforceLinkDialog = () => {
|
||||
}, [ navigate, linkMeeting ]);
|
||||
|
||||
const renderSpinner = () => (
|
||||
<View style = { [ styles.recordsSpinner, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] }>
|
||||
<View style = { [ styles.recordsSpinner, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
|
||||
<LoadingIndicator />
|
||||
</View>
|
||||
);
|
||||
@@ -63,8 +64,8 @@ const SalesforceLinkDialog = () => {
|
||||
<SafeAreaView>
|
||||
<ScrollView
|
||||
bounces = { false }
|
||||
style = { [ styles.selectedRecord, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] }>
|
||||
<View style = { styles.recordInfo }>
|
||||
style = { [ styles.selectedRecord, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
|
||||
<View style = { styles.recordInfo as ViewStyle }>
|
||||
<RecordItem { ...selectedRecord } />
|
||||
{ selectedRecordOwner && <RecordItem { ...selectedRecordOwner } /> }
|
||||
{ hasDetailsErrors && renderDetailsErrors() }
|
||||
@@ -75,9 +76,9 @@ const SalesforceLinkDialog = () => {
|
||||
<Input
|
||||
customStyles = {{ container: styles.notes }}
|
||||
maxLength = { NOTES_MAX_LENGTH }
|
||||
minHeight = { Platform.OS === 'ios' && NOTES_LINES ? 20 * NOTES_LINES : null }
|
||||
minHeight = { Platform.OS === 'ios' && NOTES_LINES ? 20 * NOTES_LINES : undefined }
|
||||
multiline = { true }
|
||||
numberOfLines = { Platform.OS === 'ios' ? null : NOTES_LINES }
|
||||
numberOfLines = { Platform.OS === 'ios' ? undefined : NOTES_LINES }
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
onChange = { value => setNotes(value) }
|
||||
placeholder = { t('dialog.addMeetingNote') }
|
||||
@@ -87,14 +88,14 @@ const SalesforceLinkDialog = () => {
|
||||
);
|
||||
|
||||
const renderRecordsSearch = () => (
|
||||
<View style = { styles.recordsSearchContainer }>
|
||||
<View style = { styles.recordsSearchContainer as ViewStyle }>
|
||||
<Input
|
||||
icon = { IconSearch }
|
||||
maxLength = { NOTES_MAX_LENGTH }
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
onChange = { value => setSearchTerm(value) }
|
||||
placeholder = { t('dialog.searchInSalesforce') }
|
||||
value = { searchTerm } />
|
||||
value = { searchTerm ?? '' } />
|
||||
{(!isLoading && !hasRecordsErrors) && (
|
||||
<Text style = { styles.resultLabel }>
|
||||
{showSearchResults
|
||||
@@ -107,7 +108,7 @@ const SalesforceLinkDialog = () => {
|
||||
);
|
||||
|
||||
const renderNoRecords = () => showNoResults && (
|
||||
<View style = { [ styles.noRecords, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] }>
|
||||
<View style = { [ styles.noRecords, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
|
||||
<Text style = { styles.noRecordsText }>
|
||||
{t('dialog.searchResultsNotFound')}
|
||||
</Text>
|
||||
@@ -118,7 +119,7 @@ const SalesforceLinkDialog = () => {
|
||||
);
|
||||
|
||||
const renderRecordsError = () => (
|
||||
<View style = { [ styles.recordsError, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] }>
|
||||
<View style = { [ styles.recordsError, { height: clientHeight - CONTENT_HEIGHT_OFFSET } ] as ViewStyle[] }>
|
||||
<Text style = { styles.recordsErrorText }>
|
||||
{t('dialog.searchResultsError')}
|
||||
</Text>
|
||||
@@ -143,8 +144,8 @@ const SalesforceLinkDialog = () => {
|
||||
<SafeAreaView>
|
||||
<ScrollView
|
||||
bounces = { false }
|
||||
style = { [ styles.recordList, { height: clientHeight - LIST_HEIGHT_OFFSET } ] }>
|
||||
{records.map(item => (
|
||||
style = { [ styles.recordList, { height: clientHeight - LIST_HEIGHT_OFFSET } ] as ViewStyle[] }>
|
||||
{records.map((item: any) => (
|
||||
<RecordItem
|
||||
key = { `record-${item.id}` }
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
@@ -164,7 +165,7 @@ const SalesforceLinkDialog = () => {
|
||||
</View>
|
||||
{
|
||||
selectedRecord
|
||||
&& <View style = { styles.footer }>
|
||||
&& <View>
|
||||
<Button
|
||||
labelKey = 'dialog.Cancel'
|
||||
/* eslint-disable-next-line react/jsx-no-bind */
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { GestureResponderEvent } from 'react-native';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../app/types';
|
||||
@@ -21,7 +22,7 @@ import {
|
||||
interface ISelectedRecord {
|
||||
id: string;
|
||||
name: string;
|
||||
onClick: (e?: React.MouseEvent) => void;
|
||||
onClick: (e?: React.MouseEvent | GestureResponderEvent) => void;
|
||||
type: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import {
|
||||
Text,
|
||||
View
|
||||
TextStyle,
|
||||
View,
|
||||
ViewStyle
|
||||
} from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { IReduxState, IStore } from '../../../../app/types';
|
||||
import { IJitsiConference } from '../../../../base/conference/reducer';
|
||||
import { getSecurityUiConfig } from '../../../../base/config/functions.any';
|
||||
import { MEETING_PASSWORD_ENABLED } from '../../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../../base/flags/functions';
|
||||
@@ -40,94 +43,94 @@ const _TEXT_INPUT_PROPS = {
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link SecurityDialog}.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The JitsiConference which requires a password.
|
||||
*/
|
||||
_conference: Object,
|
||||
_conference?: IJitsiConference;
|
||||
|
||||
/**
|
||||
* Whether the local user is the moderator.
|
||||
*/
|
||||
_isModerator: boolean,
|
||||
_isModerator: boolean;
|
||||
|
||||
/**
|
||||
* State of the lobby mode.
|
||||
*/
|
||||
_lobbyEnabled: boolean,
|
||||
_lobbyEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether the lobby mode switch is available or not.
|
||||
*/
|
||||
_lobbyModeSwitchVisible: boolean,
|
||||
_lobbyModeSwitchVisible: boolean;
|
||||
|
||||
/**
|
||||
* The value for how the conference is locked (or undefined if not locked)
|
||||
* as defined by room-lock constants.
|
||||
*/
|
||||
_locked: string,
|
||||
_locked?: string;
|
||||
|
||||
/**
|
||||
* Checks if the conference room is locked or not.
|
||||
*/
|
||||
_lockedConference: boolean,
|
||||
_lockedConference: boolean;
|
||||
|
||||
/**
|
||||
* The current known password for the JitsiConference.
|
||||
*/
|
||||
_password: string,
|
||||
_password?: string;
|
||||
|
||||
/**
|
||||
* Number of digits used in the room-lock password.
|
||||
*/
|
||||
_passwordNumberOfDigits: number,
|
||||
_passwordNumberOfDigits?: number;
|
||||
|
||||
/**
|
||||
* Whether setting a room password is available or not.
|
||||
*/
|
||||
_roomPasswordControls: boolean,
|
||||
_roomPasswordControls: boolean;
|
||||
|
||||
/**
|
||||
* Redux store dispatch function.
|
||||
*/
|
||||
dispatch: Dispatch<any>,
|
||||
dispatch: IStore['dispatch'];
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
t: Function;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link SecurityDialog}.
|
||||
*/
|
||||
type State = {
|
||||
interface IState {
|
||||
|
||||
/**
|
||||
* Password added by the participant for room lock.
|
||||
*/
|
||||
passwordInputValue: string,
|
||||
passwordInputValue: string;
|
||||
|
||||
/**
|
||||
* Shows an input or a message.
|
||||
*/
|
||||
showElement: boolean
|
||||
};
|
||||
showElement: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that renders the security options dialog.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
class SecurityDialog extends PureComponent<Props, State> {
|
||||
class SecurityDialog extends PureComponent<IProps, IState> {
|
||||
|
||||
/**
|
||||
* Instantiates a new {@code SecurityDialog}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
@@ -180,8 +183,8 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
<Text style = { styles.lobbyModeText }>
|
||||
{ t('lobby.enableDialogText') }
|
||||
</Text>
|
||||
<View style = { styles.lobbyModeSection }>
|
||||
<Text style = { styles.lobbyModeLabel } >
|
||||
<View style = { styles.lobbyModeSection as ViewStyle }>
|
||||
<Text style = { styles.lobbyModeLabel as TextStyle } >
|
||||
{ t('lobby.toggleLabel') }
|
||||
</Text>
|
||||
<Switch
|
||||
@@ -267,7 +270,7 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
if (_locked === LOCKED_REMOTELY) {
|
||||
if (_isModerator) {
|
||||
setPasswordControls = (
|
||||
<View style = { styles.passwordSetRemotelyContainer }>
|
||||
<View style = { styles.passwordSetRemotelyContainer as ViewStyle }>
|
||||
<Text style = { styles.passwordSetRemotelyText }>
|
||||
{ t('passwordSetRemotely') }
|
||||
</Text>
|
||||
@@ -281,7 +284,7 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
);
|
||||
} else {
|
||||
setPasswordControls = (
|
||||
<View style = { styles.passwordSetRemotelyContainer }>
|
||||
<View style = { styles.passwordSetRemotelyContainer as ViewStyle }>
|
||||
<Text style = { styles.passwordSetRemotelyTextDisabled }>
|
||||
{ t('passwordSetRemotely') }
|
||||
</Text>
|
||||
@@ -306,7 +309,7 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
<View
|
||||
style = {
|
||||
_locked !== LOCKED_REMOTELY
|
||||
&& styles.passwordContainerControls
|
||||
&& styles.passwordContainerControls as ViewStyle
|
||||
}>
|
||||
<View>
|
||||
{ this._setRoomPasswordMessage() }
|
||||
@@ -324,7 +327,7 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
* @private
|
||||
*/
|
||||
_setRoomPasswordMessage() {
|
||||
let textInputProps = _TEXT_INPUT_PROPS;
|
||||
let textInputProps: any = _TEXT_INPUT_PROPS;
|
||||
const {
|
||||
_isModerator,
|
||||
_locked,
|
||||
@@ -362,8 +365,8 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
} else if (_locked) {
|
||||
if (_locked === LOCKED_LOCALLY && typeof _password !== 'undefined') {
|
||||
return (
|
||||
<View style = { styles.savedPasswordContainer }>
|
||||
<Text style = { styles.savedPasswordLabel }>
|
||||
<View style = { styles.savedPasswordContainer as ViewStyle }>
|
||||
<Text style = { styles.savedPasswordLabel as TextStyle }>
|
||||
{ t('info.password') }
|
||||
</Text>
|
||||
<Text style = { styles.savedPassword }>
|
||||
@@ -376,8 +379,6 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
_onToggleLobbyMode: () => void;
|
||||
|
||||
/**
|
||||
* Handles the enable-disable lobby mode switch.
|
||||
*
|
||||
@@ -394,8 +395,6 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
_onAddPassword: () => void;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when add password button is pressed.
|
||||
*
|
||||
@@ -431,15 +430,13 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
return true;
|
||||
}
|
||||
|
||||
_onChangeText: string => void;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the text in the field changes.
|
||||
*
|
||||
* @param {string} passwordInputValue - The value of password input.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onChangeText(passwordInputValue) {
|
||||
_onChangeText(passwordInputValue: string) {
|
||||
if (!this._validateInputValue(passwordInputValue)) {
|
||||
return;
|
||||
}
|
||||
@@ -449,8 +446,6 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
/**
|
||||
* Cancels value typed in text input.
|
||||
*
|
||||
@@ -465,8 +460,6 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
this.props.dispatch(unlockRoom());
|
||||
}
|
||||
|
||||
_onCopy: () => void;
|
||||
|
||||
/**
|
||||
* Copies room password.
|
||||
*
|
||||
@@ -478,8 +471,6 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
copyText(passwordInputValue);
|
||||
}
|
||||
|
||||
_onSubmit: () => void;
|
||||
|
||||
/**
|
||||
* Submits value typed in text input.
|
||||
*
|
||||
@@ -492,7 +483,7 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
} = this.props;
|
||||
const { passwordInputValue } = this.state;
|
||||
|
||||
dispatch(endRoomLockRequest(_conference, passwordInputValue));
|
||||
_conference && dispatch(endRoomLockRequest(_conference, passwordInputValue));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,14 +491,14 @@ class SecurityDialog extends PureComponent<Props, State> {
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: Object): Object {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { conference, locked, password } = state['features/base/conference'];
|
||||
const { disableLobbyPassword, hideLobbyButton } = getSecurityUiConfig(state);
|
||||
const { lobbyEnabled } = state['features/lobby'];
|
||||
const { roomPasswordNumberOfDigits } = state['features/base/config'];
|
||||
const lobbySupported = conference && conference.isLobbySupported();
|
||||
const lobbySupported = conference?.isLobbySupported();
|
||||
const visible = getFeatureFlag(state, MEETING_PASSWORD_ENABLED, true);
|
||||
|
||||
return {
|
||||
@@ -1,21 +1,17 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../../base/i18n/functions';
|
||||
import { navigate } from '../../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import { screen } from '../../../../mobile/navigation/routes';
|
||||
import AbstractSecurityDialogButton, {
|
||||
type Props as AbstractSecurityDialogButtonProps,
|
||||
IProps as AbstractSecurityDialogButtonProps,
|
||||
_mapStateToProps as _abstractMapStateToProps
|
||||
} from '../AbstractSecurityDialogButton';
|
||||
|
||||
type Props = AbstractSecurityDialogButtonProps;
|
||||
|
||||
/**
|
||||
* Implements an {@link AbstractSecurityDialogButton} to open the security screen.
|
||||
*/
|
||||
class SecurityDialogButton<P: Props, S:*> extends AbstractSecurityDialogButton<P, S> {
|
||||
class SecurityDialogButton<P extends AbstractSecurityDialogButtonProps, S> extends AbstractSecurityDialogButton<P, S> {
|
||||
|
||||
/**
|
||||
* Opens / closes the security screen.
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||
|
||||
/**
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { Text, View, ViewStyle } from 'react-native';
|
||||
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
|
||||
@@ -10,45 +9,40 @@ import styles, { ANDROID_UNDERLINE_COLOR, PLACEHOLDER_COLOR } from './styles';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link FormRow}.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
*
|
||||
* Component's children.
|
||||
*/
|
||||
children: Object,
|
||||
children: React.ReactElement;
|
||||
|
||||
/**
|
||||
* Prop to decide if a row separator is to be rendered.
|
||||
*/
|
||||
fieldSeparator: boolean,
|
||||
fieldSeparator?: boolean;
|
||||
|
||||
/**
|
||||
* The i18n key of the text label of the form field.
|
||||
*/
|
||||
label: string,
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* One of 'row' (default) or 'column'.
|
||||
*/
|
||||
layout: string,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
t: Function
|
||||
layout?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a React {@code Component} which renders a standardized row on a
|
||||
* form. The component should have exactly one child component.
|
||||
*/
|
||||
class FormRow extends Component<Props> {
|
||||
class FormRow extends Component<IProps> {
|
||||
/**
|
||||
* Initializes a new {@code FormRow} instance.
|
||||
*
|
||||
* @param {Object} props - Component properties.
|
||||
*/
|
||||
constructor(props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
React.Children.only(this.props.children);
|
||||
@@ -77,7 +71,7 @@ class FormRow extends Component<Props> {
|
||||
return (
|
||||
<View
|
||||
style = { this._getRowStyle() } >
|
||||
<View style = { styles.fieldLabelContainer } >
|
||||
<View style = { styles.fieldLabelContainer as ViewStyle } >
|
||||
<Text
|
||||
style = { [
|
||||
styles.text,
|
||||
@@ -87,15 +81,13 @@ class FormRow extends Component<Props> {
|
||||
{ t(this.props.label) }
|
||||
</Text>
|
||||
</View>
|
||||
<View style = { styles.fieldValueContainer } >
|
||||
<View style = { styles.fieldValueContainer as ViewStyle } >
|
||||
{ newChild }
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_getDefaultFieldProps: (field: Component<*, *>) => Object;
|
||||
|
||||
/**
|
||||
* Assembles the default props to the field child component of this form
|
||||
* row.
|
||||
@@ -108,8 +100,8 @@ class FormRow extends Component<Props> {
|
||||
* @private
|
||||
* @returns {Object}
|
||||
*/
|
||||
_getDefaultFieldProps(field: Object) {
|
||||
if (field && field.type) {
|
||||
_getDefaultFieldProps(field?: React.ReactElement) {
|
||||
if (field?.type) { // @ts-ignore
|
||||
switch (field.type.displayName) {
|
||||
case 'TextInput':
|
||||
return {
|
||||
@@ -126,8 +118,6 @@ class FormRow extends Component<Props> {
|
||||
return {};
|
||||
}
|
||||
|
||||
_getRowStyle: () => Array<Object>;
|
||||
|
||||
/**
|
||||
* Assembles the row style array based on the row's props.
|
||||
*
|
||||
@@ -136,8 +126,8 @@ class FormRow extends Component<Props> {
|
||||
*/
|
||||
_getRowStyle() {
|
||||
const { fieldSeparator, layout } = this.props;
|
||||
const rowStyle = [
|
||||
styles.fieldContainer
|
||||
const rowStyle: ViewStyle[] = [
|
||||
styles.fieldContainer as ViewStyle
|
||||
];
|
||||
|
||||
if (fieldSeparator) {
|
||||
@@ -146,7 +136,7 @@ class FormRow extends Component<Props> {
|
||||
|
||||
if (layout === 'column') {
|
||||
rowStyle.push(
|
||||
styles.fieldContainerColumn
|
||||
styles.fieldContainerColumn as ViewStyle
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Text, View } from 'react-native';
|
||||
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import { BUTTON_TYPES } from '../../../base/ui/constants.any';
|
||||
import { AVATAR_SIZE } from '../../../welcome/components/styles';
|
||||
import { isServerURLChangeEnabled, normalizeUserInputURL } from '../../functions.native';
|
||||
|
||||
// @ts-ignore
|
||||
import FormRow from './FormRow';
|
||||
import FormSection from './FormSection';
|
||||
import styles from './styles';
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { VIDEO_SHARE_BUTTON_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -15,30 +13,25 @@ import { isSharingStatus } from '../../functions';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link TileViewButton}.
|
||||
*/
|
||||
type Props = AbstractButtonProps & {
|
||||
interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* Whether or not the button is disabled.
|
||||
*/
|
||||
_isDisabled: boolean,
|
||||
_isDisabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the local participant is sharing a video.
|
||||
*/
|
||||
_sharingVideo: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Dispatch<any>
|
||||
};
|
||||
_sharingVideo: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that renders a toolbar button for toggling the tile layout view.
|
||||
*
|
||||
* @augments AbstractButton
|
||||
*/
|
||||
class VideoShareButton extends AbstractButton<Props, *> {
|
||||
class VideoShareButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.sharedvideo';
|
||||
icon = IconPlay;
|
||||
label = 'toolbar.sharedvideo';
|
||||
@@ -94,17 +87,17 @@ class VideoShareButton extends AbstractButton<Props, *> {
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The properties explicitly passed to the component instance.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps): Object {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { ownerId, status: sharedVideoStatus } = state['features/shared-video'];
|
||||
const localParticipantId = getLocalParticipant(state).id;
|
||||
const localParticipantId = getLocalParticipant(state)?.id;
|
||||
const enabled = getFeatureFlag(state, VIDEO_SHARE_BUTTON_ENABLED, true);
|
||||
const { visible = enabled } = ownProps;
|
||||
|
||||
if (ownerId !== localParticipantId) {
|
||||
return {
|
||||
_isDisabled: isSharingStatus(sharedVideoStatus),
|
||||
_isDisabled: isSharingStatus(sharedVideoStatus ?? ''),
|
||||
_sharingVideo: false,
|
||||
visible
|
||||
};
|
||||
@@ -112,7 +105,7 @@ function _mapStateToProps(state, ownProps): Object {
|
||||
|
||||
return {
|
||||
_isDisabled: false,
|
||||
_sharingVideo: isSharingStatus(sharedVideoStatus),
|
||||
_sharingVideo: isSharingStatus(sharedVideoStatus ?? ''),
|
||||
visible
|
||||
};
|
||||
}
|
||||
@@ -1,22 +1,24 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import InputDialog from '../../../base/dialog/components/native/InputDialog';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import AbstractSharedVideoDialog from '../AbstractSharedVideoDialog';
|
||||
import AbstractSharedVideoDialog, { IProps } from '../AbstractSharedVideoDialog';
|
||||
|
||||
interface IState {
|
||||
error: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a component to render a display name prompt.
|
||||
*/
|
||||
class SharedVideoDialog extends AbstractSharedVideoDialog<*> {
|
||||
class SharedVideoDialog extends AbstractSharedVideoDialog<IState> {
|
||||
/**
|
||||
* Instantiates a new component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
@@ -26,15 +28,13 @@ class SharedVideoDialog extends AbstractSharedVideoDialog<*> {
|
||||
this._onSubmitValue = this._onSubmitValue.bind(this);
|
||||
}
|
||||
|
||||
_onSubmitValue: () => boolean;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the value of the link input is submitted.
|
||||
*
|
||||
* @param {string} value - The entered video link.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onSubmitValue(value) {
|
||||
_onSubmitValue(value: string) {
|
||||
const result = super._onSetVideoLink(value);
|
||||
|
||||
if (!result) {
|
||||
@@ -2,8 +2,7 @@ import React, { useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { resetSearchCriteria } from '../../actions';
|
||||
|
||||
import { resetSearchCriteria } from '../../actions.native';
|
||||
|
||||
import SpeakerStatsList from './SpeakerStatsList';
|
||||
import SpeakerStatsSearch from './SpeakerStatsSearch';
|
||||
@@ -1,9 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { SPEAKERSTATS_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -39,7 +38,7 @@ class SpeakerStatsButton extends AbstractSpeakerStatsButton {
|
||||
* visible: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const enabled = getFeatureFlag(state, SPEAKERSTATS_ENABLED, true);
|
||||
|
||||
return {
|
||||
@@ -1,7 +1,5 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { Text, View, ViewStyle } from 'react-native';
|
||||
|
||||
import Avatar from '../../../base/avatar/components/Avatar';
|
||||
import StatelessAvatar from '../../../base/avatar/components/native/StatelessAvatar';
|
||||
@@ -11,46 +9,44 @@ import BaseTheme from '../../../base/ui/components/BaseTheme.native';
|
||||
import TimeElapsed from './TimeElapsed';
|
||||
import style from './styles';
|
||||
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The name of the participant.
|
||||
*/
|
||||
displayName: string,
|
||||
displayName: string;
|
||||
|
||||
/**
|
||||
* The total milliseconds the participant has been dominant speaker.
|
||||
*/
|
||||
dominantSpeakerTime: number,
|
||||
|
||||
/**
|
||||
* The id of the user.
|
||||
*/
|
||||
participantId: string,
|
||||
dominantSpeakerTime: number;
|
||||
|
||||
/**
|
||||
* True if the participant is no longer in the meeting.
|
||||
*/
|
||||
hasLeft: boolean,
|
||||
hasLeft: boolean;
|
||||
|
||||
/**
|
||||
* True if the participant is currently the dominant speaker.
|
||||
*/
|
||||
isDominantSpeaker: boolean
|
||||
};
|
||||
isDominantSpeaker: boolean;
|
||||
|
||||
const SpeakerStatsItem = (props: Props) =>
|
||||
/**
|
||||
* The id of the user.
|
||||
*/
|
||||
participantId: string;
|
||||
}
|
||||
|
||||
const SpeakerStatsItem = (props: IProps) =>
|
||||
(
|
||||
<View
|
||||
key = { props.participantId }
|
||||
style = { style.speakerStatsItemContainer }>
|
||||
style = { style.speakerStatsItemContainer as ViewStyle }>
|
||||
<View style = { style.speakerStatsAvatar }>
|
||||
{
|
||||
props.hasLeft ? (
|
||||
<StatelessAvatar
|
||||
className = 'userAvatar'
|
||||
color = { BaseTheme.palette.ui05 }
|
||||
id = 'avatar'
|
||||
initials = { getInitials(props.displayName) }
|
||||
size = { BaseTheme.spacing[5] } />
|
||||
) : (
|
||||
@@ -61,7 +57,7 @@ const SpeakerStatsItem = (props: Props) =>
|
||||
)
|
||||
}
|
||||
</View>
|
||||
<View style = { style.speakerStatsNameTime } >
|
||||
<View style = { style.speakerStatsNameTime as ViewStyle } >
|
||||
<Text style = { [ style.speakerStatsText, props.hasLeft && style.speakerStatsLeft ] }>
|
||||
{props.displayName}
|
||||
</Text>
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
|
||||
@@ -22,5 +20,4 @@ const SpeakerStatsList = () => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default SpeakerStatsList;
|
||||
@@ -6,12 +6,11 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { IconSearch } from '../../../base/icons/svg';
|
||||
import Input from '../../../base/ui/components/native/Input';
|
||||
import { escapeRegexp } from '../../../base/util/helpers';
|
||||
import { initSearch } from '../../actions';
|
||||
import { initSearch } from '../../actions.native';
|
||||
import { isSpeakerStatsSearchDisabled } from '../../functions';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* React component for display an individual user's speaker stats.
|
||||
*
|
||||
@@ -1,6 +1,5 @@
|
||||
/* @flow */
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -9,23 +8,18 @@ import { createLocalizedTime } from '../timeFunctions';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link TimeElapsed}.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps extends WithTranslation {
|
||||
|
||||
/**
|
||||
* Style for text.
|
||||
*/
|
||||
style: Object,
|
||||
|
||||
/**
|
||||
* The function to translate human-readable text.
|
||||
*/
|
||||
t: Function,
|
||||
style: Object;
|
||||
|
||||
/**
|
||||
* The milliseconds to be converted into a human-readable format.
|
||||
*/
|
||||
time: number
|
||||
};
|
||||
time: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* React component for displaying total time elapsed. Converts a total count of
|
||||
@@ -34,7 +28,7 @@ type Props = {
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class TimeElapsed extends PureComponent<Props> {
|
||||
class TimeElapsed extends PureComponent<IProps> {
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
@@ -1,12 +1,8 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React, { ReactElement } from 'react';
|
||||
import { GestureResponderEvent, StyleProp } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
// @ts-ignore
|
||||
import Container from '../../../base/react/components/native/Container';
|
||||
// @ts-ignore
|
||||
import Text from '../../../base/react/components/native/Text';
|
||||
import {
|
||||
AbstractCaptions,
|
||||
@@ -14,10 +10,8 @@ import {
|
||||
_abstractMapStateToProps
|
||||
} from '../AbstractCaptions';
|
||||
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link Captions}.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
@@ -8,17 +6,13 @@ import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconSubtitles } from '../../../base/icons/svg';
|
||||
import { navigate }
|
||||
// @ts-ignore
|
||||
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
// @ts-ignore
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
import {
|
||||
AbstractClosedCaptionButton,
|
||||
IAbstractProps,
|
||||
_abstractMapStateToProps
|
||||
} from '../AbstractClosedCaptionButton';
|
||||
|
||||
|
||||
/**
|
||||
* A button which starts/stops the transcriptions.
|
||||
*/
|
||||
@@ -52,7 +46,7 @@ class ClosedCaptionButton
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
export function mapStateToProps(state: IReduxState, ownProps: IAbstractProps) {
|
||||
export function mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const enabled = getFeatureFlag(state, CLOSE_CAPTIONS_ENABLED, true);
|
||||
const abstractProps = _abstractMapStateToProps(state, ownProps);
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React from 'react';
|
||||
import { ScrollView } from 'react-native';
|
||||
|
||||
import LanguageListItem from './LanguageListItem';
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
interface ILanguageListProps {
|
||||
@@ -13,7 +10,6 @@ interface ILanguageListProps {
|
||||
selectedLanguage: string;
|
||||
}
|
||||
|
||||
|
||||
interface ILanguageItem {
|
||||
id: string;
|
||||
lang: string;
|
||||
@@ -30,7 +26,6 @@ const LanguageList = ({ items, onLanguageSelected }: ILanguageListProps) => {
|
||||
const listItems = items?.map(item => (
|
||||
<LanguageListItem
|
||||
key = { item.id }
|
||||
// @ts-ignore
|
||||
lang = { item.lang }
|
||||
onLanguageSelected = { onLanguageSelected }
|
||||
selected = { item.selected } />
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { StyleProp, TouchableHighlight, View, ViewStyle } from 'react-native';
|
||||
@@ -9,7 +7,6 @@ import { translate } from '../../../base/i18n/functions';
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { IconCheck } from '../../../base/icons/svg';
|
||||
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
// @ts-ignore
|
||||
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
|
||||
import { goBack }
|
||||
// @ts-ignore
|
||||
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
import AbstractLanguageSelectorDialog, {
|
||||
IAbstractLanguageSelectorDialogProps
|
||||
} from '../AbstractLanguageSelectorDialog';
|
||||
|
||||
import LanguageList from './LanguageList';
|
||||
// @ts-ignore
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
const LanguageSelectorDialog = (props: IAbstractLanguageSelectorDialogProps) => {
|
||||
const { language, listItems, onLanguageSelected, subtitles } = props;
|
||||
|
||||
@@ -25,7 +19,6 @@ const LanguageSelectorDialog = (props: IAbstractLanguageSelectorDialogProps) =>
|
||||
}, [ language ]);
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<JitsiScreen
|
||||
disableForcedKeyboardDismiss = { true }
|
||||
style = { styles.subtitlesContainer }>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { setAudioOnly, toggleAudioOnly } from '../../../base/audio-only/actions';
|
||||
import { AUDIO_ONLY_BUTTON_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
@@ -16,28 +15,23 @@ import { screen } from '../../../mobile/navigation/routes';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link AudioOnlyButton}.
|
||||
*/
|
||||
type Props = AbstractButtonProps & {
|
||||
interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* Whether the current conference is in audio only mode or not.
|
||||
*/
|
||||
_audioOnly: boolean,
|
||||
_audioOnly: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether the car mode is enabled.
|
||||
*/
|
||||
_startCarMode: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
_startCarMode?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for toggling the audio-only mode.
|
||||
*/
|
||||
class AudioOnlyButton extends AbstractButton<Props, *> {
|
||||
class AudioOnlyButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.audioOnly';
|
||||
icon = IconAudioOnly;
|
||||
label = 'toolbar.audioOnlyOn';
|
||||
@@ -86,7 +80,7 @@ class AudioOnlyButton extends AbstractButton<Props, *> {
|
||||
* _audioOnly: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps): Object {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||
const enabledInFeatureFlags = getFeatureFlag(state, AUDIO_ONLY_BUTTON_ENABLED, true);
|
||||
const { startCarMode } = state['features/base/settings'];
|
||||
@@ -1,17 +1,14 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
import React, { useCallback } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import { createBreakoutRoomsEvent, createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
// @ts-ignore
|
||||
import { appNavigate } from '../../../app/actions';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import ColorSchemeRegistry from '../../../base/color-scheme/ColorSchemeRegistry';
|
||||
import { endConference } from '../../../base/conference/actions';
|
||||
import { hideSheet } from '../../../base/dialog/actions';
|
||||
// @ts-ignore
|
||||
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
|
||||
import { PARTICIPANT_ROLE } from '../../../base/participants/constants';
|
||||
import { getLocalParticipant } from '../../../base/participants/functions';
|
||||
|
||||
@@ -8,7 +8,6 @@ import { BUTTON_TYPES } from '../../../base/ui/constants.native';
|
||||
|
||||
import HangupMenu from './HangupMenu';
|
||||
|
||||
|
||||
/**
|
||||
* Button for showing the hangup menu.
|
||||
*
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconCloudUpload } from '../../../base/icons/svg';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
@@ -15,7 +14,7 @@ import { isSalesforceEnabled } from '../../../salesforce/functions';
|
||||
/**
|
||||
* Implementation of a button for opening the Salesforce link dialog.
|
||||
*/
|
||||
class LinkToSalesforceButton extends AbstractButton<AbstractButtonProps, *> {
|
||||
class LinkToSalesforceButton extends AbstractButton<AbstractButtonProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.linkToSalesforce';
|
||||
icon = IconCloudUpload;
|
||||
label = 'toolbar.linkToSalesforce';
|
||||
@@ -40,7 +39,7 @@ class LinkToSalesforceButton extends AbstractButton<AbstractButtonProps, *> {
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
visible: isSalesforceEnabled(state)
|
||||
};
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable lines-around-comment */
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
@@ -8,9 +7,7 @@ import { translate } from '../../../base/i18n/functions';
|
||||
import { IconCar } from '../../../base/icons/svg';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { navigate }
|
||||
// @ts-ignore
|
||||
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||
// @ts-ignore
|
||||
import { screen } from '../../../mobile/navigation/routes';
|
||||
/* eslint-enable lines-around-comment */
|
||||
|
||||
@@ -50,5 +47,4 @@ function _mapStateToProps(state: IReduxState, ownProps: AbstractButtonProps): Ob
|
||||
};
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
export default translate(connect(_mapStateToProps)(OpenCarmodeButton));
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { ViewStyle } from 'react-native';
|
||||
import { Divider } from 'react-native-paper';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import { hideSheet } from '../../../base/dialog/actions';
|
||||
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
|
||||
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
|
||||
@@ -32,58 +32,58 @@ import ScreenSharingButton from './ScreenSharingButton';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link OverflowMenu}.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* True if the overflow menu is currently visible, false otherwise.
|
||||
*/
|
||||
_isOpen: boolean,
|
||||
|
||||
/**
|
||||
* Whether the recoding button should be enabled or not.
|
||||
*/
|
||||
_recordingEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The width of the screen.
|
||||
*/
|
||||
_width: number,
|
||||
|
||||
/**
|
||||
* Whether or not the reactions feature is enabled.
|
||||
*/
|
||||
_reactionsEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Used for hiding the dialog when the selection was completed.
|
||||
*/
|
||||
dispatch: Function,
|
||||
_isOpen: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not speaker stats is disable.
|
||||
*/
|
||||
_isSpeakerStatsDisabled: boolean
|
||||
};
|
||||
|
||||
type State = {
|
||||
_isSpeakerStatsDisabled?: boolean;
|
||||
|
||||
/**
|
||||
* True if the bottom scheet is scrolled to the top.
|
||||
* Whether or not the reactions feature is enabled.
|
||||
*/
|
||||
scrolledToTop: boolean
|
||||
_reactionsEnabled: boolean;
|
||||
|
||||
/**
|
||||
* Whether the recoding button should be enabled or not.
|
||||
*/
|
||||
_recordingEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The width of the screen.
|
||||
*/
|
||||
_width: number;
|
||||
|
||||
/**
|
||||
* Used for hiding the dialog when the selection was completed.
|
||||
*/
|
||||
dispatch: IStore['dispatch'];
|
||||
}
|
||||
|
||||
interface IState {
|
||||
|
||||
/**
|
||||
* True if the bottom sheet is scrolled to the top.
|
||||
*/
|
||||
scrolledToTop: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a React {@code Component} with some extra actions in addition to
|
||||
* those in the toolbar.
|
||||
*/
|
||||
class OverflowMenu extends PureComponent<Props, State> {
|
||||
class OverflowMenu extends PureComponent<IProps, IState> {
|
||||
/**
|
||||
* Initializes a new {@code OverflowMenu} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
@@ -105,7 +105,8 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||
const {
|
||||
_isSpeakerStatsDisabled,
|
||||
_reactionsEnabled,
|
||||
_width
|
||||
_width,
|
||||
dispatch
|
||||
} = this.props;
|
||||
const toolbarButtons = getMovableButtons(_width);
|
||||
|
||||
@@ -117,6 +118,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||
|
||||
const topButtonProps = {
|
||||
afterClick: this._onCancel,
|
||||
dispatch,
|
||||
showLabel: true,
|
||||
styles: {
|
||||
...bottomSheetStyles.buttons,
|
||||
@@ -132,21 +134,24 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||
<BottomSheet
|
||||
renderFooter = { _reactionsEnabled && !toolbarButtons.has('raisehand')
|
||||
? this._renderReactionMenu
|
||||
: null }>
|
||||
: undefined }>
|
||||
<OpenCarmodeButton { ...topButtonProps } />
|
||||
<AudioOnlyButton { ...buttonProps } />
|
||||
{!_reactionsEnabled && !toolbarButtons.has('raisehand') && <RaiseHandButton { ...buttonProps } />}
|
||||
<Divider style = { styles.divider } />
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.divider as ViewStyle } />
|
||||
<SecurityDialogButton { ...buttonProps } />
|
||||
<RecordButton { ...buttonProps } />
|
||||
<LiveStreamButton { ...buttonProps } />
|
||||
<LinkToSalesforceButton { ...buttonProps } />
|
||||
<Divider style = { styles.divider } />
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.divider as ViewStyle } />
|
||||
<SharedVideoButton { ...buttonProps } />
|
||||
{!toolbarButtons.has('screensharing') && <ScreenSharingButton { ...buttonProps } />}
|
||||
{!_isSpeakerStatsDisabled && <SpeakerStatsButton { ...buttonProps } />}
|
||||
{!toolbarButtons.has('tileview') && <TileViewButton { ...buttonProps } />}
|
||||
<Divider style = { styles.divider } />
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.divider as ViewStyle } />
|
||||
<ClosedCaptionButton { ...buttonProps } />
|
||||
<SharedDocumentButton { ...buttonProps } />
|
||||
<SettingsButton { ...buttonProps } />
|
||||
@@ -165,7 +170,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Functoin to render the reaction menu as the footer of the bottom sheet.
|
||||
* Function to render the reaction menu as the footer of the bottom sheet.
|
||||
*
|
||||
* @returns {React$Element}
|
||||
*/
|
||||
@@ -181,9 +186,9 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
_isSpeakerStatsDisabled: isSpeakerStatsDisabled(state),
|
||||
_reactionsEnabled: isReactionsEnabled(state),
|
||||
@@ -1,5 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { openSheet } from '../../../base/dialog/actions';
|
||||
import { OVERFLOW_MENU_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
@@ -9,21 +10,10 @@ import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/too
|
||||
|
||||
import OverflowMenu from './OverflowMenu';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link OverflowMenuButton}.
|
||||
*/
|
||||
type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
|
||||
/**
|
||||
* An implementation of a button for showing the {@code OverflowMenu}.
|
||||
*/
|
||||
class OverflowMenuButton extends AbstractButton<Props, *> {
|
||||
class OverflowMenuButton extends AbstractButton<AbstractButtonProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.moreActions';
|
||||
icon = IconDotsHorizontal;
|
||||
label = 'toolbar.moreActions';
|
||||
@@ -47,7 +37,7 @@ class OverflowMenuButton extends AbstractButton<Props, *> {
|
||||
* @private
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const enabledFlag = getFeatureFlag(state, OVERFLOW_MENU_ENABLED, true);
|
||||
|
||||
return {
|
||||
@@ -1,10 +1,8 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { type Dispatch } from 'redux';
|
||||
|
||||
import { createToolbarEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { RAISE_HAND_ENABLED } from '../../../base/flags/constants';
|
||||
import { getFeatureFlag } from '../../../base/flags/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -14,33 +12,29 @@ import {
|
||||
getLocalParticipant,
|
||||
hasRaisedHand
|
||||
} from '../../../base/participants/functions';
|
||||
import { ILocalParticipant } from '../../../base/participants/types';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link RaiseHandButton}.
|
||||
*/
|
||||
type Props = AbstractButtonProps & {
|
||||
interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* The local participant.
|
||||
*/
|
||||
_localParticipant: Object,
|
||||
_localParticipant?: ILocalParticipant;
|
||||
|
||||
/**
|
||||
* Whether the participant raused their hand or not.
|
||||
* Whether the participant raised their hand or not.
|
||||
*/
|
||||
_raisedHand: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Dispatch<any>
|
||||
};
|
||||
_raisedHand: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button to raise or lower hand.
|
||||
*/
|
||||
class RaiseHandButton extends AbstractButton<Props, *> {
|
||||
class RaiseHandButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.raiseHand';
|
||||
icon = IconRaiseHand;
|
||||
label = 'toolbar.raiseYourHand';
|
||||
@@ -88,9 +82,9 @@ class RaiseHandButton extends AbstractButton<Props, *> {
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The properties explicitly passed to the component instance.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps): Object {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const _localParticipant = getLocalParticipant(state);
|
||||
const enabled = getFeatureFlag(state, RAISE_HAND_ENABLED, true);
|
||||
const { visible = enabled } = ownProps;
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconCameraRefresh } from '../../../base/icons/svg';
|
||||
import { toggleCameraFacingMode } from '../../../base/media/actions';
|
||||
@@ -12,28 +11,23 @@ import { isLocalTrackMuted } from '../../../base/tracks/functions.native';
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link ToggleCameraButton}.
|
||||
*/
|
||||
type Props = AbstractButtonProps & {
|
||||
interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* Whether the current conference is in audio only mode or not.
|
||||
*/
|
||||
_audioOnly: boolean,
|
||||
_audioOnly: boolean;
|
||||
|
||||
/**
|
||||
* Whether video is currently muted or not.
|
||||
*/
|
||||
_videoMuted: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
_videoMuted: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for toggling the camera facing mode.
|
||||
*/
|
||||
class ToggleCameraButton extends AbstractButton<Props, *> {
|
||||
class ToggleCameraButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.toggleCamera';
|
||||
icon = IconCameraRefresh;
|
||||
label = 'toolbar.toggleCamera';
|
||||
@@ -72,7 +66,7 @@ class ToggleCameraButton extends AbstractButton<Props, *> {
|
||||
* _videoMuted: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { enabled: audioOnly } = state['features/base/audio-only'];
|
||||
const tracks = state['features/base/tracks'];
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconAudioOnlyOff } from '../../../base/icons/svg';
|
||||
import { updateSettings } from '../../../base/settings/actions';
|
||||
@@ -10,23 +9,18 @@ import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/too
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link ToggleSelfViewButton}.
|
||||
*/
|
||||
type Props = AbstractButtonProps & {
|
||||
interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* Whether the self view is disabled or not.
|
||||
*/
|
||||
_disableSelfView: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function
|
||||
};
|
||||
_disableSelfView: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of a button for toggling the self view.
|
||||
*/
|
||||
class ToggleSelfViewButton extends AbstractButton<Props, *> {
|
||||
class ToggleSelfViewButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.selfView';
|
||||
icon = IconAudioOnlyOff;
|
||||
label = 'videothumbnail.hideSelfView';
|
||||
@@ -69,7 +63,7 @@ class ToggleSelfViewButton extends AbstractButton<Props, *> {
|
||||
* _disableSelfView: boolean
|
||||
* }}
|
||||
*/
|
||||
function _mapStateToProps(state): Object {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { disableSelfView } = state['features/base/settings'];
|
||||
|
||||
return {
|
||||
@@ -1,13 +1,11 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { View, ViewStyle } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import ColorSchemeRegistry from '../../../base/color-scheme/ColorSchemeRegistry';
|
||||
import Platform from '../../../base/react/Platform.native';
|
||||
import { StyleType } from '../../../base/styles/functions.native';
|
||||
import ChatButton from '../../../chat/components/native/ChatButton';
|
||||
import ReactionsMenuButton from '../../../reactions/components/native/ReactionsMenuButton';
|
||||
import { isReactionsEnabled } from '../../../reactions/functions.any';
|
||||
@@ -27,38 +25,38 @@ import styles from './styles';
|
||||
/**
|
||||
* The type of {@link Toolbox}'s React {@code Component} props.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* Whether the end conference feature is supported.
|
||||
*/
|
||||
_endConferenceSupported: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the reactions feature is enabled.
|
||||
*/
|
||||
_reactionsEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: StyleType,
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the toolbox is visible.
|
||||
*/
|
||||
_visible: boolean,
|
||||
_endConferenceSupported: boolean;
|
||||
|
||||
/**
|
||||
* Whether we are in visitors mode.
|
||||
*/
|
||||
_iAmVisitor: boolean,
|
||||
_iAmVisitor: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the reactions feature is enabled.
|
||||
*/
|
||||
_reactionsEnabled: boolean;
|
||||
|
||||
/**
|
||||
* The color-schemed stylesheet of the feature.
|
||||
*/
|
||||
_styles: any;
|
||||
|
||||
/**
|
||||
* The indicator which determines whether the toolbox is visible.
|
||||
*/
|
||||
_visible: boolean;
|
||||
|
||||
/**
|
||||
* The width of the screen.
|
||||
*/
|
||||
_width: number
|
||||
};
|
||||
_width: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the conference Toolbox on React Native.
|
||||
@@ -66,7 +64,7 @@ type Props = {
|
||||
* @param {Object} props - The props of the component.
|
||||
* @returns {React$Element}.
|
||||
*/
|
||||
function Toolbox(props: Props) {
|
||||
function Toolbox(props: IProps) {
|
||||
const { _endConferenceSupported, _reactionsEnabled, _styles, _visible, _iAmVisitor, _width } = props;
|
||||
|
||||
if (!_visible) {
|
||||
@@ -74,7 +72,7 @@ function Toolbox(props: Props) {
|
||||
}
|
||||
|
||||
const bottomEdge = Platform.OS === 'ios' && _visible;
|
||||
const { buttonStylesBorderless, hangupButtonStyles, hangupMenuButtonStyles, toggledButtonStyles } = _styles;
|
||||
const { buttonStylesBorderless, hangupButtonStyles, toggledButtonStyles } = _styles;
|
||||
const additionalButtons = getMovableButtons(_width);
|
||||
const backgroundToggledStyle = {
|
||||
...toggledButtonStyles,
|
||||
@@ -93,12 +91,14 @@ function Toolbox(props: Props) {
|
||||
|
||||
return (
|
||||
<View
|
||||
style = { styles.toolboxContainer }>
|
||||
style = { styles.toolboxContainer as ViewStyle }>
|
||||
<SafeAreaView
|
||||
accessibilityRole = 'toolbar'
|
||||
|
||||
// @ts-ignore
|
||||
edges = { [ bottomEdge && 'bottom' ].filter(Boolean) }
|
||||
pointerEvents = 'box-none'
|
||||
style = { style }>
|
||||
style = { style as ViewStyle }>
|
||||
{!_iAmVisitor && <AudioMuteButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
@@ -108,9 +108,9 @@ function Toolbox(props: Props) {
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
}
|
||||
{additionalButtons.has('chat')
|
||||
&& <ChatButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { backgroundToggledStyle } />
|
||||
&& <ChatButton
|
||||
styles = { buttonStylesBorderless }
|
||||
toggledStyles = { backgroundToggledStyle } />
|
||||
}
|
||||
{!_iAmVisitor && additionalButtons.has('screensharing')
|
||||
&& <ScreenSharingButton styles = { buttonStylesBorderless } />}
|
||||
@@ -127,9 +127,7 @@ function Toolbox(props: Props) {
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
}
|
||||
{ _endConferenceSupported
|
||||
? <HangupMenuButton
|
||||
styles = { hangupMenuButtonStyles }
|
||||
toggledStyles = { toggledButtonStyles } />
|
||||
? <HangupMenuButton />
|
||||
: <HangupButton
|
||||
styles = { hangupButtonStyles } />
|
||||
}
|
||||
@@ -145,9 +143,9 @@ function Toolbox(props: Props) {
|
||||
* @param {Object} state - The redux state of which parts are to be mapped to
|
||||
* {@code Toolbox} props.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state: Object): Object {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { conference } = state['features/base/conference'];
|
||||
const endConferenceSupported = conference?.isEndConferenceSupported();
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
// @flow
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import ExpandedLabel, { Props as AbstractProps } from '../../base/label/components/native/ExpandedLabel';
|
||||
import ExpandedLabel, { IProps as AbstractProps } from '../../base/label/components/native/ExpandedLabel';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
t: Function
|
||||
}
|
||||
type Props = AbstractProps & WithTranslation;
|
||||
|
||||
/**
|
||||
* A react {@code Component} that implements an expanded label as tooltip-like
|
||||
@@ -1,12 +1,10 @@
|
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import Label from '../../base/label/components/native/Label';
|
||||
|
||||
import { type Props, _mapStateToProps } from './AbstractTranscribingLabel';
|
||||
import { IProps, _mapStateToProps } from './AbstractTranscribingLabel';
|
||||
|
||||
/**
|
||||
* React {@code Component} for displaying a label when a transcriber is in the
|
||||
@@ -14,7 +12,7 @@ import { type Props, _mapStateToProps } from './AbstractTranscribingLabel';
|
||||
*
|
||||
* @augments Component
|
||||
*/
|
||||
class TranscribingLabel extends Component<Props> {
|
||||
class TranscribingLabel extends Component<IProps> {
|
||||
|
||||
/**
|
||||
* Renders the platform-specific label component.
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { approveParticipant } from '../../../av-moderation/actions';
|
||||
import { isSupported } from '../../../av-moderation/functions';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -11,34 +10,29 @@ import { getParticipantById, isLocalParticipantModerator } from '../../../base/p
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { isForceMuted } from '../../../participants-pane/functions';
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
export interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* Whether or not the participant is audio force muted.
|
||||
*/
|
||||
isAudioForceMuted: boolean,
|
||||
isAudioForceMuted: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not the participant is video force muted.
|
||||
*/
|
||||
isVideoForceMuted: boolean,
|
||||
isVideoForceMuted: boolean;
|
||||
|
||||
/**
|
||||
* The ID of the participant object that this button is supposed to
|
||||
* ask to unmute.
|
||||
*/
|
||||
participantID: string
|
||||
};
|
||||
participantID: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract remote video menu button which asks the remote participant to unmute.
|
||||
*/
|
||||
class AskUnmuteButton extends AbstractButton<Props, *> {
|
||||
class AskUnmuteButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'participantsPane.actions.askUnmute';
|
||||
icon = IconMic;
|
||||
label = 'participantsPane.actions.askUnmute';
|
||||
@@ -91,16 +85,16 @@ class AskUnmuteButton extends AbstractButton<Props, *> {
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - Properties of component.
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function mapStateToProps(state, ownProps) {
|
||||
function mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { participantID } = ownProps;
|
||||
const participant = getParticipantById(state, participantID);
|
||||
|
||||
return {
|
||||
isAudioForceMuted: isForceMuted(participant, MEDIA_TYPE.AUDIO, state),
|
||||
isVideoForceMuted: isForceMuted(participant, MEDIA_TYPE.VIDEO, state),
|
||||
visible: isLocalParticipantModerator(state) && isSupported()
|
||||
visible: isLocalParticipantModerator(state) && isSupported()(state)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,28 +7,18 @@ import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/too
|
||||
|
||||
import ConnectionStatusComponent from './ConnectionStatusComponent';
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
export interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* The ID of the participant that this button is supposed to pin.
|
||||
*/
|
||||
participantID: string,
|
||||
|
||||
/**
|
||||
* The function to be used to translate i18n labels.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
participantID: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A remote video menu button which shows the connection statistics.
|
||||
*/
|
||||
class ConnectionStatusButton extends AbstractButton<Props, *> {
|
||||
class ConnectionStatusButton extends AbstractButton<IProps> {
|
||||
icon = IconInfoCircle;
|
||||
label = 'videothumbnail.connectionInfo';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -28,8 +26,6 @@ class GrantModeratorDialog extends AbstractGrantModeratorDialog {
|
||||
onSubmit = { this._onSubmit } />
|
||||
);
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
}
|
||||
|
||||
export default translate(connect(abstractMapStateToProps)(GrantModeratorDialog));
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||
import AbstractKickButton from '../AbstractKickButton';
|
||||
@@ -12,7 +11,7 @@ import AbstractKickButton from '../AbstractKickButton';
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
visible: isLocalParticipantModerator(state)
|
||||
};
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -29,8 +27,6 @@ class KickRemoteParticipantDialog extends AbstractKickRemoteParticipantDialog {
|
||||
title = 'dialog.kickParticipantTitle' />
|
||||
);
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
}
|
||||
|
||||
export default translate(connect()(KickRemoteParticipantDialog));
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { Text, TextStyle, View, ViewStyle } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import Avatar from '../../../base/avatar/components/Avatar';
|
||||
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
|
||||
import { bottomSheetStyles } from '../../../base/dialog/components/native/styles';
|
||||
@@ -10,50 +11,50 @@ import {
|
||||
getLocalParticipant,
|
||||
getParticipantDisplayName
|
||||
} from '../../../base/participants/functions';
|
||||
import { ILocalParticipant } from '../../../base/participants/types';
|
||||
import ToggleSelfViewButton from '../../../toolbox/components/native/ToggleSelfViewButton';
|
||||
|
||||
import ConnectionStatusButton from './ConnectionStatusButton';
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* Size of the rendered avatar in the menu.
|
||||
*/
|
||||
const AVATAR_SIZE = 24;
|
||||
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The local participant.
|
||||
*/
|
||||
_participant: Object,
|
||||
_participant?: ILocalParticipant;
|
||||
|
||||
/**
|
||||
* Display name of the participant retrieved from Redux.
|
||||
*/
|
||||
_participantDisplayName: string,
|
||||
_participantDisplayName: string;
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
dispatch: IStore['dispatch'];
|
||||
|
||||
/**
|
||||
* Translation function.
|
||||
*/
|
||||
t: Function
|
||||
t: Function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to implement a popup menu that opens upon long pressing a thumbnail.
|
||||
*/
|
||||
class LocalVideoMenu extends PureComponent<Props> {
|
||||
class LocalVideoMenu extends PureComponent<IProps> {
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._renderMenuHeader = this._renderMenuHeader.bind(this);
|
||||
@@ -68,7 +69,7 @@ class LocalVideoMenu extends PureComponent<Props> {
|
||||
const { _participant } = this.props;
|
||||
const buttonProps = {
|
||||
showLabel: true,
|
||||
participantID: _participant.id,
|
||||
participantID: _participant?.id ?? '',
|
||||
styles: bottomSheetStyles.buttons
|
||||
};
|
||||
|
||||
@@ -94,11 +95,11 @@ class LocalVideoMenu extends PureComponent<Props> {
|
||||
<View
|
||||
style = { [
|
||||
bottomSheetStyles.sheet,
|
||||
styles.participantNameContainer ] }>
|
||||
styles.participantNameContainer ] as ViewStyle[] }>
|
||||
<Avatar
|
||||
participantId = { _participant.id }
|
||||
participantId = { _participant?.id }
|
||||
size = { AVATAR_SIZE } />
|
||||
<Text style = { styles.participantNameLabel }>
|
||||
<Text style = { styles.participantNameLabel as TextStyle }>
|
||||
{ this.props._participantDisplayName }
|
||||
</Text>
|
||||
</View>
|
||||
@@ -111,14 +112,14 @@ class LocalVideoMenu extends PureComponent<Props> {
|
||||
*
|
||||
* @param {Object} state - Redux state.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const participant = getLocalParticipant(state);
|
||||
|
||||
return {
|
||||
_participant: participant,
|
||||
_participantDisplayName: getParticipantDisplayName(state, participant.id)
|
||||
_participantDisplayName: getParticipantDisplayName(state, participant?.id ?? '')
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||
import AbstractMuteButton, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractMuteButton';
|
||||
@@ -13,7 +12,7 @@ import AbstractMuteButton, { _mapStateToProps as _abstractMapStateToProps } from
|
||||
* @param {Object} ownProps - Properties of component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
return {
|
||||
..._abstractMapStateToProps(state, ownProps),
|
||||
visible: isLocalParticipantModerator(state)
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { ViewStyle } from 'react-native';
|
||||
import Dialog from 'react-native-dialog';
|
||||
import { Divider } from 'react-native-paper';
|
||||
import { connect } from 'react-redux';
|
||||
@@ -46,7 +47,8 @@ class MuteEveryoneDialog extends AbstractMuteEveryoneDialog<IProps> {
|
||||
descriptionKey = { this.state.content }
|
||||
onSubmit = { this._onSubmit }
|
||||
title = { this.props.title } >
|
||||
<Divider style = { styles.dividerDialog } />
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.dividerDialog as ViewStyle } />
|
||||
{ this._renderSwitch() }
|
||||
</ConfirmDialog>
|
||||
);
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||
import AbstractMuteEveryoneElseButton from '../AbstractMuteEveryoneElseButton';
|
||||
@@ -12,7 +11,7 @@ import AbstractMuteEveryoneElseButton from '../AbstractMuteEveryoneElseButton';
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
visible: isLocalParticipantModerator(state)
|
||||
};
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -29,8 +27,6 @@ class MuteRemoteParticipantsVideoDialog extends AbstractMuteRemoteParticipantsVi
|
||||
onSubmit = { this._onSubmit } />
|
||||
);
|
||||
}
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
}
|
||||
|
||||
export default translate(connect(abstractMapStateToProps)(MuteRemoteParticipantsVideoDialog));
|
||||
@@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||
import AbstractMuteVideoButton, { _mapStateToProps as _abstractMapStateToProps } from '../AbstractMuteVideoButton';
|
||||
@@ -13,7 +12,7 @@ import AbstractMuteVideoButton, { _mapStateToProps as _abstractMapStateToProps }
|
||||
* @param {Object} ownProps - Properties of component.
|
||||
* @returns {Props}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
return {
|
||||
..._abstractMapStateToProps(state, ownProps),
|
||||
visible: isLocalParticipantModerator(state)
|
||||
@@ -1,40 +1,29 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconEnlarge } from '../../../base/icons/svg';
|
||||
import { pinParticipant } from '../../../base/participants/actions';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { shouldDisplayTileView } from '../../../video-layout/functions';
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
export interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* True if tile view is currently enabled.
|
||||
*/
|
||||
_tileViewEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
_tileViewEnabled?: boolean;
|
||||
|
||||
/**
|
||||
* The ID of the participant that this button is supposed to pin.
|
||||
*/
|
||||
participantID: string,
|
||||
|
||||
/**
|
||||
* The function to be used to translate i18n labels.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
participantID: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A remote video menu button which pins a participant and exist the tile view.
|
||||
*/
|
||||
class PinButton extends AbstractButton<Props, *> {
|
||||
class PinButton extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'toolbar.accessibilityLabel.show';
|
||||
icon = IconEnlarge;
|
||||
label = 'videothumbnail.show';
|
||||
@@ -57,9 +46,9 @@ class PinButton extends AbstractButton<Props, *> {
|
||||
* Maps part of the Redux state to the props of this component.
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state) {
|
||||
function _mapStateToProps(state: IReduxState) {
|
||||
const { isOpen } = state['features/participants-pane'];
|
||||
|
||||
return {
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { Text, TextStyle, View, ViewStyle } from 'react-native';
|
||||
import { Divider } from 'react-native-paper';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import Avatar from '../../../base/avatar/components/Avatar';
|
||||
import { hideSheet } from '../../../base/dialog/actions';
|
||||
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
|
||||
@@ -16,10 +17,11 @@ import {
|
||||
isLocalParticipantModerator
|
||||
} from '../../../base/participants/functions';
|
||||
import { getBreakoutRooms, getCurrentRoomId } from '../../../breakout-rooms/functions';
|
||||
import { IRoom } from '../../../breakout-rooms/types';
|
||||
import PrivateMessageButton from '../../../chat/components/native/PrivateMessageButton';
|
||||
import ConnectionStatusButton from '../native/ConnectionStatusButton';
|
||||
|
||||
import AskUnmuteButton from './AskUnmuteButton';
|
||||
import ConnectionStatusButton from './ConnectionStatusButton';
|
||||
import GrantModeratorButton from './GrantModeratorButton';
|
||||
import KickButton from './KickButton';
|
||||
import MuteButton from './MuteButton';
|
||||
@@ -31,85 +33,84 @@ import styles from './styles';
|
||||
|
||||
// import VolumeSlider from './VolumeSlider';
|
||||
|
||||
|
||||
/**
|
||||
* Size of the rendered avatar in the menu.
|
||||
*/
|
||||
const AVATAR_SIZE = 24;
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* The ID of the participant for which this menu opened for.
|
||||
*/
|
||||
participantId: String,
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* The id of the current room.
|
||||
*/
|
||||
_currentRoomId: String,
|
||||
|
||||
/**
|
||||
* Whether or not to display the kick button.
|
||||
*/
|
||||
_disableKick: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not to display the send private message button.
|
||||
*/
|
||||
_disablePrivateChat: Boolean,
|
||||
|
||||
/**
|
||||
* Whether or not to display the remote mute buttons.
|
||||
*/
|
||||
_disableRemoteMute: boolean,
|
||||
_currentRoomId: string;
|
||||
|
||||
/**
|
||||
* Whether or not to display the grant moderator button.
|
||||
*/
|
||||
_disableGrantModerator: Boolean,
|
||||
_disableGrantModerator: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not to display the kick button.
|
||||
*/
|
||||
_disableKick: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not to display the send private message button.
|
||||
*/
|
||||
_disablePrivateChat: boolean;
|
||||
|
||||
/**
|
||||
* Whether or not to display the remote mute buttons.
|
||||
*/
|
||||
_disableRemoteMute: boolean;
|
||||
|
||||
/**
|
||||
* Whether the participant is present in the room or not.
|
||||
*/
|
||||
_isParticipantAvailable?: boolean,
|
||||
_isParticipantAvailable?: boolean;
|
||||
|
||||
/**
|
||||
* Whether the local participant is moderator or not.
|
||||
*/
|
||||
_moderator: boolean,
|
||||
_moderator: boolean;
|
||||
|
||||
/**
|
||||
* Display name of the participant retrieved from Redux.
|
||||
*/
|
||||
_participantDisplayName: string,
|
||||
_participantDisplayName: string;
|
||||
|
||||
/**
|
||||
* Array containing the breakout rooms.
|
||||
*/
|
||||
_rooms: Array<Object>,
|
||||
_rooms: Array<IRoom>;
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Function;
|
||||
|
||||
/**
|
||||
* The ID of the participant for which this menu opened for.
|
||||
*/
|
||||
participantId: string;
|
||||
|
||||
/**
|
||||
* Translation function.
|
||||
*/
|
||||
t: Function
|
||||
t: Function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to implement a popup menu that opens upon long pressing a thumbnail.
|
||||
*/
|
||||
class RemoteVideoMenu extends PureComponent<Props> {
|
||||
class RemoteVideoMenu extends PureComponent<IProps> {
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
@@ -149,7 +150,8 @@ class RemoteVideoMenu extends PureComponent<Props> {
|
||||
{ !_disableRemoteMute && <MuteButton { ...buttonProps } /> }
|
||||
<MuteEveryoneElseButton { ...buttonProps } />
|
||||
{ !_disableRemoteMute && <MuteVideoButton { ...buttonProps } /> }
|
||||
<Divider style = { styles.divider } />
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.divider as ViewStyle } />
|
||||
{ !_disableKick && <KickButton { ...buttonProps } /> }
|
||||
{ !_disableGrantModerator && <GrantModeratorButton { ...buttonProps } /> }
|
||||
<PinButton { ...buttonProps } />
|
||||
@@ -158,9 +160,10 @@ class RemoteVideoMenu extends PureComponent<Props> {
|
||||
{ ...buttonProps }
|
||||
afterClick = { undefined } />
|
||||
{_moderator && _rooms.length > 1 && <>
|
||||
<Divider style = { styles.divider } />
|
||||
<View style = { styles.contextMenuItem }>
|
||||
<Text style = { styles.contextMenuItemText }>
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.divider as ViewStyle } />
|
||||
<View style = { styles.contextMenuItem as ViewStyle }>
|
||||
<Text style = { styles.contextMenuItemText as TextStyle }>
|
||||
{t('breakoutRooms.actions.sendToBreakoutRoom')}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -196,11 +199,11 @@ class RemoteVideoMenu extends PureComponent<Props> {
|
||||
<View
|
||||
style = { [
|
||||
bottomSheetStyles.sheet,
|
||||
styles.participantNameContainer ] }>
|
||||
styles.participantNameContainer ] as ViewStyle[] }>
|
||||
<Avatar
|
||||
participantId = { participantId }
|
||||
size = { AVATAR_SIZE } />
|
||||
<Text style = { styles.participantNameLabel }>
|
||||
<Text style = { styles.participantNameLabel as TextStyle }>
|
||||
{ this.props._participantDisplayName }
|
||||
</Text>
|
||||
</View>
|
||||
@@ -214,9 +217,9 @@ class RemoteVideoMenu extends PureComponent<Props> {
|
||||
* @param {Object} state - Redux state.
|
||||
* @param {Object} ownProps - Properties of component.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const kickOutEnabled = getFeatureFlag(state, KICK_OUT_ENABLED, true);
|
||||
const { participantId } = ownProps;
|
||||
const { remoteVideoMenu = {}, disableRemoteMute } = state['features/base/config'];
|
||||
@@ -1,42 +1,32 @@
|
||||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { createBreakoutRoomsEvent } from '../../../analytics/AnalyticsEvents';
|
||||
import { sendAnalytics } from '../../../analytics/functions';
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import { translate } from '../../../base/i18n/functions';
|
||||
import { IconRingGroup } from '../../../base/icons/svg';
|
||||
import { isLocalParticipantModerator } from '../../../base/participants/functions';
|
||||
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
|
||||
import { sendParticipantToRoom } from '../../../breakout-rooms/actions';
|
||||
import { IRoom } from '../../../breakout-rooms/types';
|
||||
|
||||
export type Props = AbstractButtonProps & {
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
export interface IProps extends AbstractButtonProps {
|
||||
|
||||
/**
|
||||
* ID of the participant to send to breakout room.
|
||||
*/
|
||||
participantID: string,
|
||||
participantID: string;
|
||||
|
||||
/**
|
||||
* Room to send participant to.
|
||||
*/
|
||||
room: Object,
|
||||
|
||||
/**
|
||||
* Translation function.
|
||||
*/
|
||||
t: Function
|
||||
};
|
||||
room: IRoom;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract remote video menu button which sends the remote participant to a breakout room.
|
||||
*/
|
||||
class SendToBreakoutRoom extends AbstractButton<Props, *> {
|
||||
class SendToBreakoutRoom extends AbstractButton<IProps> {
|
||||
accessibilityLabel = 'breakoutRooms.actions.sendToBreakoutRoom';
|
||||
icon = IconRingGroup;
|
||||
|
||||
@@ -70,9 +60,9 @@ class SendToBreakoutRoom extends AbstractButton<Props, *> {
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - Properties of component.
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
function mapStateToProps(state: IReduxState) {
|
||||
return {
|
||||
visible: isLocalParticipantModerator(state)
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
// @flow
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { Text, TextStyle, View, ViewStyle } from 'react-native';
|
||||
import { Divider } from 'react-native-paper';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState, IStore } from '../../../app/types';
|
||||
import Avatar from '../../../base/avatar/components/Avatar';
|
||||
import { hideSheet } from '../../../base/dialog/actions';
|
||||
import BottomSheet from '../../../base/dialog/components/native/BottomSheet';
|
||||
@@ -17,50 +16,49 @@ import SharedVideoButton from '../../../shared-video/components/native/SharedVid
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* Size of the rendered avatar in the menu.
|
||||
*/
|
||||
const AVATAR_SIZE = 24;
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
|
||||
/**
|
||||
* The ID of the participant for which this menu opened for.
|
||||
*/
|
||||
participantId: string,
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* True if the menu is currently open, false otherwise.
|
||||
*/
|
||||
_isOpen: boolean,
|
||||
_isOpen: boolean;
|
||||
|
||||
/**
|
||||
* Whether the participant is present in the room or not.
|
||||
*/
|
||||
_isParticipantAvailable?: boolean,
|
||||
_isParticipantAvailable?: boolean;
|
||||
|
||||
/**
|
||||
* Display name of the participant retrieved from Redux.
|
||||
*/
|
||||
_participantDisplayName: string,
|
||||
_participantDisplayName: string;
|
||||
|
||||
/**
|
||||
* The Redux dispatch function.
|
||||
*/
|
||||
dispatch: IStore['dispatch'];
|
||||
|
||||
/**
|
||||
* The ID of the participant for which this menu opened for.
|
||||
*/
|
||||
participantId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to implement a popup menu that opens upon long pressing a fake participant thumbnail.
|
||||
*/
|
||||
class SharedVideoMenu extends PureComponent<Props> {
|
||||
class SharedVideoMenu extends PureComponent<IProps> {
|
||||
/**
|
||||
* Constructor of the component.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this._onCancel = this._onCancel.bind(this);
|
||||
@@ -89,7 +87,8 @@ class SharedVideoMenu extends PureComponent<Props> {
|
||||
<BottomSheet
|
||||
renderHeader = { this._renderMenuHeader }
|
||||
showSlidingView = { _isParticipantAvailable }>
|
||||
<Divider style = { styles.divider } />
|
||||
{/* @ts-ignore */}
|
||||
<Divider style = { styles.divider as ViewStyle } />
|
||||
<SharedVideoButton { ...buttonProps } />
|
||||
</BottomSheet>
|
||||
);
|
||||
@@ -117,11 +116,11 @@ class SharedVideoMenu extends PureComponent<Props> {
|
||||
<View
|
||||
style = { [
|
||||
bottomSheetStyles.sheet,
|
||||
styles.participantNameContainer ] }>
|
||||
styles.participantNameContainer ] as ViewStyle[] }>
|
||||
<Avatar
|
||||
participantId = { participantId }
|
||||
size = { AVATAR_SIZE } />
|
||||
<Text style = { styles.participantNameLabel }>
|
||||
<Text style = { styles.participantNameLabel as TextStyle }>
|
||||
{ this.props._participantDisplayName }
|
||||
</Text>
|
||||
</View>
|
||||
@@ -135,9 +134,9 @@ class SharedVideoMenu extends PureComponent<Props> {
|
||||
* @param {Object} state - Redux state.
|
||||
* @param {Object} ownProps - Properties of component.
|
||||
* @private
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function _mapStateToProps(state, ownProps) {
|
||||
function _mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { participantId } = ownProps;
|
||||
const isParticipantAvailable = getParticipantById(state, participantId);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// @flow
|
||||
|
||||
import Slider from '@react-native-community/slider';
|
||||
import _ from 'lodash';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { View, ViewStyle } from 'react-native';
|
||||
import { withTheme } from 'react-native-paper';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { IReduxState } from '../../../app/types';
|
||||
import Icon from '../../../base/icons/components/Icon';
|
||||
import { IconVolumeUp } from '../../../base/icons/svg';
|
||||
import { setVolume } from '../../../participants-pane/actions.native';
|
||||
@@ -14,57 +13,55 @@ import { VOLUME_SLIDER_SCALE } from '../../constants';
|
||||
|
||||
import styles from './styles';
|
||||
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} props of {@link VolumeSlider}.
|
||||
*/
|
||||
type Props = {
|
||||
interface IProps {
|
||||
|
||||
/**
|
||||
* Whether the participant enters the conference silent.
|
||||
*/
|
||||
_startSilent: boolean,
|
||||
_startSilent: boolean;
|
||||
|
||||
/**
|
||||
* The volume level for the participant.
|
||||
*/
|
||||
_volume: number,
|
||||
_volume: number;
|
||||
|
||||
/**
|
||||
* The redux dispatch function.
|
||||
*/
|
||||
dispatch: Function,
|
||||
dispatch: Function;
|
||||
|
||||
/**
|
||||
* The ID of the participant.
|
||||
*/
|
||||
participantID: string,
|
||||
participantID: string;
|
||||
|
||||
/**
|
||||
* Theme used for styles.
|
||||
*/
|
||||
theme: Object
|
||||
};
|
||||
theme: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of the React {@code Component} state of {@link VolumeSlider}.
|
||||
*/
|
||||
type State = {
|
||||
interface IState {
|
||||
|
||||
/**
|
||||
* The volume of the participant's audio element. The value will
|
||||
* be represented by a slider.
|
||||
*/
|
||||
volumeLevel: number
|
||||
};
|
||||
volumeLevel: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component that renders the volume slider.
|
||||
*
|
||||
* @returns {React$Element<any>}
|
||||
*/
|
||||
class VolumeSlider extends PureComponent<Props, State> {
|
||||
_onVolumeChange: Function;
|
||||
class VolumeSlider extends PureComponent<IProps, IState> {
|
||||
_originalVolumeChange: Function;
|
||||
|
||||
/**
|
||||
@@ -73,7 +70,7 @@ class VolumeSlider extends PureComponent<Props, State> {
|
||||
* @param {Object} props - The read-only properties with which the new
|
||||
* instance is to be initialized.
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
@@ -100,7 +97,7 @@ class VolumeSlider extends PureComponent<Props, State> {
|
||||
const onVolumeChange = _startSilent ? undefined : this._onVolumeChange;
|
||||
|
||||
return (
|
||||
<View style = { styles.volumeSliderContainer } >
|
||||
<View style = { styles.volumeSliderContainer as ViewStyle } >
|
||||
<Icon
|
||||
size = { 24 }
|
||||
src = { IconVolumeUp } />
|
||||
@@ -110,7 +107,7 @@ class VolumeSlider extends PureComponent<Props, State> {
|
||||
minimumTrackTintColor = { palette.action01 }
|
||||
minimumValue = { 0 }
|
||||
onValueChange = { onVolumeChange }
|
||||
style = { styles.sliderContainer }
|
||||
style = { styles.sliderContainer as ViewStyle }
|
||||
thumbTintColor = { palette.ui10 }
|
||||
value = { volumeLevel } />
|
||||
</View>
|
||||
@@ -126,7 +123,7 @@ class VolumeSlider extends PureComponent<Props, State> {
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_onVolumeChange(volumeLevel) {
|
||||
_onVolumeChange(volumeLevel: number) {
|
||||
const { dispatch, participantID } = this.props;
|
||||
|
||||
dispatch(setVolume(participantID, volumeLevel));
|
||||
@@ -139,9 +136,9 @@ class VolumeSlider extends PureComponent<Props, State> {
|
||||
*
|
||||
* @param {Object} state - The Redux state.
|
||||
* @param {Object} ownProps - The own props of the component.
|
||||
* @returns {Props}
|
||||
* @returns {IProps}
|
||||
*/
|
||||
function mapStateToProps(state, ownProps): Object {
|
||||
function mapStateToProps(state: IReduxState, ownProps: any) {
|
||||
const { participantID } = ownProps;
|
||||
const { participantsVolume } = state['features/participants-pane'];
|
||||
const { startSilent } = state['features/base/config'];
|
||||
@@ -1,13 +1,11 @@
|
||||
// @flow
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
|
||||
import { translate } from '../../base/i18n/functions';
|
||||
import ExpandedLabel, { Props as AbstractProps } from '../../base/label/components/native/ExpandedLabel';
|
||||
import ExpandedLabel, { IProps as AbstractProps } from '../../base/label/components/native/ExpandedLabel';
|
||||
|
||||
import { AUD_LABEL_COLOR } from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
t: Function
|
||||
}
|
||||
type Props = AbstractProps & WithTranslation;
|
||||
|
||||
/**
|
||||
* A react {@code Component} that implements an expanded label as tooltip-like
|
||||
@@ -1,5 +1,3 @@
|
||||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
@@ -13,13 +11,13 @@ import AbstractVideoQualityLabel, {
|
||||
} from './AbstractVideoQualityLabel';
|
||||
import styles from './styles';
|
||||
|
||||
type Props = AbstractProps & {
|
||||
interface IProps extends AbstractProps {
|
||||
|
||||
/**
|
||||
* Style of the component passed as props.
|
||||
*/
|
||||
style: ?StyleType
|
||||
};
|
||||
style?: StyleType;
|
||||
}
|
||||
|
||||
/**
|
||||
* React {@code Component} responsible for displaying a label that indicates
|
||||
@@ -30,7 +28,7 @@ type Props = AbstractProps & {
|
||||
* is kept consistent with web and in the future we may introduce the required
|
||||
* api and extend this component with actual quality indication.
|
||||
*/
|
||||
class VideoQualityLabel extends AbstractVideoQualityLabel<Props> {
|
||||
class VideoQualityLabel extends AbstractVideoQualityLabel<IProps> {
|
||||
|
||||
/**
|
||||
* Implements React {@link Component}'s render.
|
||||
@@ -46,7 +44,7 @@ class VideoQualityLabel extends AbstractVideoQualityLabel<Props> {
|
||||
}
|
||||
|
||||
return (
|
||||
<Label
|
||||
<Label // @ts-ignore
|
||||
style = { combineStyles(styles.indicatorAudioOnly, style) }
|
||||
text = { t('videoStatus.audioOnly') } />
|
||||
);
|
||||
@@ -55,6 +55,7 @@ external_services = {
|
||||
};
|
||||
|
||||
muc_mapper_domain_base = 'vX.meet.jitsi';
|
||||
main_domain = 'jitmeet.example.com';
|
||||
|
||||
-- https://prosody.im/doc/modules/mod_smacks
|
||||
smacks_max_unacked_stanzas = 5;
|
||||
|
||||
@@ -20,18 +20,28 @@ local get_room_from_jid = util.get_room_from_jid;
|
||||
local get_focus_occupant = util.get_focus_occupant;
|
||||
local internal_room_jid_match_rewrite = util.internal_room_jid_match_rewrite;
|
||||
|
||||
-- this is the main virtual host of this vnode
|
||||
local local_domain = module:get_option_string('muc_mapper_domain_base');
|
||||
if not local_domain then
|
||||
module:log('warn', "No 'muc_mapper_domain_base' option set, disabling fmuc plugin");
|
||||
return;
|
||||
end
|
||||
|
||||
-- this is the main virtual host of the main prosody that this vnode serves
|
||||
local main_domain = module:get_option_string('main_domain');
|
||||
if not main_domain then
|
||||
module:log('warn', "No 'main_domain' option set, disabling fmuc plugin");
|
||||
return;
|
||||
end
|
||||
|
||||
local muc_domain_prefix = module:get_option_string('muc_mapper_domain_prefix', 'conference');
|
||||
local main_domain = string.gsub(module.host, muc_domain_prefix..'.', '');
|
||||
|
||||
local NICK_NS = 'http://jabber.org/protocol/nick';
|
||||
|
||||
-- we send stats for the total number of rooms, total number of participants and total number of visitors
|
||||
local measure_rooms = module:measure("vnode-rooms", "amount");
|
||||
local measure_participants = module:measure("vnode-participants", "amount");
|
||||
local measure_visitors = module:measure("vnode-visitors", "amount");
|
||||
|
||||
-- This is the domain of the main prosody that is federating with us;
|
||||
local fmuc_main_domain;
|
||||
local measure_rooms = module:measure('vnode-rooms', 'amount');
|
||||
local measure_participants = module:measure('vnode-participants', 'amount');
|
||||
local measure_visitors = module:measure('vnode-visitors', 'amount');
|
||||
|
||||
local sent_iq_cache = require 'util.cache'.new(200);
|
||||
|
||||
@@ -45,12 +55,8 @@ module:hook('muc-occupant-pre-join', function (event)
|
||||
local occupant, session = event.occupant, event.origin;
|
||||
local node, host = jid.split(occupant.bare_jid);
|
||||
|
||||
if host == main_domain then
|
||||
if host == local_domain then
|
||||
occupant.role = 'visitor';
|
||||
elseif not fmuc_main_domain then
|
||||
if node ~= 'focus' then
|
||||
fmuc_main_domain = host;
|
||||
end
|
||||
end
|
||||
end, 3);
|
||||
|
||||
@@ -103,7 +109,7 @@ module:hook('muc-occupant-left', function (event)
|
||||
local room, occupant = event.room, event.occupant;
|
||||
local occupant_domain = jid.host(occupant.bare_jid);
|
||||
|
||||
if occupant_domain == main_domain then
|
||||
if occupant_domain == local_domain then
|
||||
local focus_occupant = get_focus_occupant(room);
|
||||
if not focus_occupant then
|
||||
module:log('warn', 'No focus found for %s', room.jid);
|
||||
@@ -181,11 +187,11 @@ module:hook('muc-broadcast-presence', function (event)
|
||||
sent_iq_cache:set(iq_id, socket.gettime());
|
||||
local promotion_request = st.iq({
|
||||
type = 'set',
|
||||
to = 'visitors.'..fmuc_main_domain,
|
||||
from = main_domain,
|
||||
to = 'visitors.'..main_domain,
|
||||
from = local_domain,
|
||||
id = iq_id })
|
||||
:tag('visitors', { xmlns = 'jitsi:visitors',
|
||||
room = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..fmuc_main_domain) })
|
||||
room = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..main_domain) })
|
||||
:tag('promotion-request', { xmlns = 'jitsi:visitors', jid = occupant.jid }):up();
|
||||
|
||||
local nick_element = occupant:get_presence():get_child('nick', NICK_NS);
|
||||
@@ -221,8 +227,8 @@ local function stanza_handler(event)
|
||||
return;
|
||||
end
|
||||
|
||||
if stanza.attr.from ~= 'visitors.'..fmuc_main_domain then
|
||||
module:log('warn', 'not from visitors component, ignore! %s %s', stanza.attr.from, stanza);
|
||||
if stanza.attr.from ~= 'visitors.'..main_domain then
|
||||
module:log('warn', 'not from visitors component, ignore! %s', stanza);
|
||||
return true;
|
||||
end
|
||||
|
||||
@@ -241,7 +247,7 @@ local function stanza_handler(event)
|
||||
|
||||
-- respond with successful receiving the iq
|
||||
origin.send(st.iq({
|
||||
type = "result";
|
||||
type = 'result';
|
||||
from = stanza.attr.to;
|
||||
to = stanza.attr.from;
|
||||
id = stanza.attr.id
|
||||
@@ -276,12 +282,12 @@ function process_host_module(name, callback)
|
||||
process_host(name);
|
||||
end
|
||||
end
|
||||
process_host_module(main_domain, function(host_module, host)
|
||||
process_host_module(local_domain, function(host_module, host)
|
||||
host_module:hook('iq/host', stanza_handler, 10);
|
||||
end);
|
||||
|
||||
-- only live chat is supported for visitors
|
||||
module:hook("muc-occupant-groupchat", function(event)
|
||||
module:hook('muc-occupant-groupchat', function(event)
|
||||
local occupant, room, stanza = event.occupant, event.room, event.stanza;
|
||||
local from = stanza.attr.from;
|
||||
local occupant_host = jid.host(occupant.bare_jid);
|
||||
@@ -289,7 +295,7 @@ module:hook("muc-occupant-groupchat", function(event)
|
||||
-- if there is no occupant this is a message from main, probably coming from other vnode
|
||||
if occupant then
|
||||
-- we manage nick only for visitors
|
||||
if occupant_host ~= fmuc_main_domain then
|
||||
if occupant_host ~= main_domain then
|
||||
-- add to message stanza display name for the visitor
|
||||
-- remove existing nick to avoid forgery
|
||||
stanza:remove_children('nick', NICK_NS);
|
||||
@@ -310,15 +316,15 @@ module:hook("muc-occupant-groupchat", function(event)
|
||||
-- let's send it to main chat and rest of visitors here
|
||||
for _, o in room:each_occupant() do
|
||||
-- filter remote occupants
|
||||
if jid.host(o.bare_jid) == main_domain then
|
||||
if jid.host(o.bare_jid) == local_domain then
|
||||
room:route_to_occupant(o, stanza)
|
||||
end
|
||||
end
|
||||
|
||||
-- send to main participants only messages from local occupants (skip from remote vnodes)
|
||||
if occupant and occupant_host ~= fmuc_main_domain then
|
||||
if occupant and occupant_host ~= main_domain then
|
||||
local main_message = st.clone(stanza);
|
||||
main_message.attr.to = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..fmuc_main_domain);
|
||||
main_message.attr.to = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..main_domain);
|
||||
module:send(main_message);
|
||||
end
|
||||
stanza.attr.from = from; -- something prosody does internally
|
||||
@@ -328,20 +334,20 @@ end, 55); -- prosody check for visitor's chat is prio 50, we want to override it
|
||||
|
||||
module:hook('muc-private-message', function(event)
|
||||
-- private messaging is forbidden
|
||||
event.origin.send(st.error_reply(event.stanza, "auth", "forbidden",
|
||||
"Private messaging is disabled on visitor nodes"));
|
||||
event.origin.send(st.error_reply(event.stanza, 'auth', 'forbidden',
|
||||
'Private messaging is disabled on visitor nodes'));
|
||||
return true;
|
||||
end, 10);
|
||||
|
||||
-- we calculate the stats on the configured interval (60 seconds by default)
|
||||
module:hook_global("stats-update", function ()
|
||||
module:hook_global('stats-update', function ()
|
||||
local participants_count, rooms_count, visitors_count = 0, 0, 0;
|
||||
|
||||
-- iterate over all rooms
|
||||
for room in prosody.hosts[module.host].modules.muc.each_room() do
|
||||
rooms_count = rooms_count + 1;
|
||||
for _, o in room:each_occupant() do
|
||||
if jid.host(o.bare_jid) == main_domain then
|
||||
if jid.host(o.bare_jid) == local_domain then
|
||||
visitors_count = visitors_count + 1;
|
||||
else
|
||||
participants_count = participants_count + 1;
|
||||
@@ -356,4 +362,80 @@ module:hook_global("stats-update", function ()
|
||||
measure_participants(participants_count);
|
||||
end);
|
||||
|
||||
-- we skip it till the main participants are added from the main prosody
|
||||
module:hook('jicofo-unlock-room', function(e)
|
||||
-- we do not block events we fired
|
||||
if e.fmuc_fired then
|
||||
return;
|
||||
end
|
||||
|
||||
return true;
|
||||
end);
|
||||
|
||||
-- handles incoming iq connect stanzas
|
||||
local function iq_from_main_handler(event)
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
|
||||
if stanza.name ~= 'iq' then
|
||||
return;
|
||||
end
|
||||
|
||||
if stanza.attr.type == 'result' and sent_iq_cache:get(stanza.attr.id) then
|
||||
sent_iq_cache:set(stanza.attr.id, nil);
|
||||
return true;
|
||||
end
|
||||
|
||||
if stanza.attr.type ~= 'set' then
|
||||
return;
|
||||
end
|
||||
|
||||
local visitors_iq = event.stanza:get_child('visitors', 'jitsi:visitors');
|
||||
if not visitors_iq then
|
||||
return;
|
||||
end
|
||||
|
||||
if stanza.attr.from ~= main_domain then
|
||||
module:log('warn', 'not from main prosody, ignore! %s', stanza);
|
||||
return true;
|
||||
end
|
||||
|
||||
local room_jid = visitors_iq.attr.room;
|
||||
local room = get_room_from_jid(room_jid_match_rewrite(room_jid));
|
||||
|
||||
if not room then
|
||||
module:log('warn', 'No room found %s', room_jid);
|
||||
return;
|
||||
end
|
||||
|
||||
local node = visitors_iq:get_child('connect');
|
||||
local fire_jicofo_unlock = true;
|
||||
|
||||
if not node then
|
||||
node = visitors_iq:get_child('update');
|
||||
fire_jicofo_unlock = false;
|
||||
end
|
||||
|
||||
if not node then
|
||||
return;
|
||||
end
|
||||
|
||||
-- respond with successful receiving the iq
|
||||
origin.send(st.iq({
|
||||
type = 'result';
|
||||
from = stanza.attr.to;
|
||||
to = stanza.attr.from;
|
||||
id = stanza.attr.id
|
||||
}));
|
||||
|
||||
-- if there is password supplied use it
|
||||
-- if this is update it will either set or remove the password
|
||||
room:set_password(node.attr.password);
|
||||
|
||||
if fire_jicofo_unlock then
|
||||
-- everything is connected allow participants to join
|
||||
module:fire_event('jicofo-unlock-room', { room = room; fmuc_fired = true; });
|
||||
end
|
||||
|
||||
return true;
|
||||
end
|
||||
module:hook('iq/host', iq_from_main_handler, 10);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
--- NOTE: Make sure all communication between prosodies is using the real jids ([foo]room1@muc.example.com)
|
||||
local st = require 'util.stanza';
|
||||
local jid = require 'util.jid';
|
||||
local new_id = require 'util.id'.medium;
|
||||
local util = module:require 'util';
|
||||
local presence_check_status = util.presence_check_status;
|
||||
|
||||
@@ -36,6 +37,8 @@ local ignore_list = module:get_option_set('visitors_ignore_list', {});
|
||||
-- Advertise the component for discovery via disco#items
|
||||
module:add_identity('component', 'visitors', 'visitors.'..module.host);
|
||||
|
||||
local sent_iq_cache = require 'util.cache'.new(200);
|
||||
|
||||
-- visitors_nodes = {
|
||||
-- roomjid1 = {
|
||||
-- nodes = {
|
||||
@@ -47,6 +50,24 @@ module:add_identity('component', 'visitors', 'visitors.'..module.host);
|
||||
--}
|
||||
local visitors_nodes = {};
|
||||
|
||||
-- sends connect or update iq
|
||||
-- @parameter type - Type of iq to send 'connect' or 'update'
|
||||
local function send_visitors_iq(conference_service, room, type)
|
||||
-- send iq informing the vnode that the connect is done and it will allow visitors to join
|
||||
local iq_id = new_id();
|
||||
sent_iq_cache:set(iq_id, socket.gettime());
|
||||
local connect_done = st.iq({
|
||||
type = 'set',
|
||||
to = conference_service,
|
||||
from = module.host,
|
||||
id = iq_id })
|
||||
:tag('visitors', { xmlns = 'jitsi:visitors',
|
||||
room = jid.join(jid.node(room.jid), conference_service) })
|
||||
:tag(type, { xmlns = 'jitsi:visitors', password = room:get_password() or '' }):up();
|
||||
|
||||
module:send(connect_done);
|
||||
end
|
||||
|
||||
-- an event received from visitors component, which receives iqs from jicofo
|
||||
local function connect_vnode(event)
|
||||
local room, vnode = event.room, event.vnode;
|
||||
@@ -75,7 +96,15 @@ local function connect_vnode(event)
|
||||
fmuc_pr.attr.to = jid.join(user, conference_service , res);
|
||||
fmuc_pr.attr.from = o.jid;
|
||||
-- add <x>
|
||||
fmuc_pr:tag('x', { xmlns = MUC_NS }):up();
|
||||
fmuc_pr:tag('x', { xmlns = MUC_NS });
|
||||
|
||||
-- if there is a password on the main room let's add the password for the vnode join
|
||||
-- as we will set the password to the vnode room and we will need it
|
||||
local pass = room:get_password();
|
||||
if pass and pass ~= '' then
|
||||
fmuc_pr:tag('password'):text(pass);
|
||||
end
|
||||
fmuc_pr:up();
|
||||
|
||||
module:send(fmuc_pr);
|
||||
|
||||
@@ -83,9 +112,26 @@ local function connect_vnode(event)
|
||||
end
|
||||
end
|
||||
visitors_nodes[room.jid].nodes[conference_service] = sent_main_participants;
|
||||
|
||||
send_visitors_iq(conference_service, room, 'connect');
|
||||
end
|
||||
module:hook('jitsi-connect-vnode', connect_vnode);
|
||||
|
||||
-- listens for responses to the iq sent for connecting vnode
|
||||
local function stanza_handler(event)
|
||||
local origin, stanza = event.origin, event.stanza;
|
||||
|
||||
if stanza.name ~= 'iq' then
|
||||
return;
|
||||
end
|
||||
|
||||
if stanza.attr.type == 'result' and sent_iq_cache:get(stanza.attr.id) then
|
||||
sent_iq_cache:set(stanza.attr.id, nil);
|
||||
return true;
|
||||
end
|
||||
end
|
||||
module:hook('iq/host', stanza_handler, 10);
|
||||
|
||||
-- an event received from visitors component, which receives iqs from jicofo
|
||||
local function disconnect_vnode(event)
|
||||
local room, vnode = event.room, event.vnode;
|
||||
@@ -211,7 +257,7 @@ process_host_module(main_muc_component_config, function(host_module, host)
|
||||
end
|
||||
end);
|
||||
-- forwards messages from main participants to vnodes
|
||||
host_module:hook("muc-occupant-groupchat", function(event)
|
||||
host_module:hook('muc-occupant-groupchat', function(event)
|
||||
local room, stanza, occupant = event.room, event.stanza, event.occupant;
|
||||
|
||||
-- filter sending messages from transcribers/jibris to visitors
|
||||
@@ -231,7 +277,7 @@ process_host_module(main_muc_component_config, function(host_module, host)
|
||||
end);
|
||||
-- receiving messages from visitor nodes and forward them to local main participants
|
||||
-- and forward them to the rest of visitor nodes
|
||||
host_module:hook("muc-occupant-groupchat", function(event)
|
||||
host_module:hook('muc-occupant-groupchat', function(event)
|
||||
local occupant, room, stanza = event.occupant, event.room, event.stanza;
|
||||
local to = stanza.attr.to;
|
||||
local from = stanza.attr.from;
|
||||
@@ -260,4 +306,18 @@ process_host_module(main_muc_component_config, function(host_module, host)
|
||||
|
||||
return true;
|
||||
end, 55); -- prosody check for unknown participant chat is prio 50, we want to override it
|
||||
|
||||
host_module:hook('muc-config-submitted/muc#roomconfig_roomsecret', function(event)
|
||||
if event.status_codes['104'] then
|
||||
local room = event.room;
|
||||
|
||||
if visitors_nodes[room.jid] then
|
||||
-- we need to update all vnodes
|
||||
local vnodes = visitors_nodes[room.jid].nodes;
|
||||
for conference_service in pairs(vnodes) do
|
||||
send_visitors_iq(conference_service, room, 'update');
|
||||
end
|
||||
end
|
||||
end
|
||||
end, -100); -- we want to run last in order to check is the status code 104
|
||||
end);
|
||||
|
||||
@@ -8,7 +8,9 @@ local get_room_from_jid = util.get_room_from_jid;
|
||||
local get_focus_occupant = util.get_focus_occupant;
|
||||
local get_room_by_name_and_subdomain = util.get_room_by_name_and_subdomain;
|
||||
local new_id = require 'util.id'.medium;
|
||||
local um_is_admin = require "core.usermanager".is_admin;
|
||||
local um_is_admin = require 'core.usermanager'.is_admin;
|
||||
|
||||
local MUC_NS = 'http://jabber.org/protocol/muc';
|
||||
|
||||
local muc_domain_prefix = module:get_option_string('muc_mapper_domain_prefix', 'conference');
|
||||
local muc_domain_base = module:get_option_string('muc_mapper_domain_base');
|
||||
@@ -17,7 +19,7 @@ if not muc_domain_base then
|
||||
return;
|
||||
end
|
||||
|
||||
local auto_allow_promotion = module:get_option_boolean("auto_allow_visitor_promotion", false);
|
||||
local auto_allow_promotion = module:get_option_boolean('auto_allow_visitor_promotion', false);
|
||||
|
||||
local function is_admin(jid)
|
||||
return um_is_admin(jid, module.host);
|
||||
@@ -33,7 +35,7 @@ local sent_iq_cache = require 'util.cache'.new(200);
|
||||
local function respond_iq_result(origin, stanza)
|
||||
-- respond with successful receiving the iq
|
||||
origin.send(st.iq({
|
||||
type = "result";
|
||||
type = 'result';
|
||||
from = stanza.attr.to;
|
||||
to = stanza.attr.from;
|
||||
id = stanza.attr.id
|
||||
@@ -158,7 +160,7 @@ local function stanza_handler(event)
|
||||
return processed;
|
||||
end
|
||||
|
||||
module:hook("iq/host", stanza_handler, 10);
|
||||
module:hook('iq/host', stanza_handler, 10);
|
||||
|
||||
--process a host module directly if loaded or hooks to wait for its load
|
||||
function process_host_module(name, callback)
|
||||
@@ -184,6 +186,14 @@ process_host_module(muc_domain_prefix..'.'..muc_domain_base, function(host_modul
|
||||
host_module:hook('muc-occupant-pre-join', function (event)
|
||||
local room, stanza, origin = event.room, event.stanza, event.origin;
|
||||
|
||||
-- visitors were already in the room one way or another they have access
|
||||
-- skip password challenge
|
||||
local join = stanza:get_child('x', MUC_NS);
|
||||
if join and room:get_password() and
|
||||
visitors_promotion_map[room.jid] and visitors_promotion_map[room.jid][jid.node(stanza.attr.from)] then
|
||||
join:tag('password', { xmlns = MUC_NS }):text(room:get_password());
|
||||
end
|
||||
|
||||
-- we skip any checks when auto-allow is enabled
|
||||
if auto_allow_promotion then
|
||||
return;
|
||||
@@ -191,7 +201,7 @@ process_host_module(muc_domain_prefix..'.'..muc_domain_base, function(host_modul
|
||||
|
||||
if visitors_promotion_map[room.jid] then
|
||||
-- now let's check for jid
|
||||
if visitors_promotion_map[room.jid] and visitors_promotion_map[room.jid][jid.node(stanza.attr.from)] then
|
||||
if visitors_promotion_map[room.jid][jid.node(stanza.attr.from)] then
|
||||
-- allow join
|
||||
return;
|
||||
end
|
||||
@@ -208,7 +218,7 @@ end);
|
||||
|
||||
-- enable only in case of auto-allow is enabled
|
||||
if auto_allow_promotion then
|
||||
prosody.events.add_handler("pre-jitsi-authentication", function(session)
|
||||
prosody.events.add_handler('pre-jitsi-authentication', function(session)
|
||||
if not session.customusername or not session.jitsi_web_query_room then
|
||||
return nil;
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user