mirror of https://github.com/jitsi/jitsi-meet
parent
f270b50972
commit
42271b1b89
After Width: | Height: | Size: 256 B |
After Width: | Height: | Size: 194 B |
@ -0,0 +1,116 @@ |
||||
// @flow
|
||||
|
||||
import { PureComponent } from 'react'; |
||||
|
||||
import { sendMessage, setPrivateMessageRecipient } from '../actions'; |
||||
import { getParticipantById } from '../../base/participants'; |
||||
|
||||
type Props = { |
||||
|
||||
/** |
||||
* The message that is about to be sent. |
||||
*/ |
||||
message: Object, |
||||
|
||||
/** |
||||
* The ID of the participant that we think the message may be intended to. |
||||
*/ |
||||
participantID: string, |
||||
|
||||
/** |
||||
* Function to be used to translate i18n keys. |
||||
*/ |
||||
t: Function, |
||||
|
||||
/** |
||||
* Prop to be invoked on sending the message. |
||||
*/ |
||||
_onSendMessage: Function, |
||||
|
||||
/** |
||||
* Prop to be invoked when the user wants to set a private recipient. |
||||
*/ |
||||
_onSetMessageRecipient: Function, |
||||
|
||||
/** |
||||
* The participant retreived from Redux by the participanrID prop. |
||||
*/ |
||||
_participant: Object |
||||
}; |
||||
|
||||
/** |
||||
* Abstract class for the dialog displayed to avoid mis-sending private messages. |
||||
*/ |
||||
export class AbstractChatPrivacyDialog extends PureComponent<Props> { |
||||
/** |
||||
* Instantiates a new instance. |
||||
* |
||||
* @inheritdoc |
||||
*/ |
||||
constructor(props: Props) { |
||||
super(props); |
||||
|
||||
this._onSendGroupMessage = this._onSendGroupMessage.bind(this); |
||||
this._onSendPrivateMessage = this._onSendPrivateMessage.bind(this); |
||||
} |
||||
|
||||
_onSendGroupMessage: () => boolean; |
||||
|
||||
/** |
||||
* Callback to be invoked for cancel action (user wants to send a group message). |
||||
* |
||||
* @returns {boolean} |
||||
*/ |
||||
_onSendGroupMessage() { |
||||
this.props._onSendMessage(this.props.message); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
_onSendPrivateMessage: () => boolean; |
||||
|
||||
/** |
||||
* Callback to be invoked for submit action (user wants to send a private message). |
||||
* |
||||
* @returns {void} |
||||
*/ |
||||
_onSendPrivateMessage() { |
||||
const { message, _onSendMessage, _onSetMessageRecipient, _participant } = this.props; |
||||
|
||||
_onSetMessageRecipient(_participant); |
||||
_onSendMessage(message); |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Maps part of the props of this component to Redux actions. |
||||
* |
||||
* @param {Function} dispatch - The Redux dispatch function. |
||||
* @returns {Props} |
||||
*/ |
||||
export function _mapDispatchToProps(dispatch: Function): $Shape<Props> { |
||||
return { |
||||
_onSendMessage: (message: Object) => { |
||||
dispatch(sendMessage(message, true)); |
||||
}, |
||||
|
||||
_onSetMessageRecipient: participant => { |
||||
dispatch(setPrivateMessageRecipient(participant)); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Maps part of the Redux store to the props of this component. |
||||
* |
||||
* @param {Object} state - The Redux state. |
||||
* @param {Props} ownProps - The own props of the component. |
||||
* @returns {Props} |
||||
*/ |
||||
export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> { |
||||
return { |
||||
_participant: getParticipantById(state, ownProps.participantID) |
||||
}; |
||||
} |
@ -0,0 +1,61 @@ |
||||
// @flow
|
||||
|
||||
import { PureComponent } from 'react'; |
||||
|
||||
import { getParticipantDisplayName } from '../../base/participants'; |
||||
|
||||
import { setPrivateMessageRecipient } from '../actions'; |
||||
|
||||
type Props = { |
||||
|
||||
/** |
||||
* Function used to translate i18n labels. |
||||
*/ |
||||
t: Function, |
||||
|
||||
/** |
||||
* Function to remove the recipent setting of the chat window. |
||||
*/ |
||||
_onRemovePrivateMessageRecipient: Function, |
||||
|
||||
/** |
||||
* The name of the message recipient, if any. |
||||
*/ |
||||
_privateMessageRecipient: ?string |
||||
}; |
||||
|
||||
/** |
||||
* Abstract class for the {@code MessageRecipient} component. |
||||
*/ |
||||
export default class AbstractMessageRecipient extends PureComponent<Props> { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Maps part of the props of this component to Redux actions. |
||||
* |
||||
* @param {Function} dispatch - The Redux dispatch function. |
||||
* @returns {Props} |
||||
*/ |
||||
export function _mapDispatchToProps(dispatch: Function): $Shape<Props> { |
||||
return { |
||||
_onRemovePrivateMessageRecipient: () => { |
||||
dispatch(setPrivateMessageRecipient()); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Maps part of the Redux store to the props of this component. |
||||
* |
||||
* @param {Object} state - The Redux state. |
||||
* @returns {Props} |
||||
*/ |
||||
export function _mapStateToProps(state: Object): $Shape<Props> { |
||||
const { privateMessageRecipient } = state['features/chat']; |
||||
|
||||
return { |
||||
_privateMessageRecipient: |
||||
privateMessageRecipient ? getParticipantDisplayName(state, privateMessageRecipient.id) : undefined |
||||
}; |
||||
} |
@ -0,0 +1,101 @@ |
||||
// @flow
|
||||
|
||||
import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox'; |
||||
|
||||
import { translate } from '../../base/i18n'; |
||||
import { IconMessage, IconReply } from '../../base/icons'; |
||||
import { getParticipantById } from '../../base/participants'; |
||||
import { connect } from '../../base/redux'; |
||||
|
||||
import { setPrivateMessageRecipient } from '../actions'; |
||||
|
||||
export type Props = AbstractButtonProps & { |
||||
|
||||
/** |
||||
* The ID of the participant that the message is to be sent. |
||||
*/ |
||||
participantID: string, |
||||
|
||||
/** |
||||
* True if the button is rendered as a reply button. |
||||
*/ |
||||
reply: boolean, |
||||
|
||||
/** |
||||
* Function to be used to translate i18n labels. |
||||
*/ |
||||
t: Function, |
||||
|
||||
/** |
||||
* The participant object retreived from Redux. |
||||
*/ |
||||
_participant: Object, |
||||
|
||||
/** |
||||
* Function to dispatch the result of the participant selection to send a private message. |
||||
*/ |
||||
_setPrivateMessageRecipient: Function |
||||
}; |
||||
|
||||
/** |
||||
* Class to render a button that initiates the sending of a private message through chet. |
||||
*/ |
||||
class PrivateMessageButton extends AbstractButton<Props, any> { |
||||
accessibilityLabel = 'toolbar.accessibilityLabel.privateMessage'; |
||||
icon = IconMessage; |
||||
label = 'toolbar.privateMessage'; |
||||
toggledIcon = IconReply; |
||||
|
||||
/** |
||||
* Handles clicking / pressing the button, and kicks the participant. |
||||
* |
||||
* @private |
||||
* @returns {void} |
||||
*/ |
||||
_handleClick() { |
||||
const { _participant, _setPrivateMessageRecipient } = this.props; |
||||
|
||||
_setPrivateMessageRecipient(_participant); |
||||
} |
||||
|
||||
/** |
||||
* Helper function to be implemented by subclasses, which must return a |
||||
* {@code boolean} value indicating if this button is toggled or not. |
||||
* |
||||
* @protected |
||||
* @returns {boolean} |
||||
*/ |
||||
_isToggled() { |
||||
return this.props.reply; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Maps part of the props of this component to Redux actions. |
||||
* |
||||
* @param {Function} dispatch - The Redux dispatch function. |
||||
* @returns {Props} |
||||
*/ |
||||
export function _mapDispatchToProps(dispatch: Function): $Shape<Props> { |
||||
return { |
||||
_setPrivateMessageRecipient: participant => { |
||||
dispatch(setPrivateMessageRecipient(participant)); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Maps part of the Redux store to the props of this component. |
||||
* |
||||
* @param {Object} state - The Redux state. |
||||
* @param {Props} ownProps - The own props of the component. |
||||
* @returns {Props} |
||||
*/ |
||||
export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> { |
||||
return { |
||||
_participant: getParticipantById(state, ownProps.participantID) |
||||
}; |
||||
} |
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(PrivateMessageButton)); |
@ -1,3 +1,4 @@ |
||||
// @flow
|
||||
|
||||
export * from './native'; |
||||
export { default as PrivateMessageButton } from './PrivateMessageButton'; |
||||
|
@ -1,3 +1,5 @@ |
||||
// @flow
|
||||
|
||||
export * from './web'; |
||||
|
||||
export { default as PrivateMessageButton } from './PrivateMessageButton'; |
||||
|
@ -0,0 +1,37 @@ |
||||
// @flow
|
||||
|
||||
import React from 'react'; |
||||
|
||||
import { ConfirmDialog } from '../../../base/dialog'; |
||||
import { translate } from '../../../base/i18n'; |
||||
import { connect } from '../../../base/redux'; |
||||
|
||||
import { AbstractChatPrivacyDialog, _mapDispatchToProps, _mapStateToProps } from '../AbstractChatPrivacyDialog'; |
||||
|
||||
/** |
||||
* Implements a component for the dialog displayed to avoid mis-sending private messages. |
||||
*/ |
||||
class ChatPrivacyDialog extends AbstractChatPrivacyDialog { |
||||
/** |
||||
* Implements React's {@link Component#render()}. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render() { |
||||
return ( |
||||
<ConfirmDialog |
||||
cancelKey = 'dialog.sendPrivateMessageCancel' |
||||
contentKey = 'dialog.sendPrivateMessage' |
||||
okKey = 'dialog.sendPrivateMessageOk' |
||||
onCancel = { this._onSendGroupMessage } |
||||
onSubmit = { this._onSendPrivateMessage } /> |
||||
); |
||||
} |
||||
|
||||
_onSendGroupMessage: () => boolean; |
||||
|
||||
_onSendPrivateMessage: () => boolean; |
||||
} |
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(ChatPrivacyDialog)); |
@ -0,0 +1,52 @@ |
||||
// @flow
|
||||
|
||||
import React from 'react'; |
||||
import { Text, TouchableHighlight, View } from 'react-native'; |
||||
|
||||
import { translate } from '../../../base/i18n'; |
||||
import { Icon, IconCancelSelection } from '../../../base/icons'; |
||||
import { connect } from '../../../base/redux'; |
||||
|
||||
import AbstractMessageRecipient, { |
||||
_mapDispatchToProps, |
||||
_mapStateToProps |
||||
} from '../AbstractMessageRecipient'; |
||||
|
||||
import styles from './styles'; |
||||
|
||||
/** |
||||
* Class to implement the displaying of the recipient of the next message. |
||||
*/ |
||||
class MessageRecipient extends AbstractMessageRecipient { |
||||
/** |
||||
* Implements {@code PureComponent#render}. |
||||
* |
||||
* @inheritdoc |
||||
*/ |
||||
render() { |
||||
const { _privateMessageRecipient } = this.props; |
||||
|
||||
if (!_privateMessageRecipient) { |
||||
return null; |
||||
} |
||||
|
||||
const { t } = this.props; |
||||
|
||||
return ( |
||||
<View style = { styles.messageRecipientContainer }> |
||||
<Text style = { styles.messageRecipientText }> |
||||
{ t('chat.messageTo', { |
||||
recipient: _privateMessageRecipient |
||||
}) } |
||||
</Text> |
||||
<TouchableHighlight onPress = { this.props._onRemovePrivateMessageRecipient }> |
||||
<Icon |
||||
src = { IconCancelSelection } |
||||
style = { styles.messageRecipientCancelIcon } /> |
||||
</TouchableHighlight> |
||||
</View> |
||||
); |
||||
} |
||||
} |
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(MessageRecipient)); |
@ -0,0 +1,42 @@ |
||||
/* @flow */ |
||||
|
||||
import React from 'react'; |
||||
|
||||
import { Dialog } from '../../../base/dialog'; |
||||
import { translate } from '../../../base/i18n'; |
||||
import { connect } from '../../../base/redux'; |
||||
|
||||
import { AbstractChatPrivacyDialog, _mapDispatchToProps, _mapStateToProps } from '../AbstractChatPrivacyDialog'; |
||||
|
||||
/** |
||||
* Implements a component for the dialog displayed to avoid mis-sending private messages. |
||||
*/ |
||||
class ChatPrivacyDialog extends AbstractChatPrivacyDialog { |
||||
/** |
||||
* Implements React's {@link Component#render()}. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render() { |
||||
return ( |
||||
<Dialog |
||||
cancelKey = 'dialog.sendPrivateMessageCancel' |
||||
okKey = 'dialog.sendPrivateMessageOk' |
||||
onCancel = { this._onSendGroupMessage } |
||||
onSubmit = { this._onSendPrivateMessage } |
||||
titleKey = 'dialog.sendPrivateMessageTitle' |
||||
width = 'small'> |
||||
<div> |
||||
{ this.props.t('dialog.sendPrivateMessage') } |
||||
</div> |
||||
</Dialog> |
||||
); |
||||
} |
||||
|
||||
_onSendGroupMessage: () => boolean; |
||||
|
||||
_onSendPrivateMessage: () => boolean; |
||||
} |
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(ChatPrivacyDialog)); |
@ -0,0 +1,48 @@ |
||||
// @flow
|
||||
|
||||
import React from 'react'; |
||||
|
||||
import { translate } from '../../../base/i18n'; |
||||
import { Icon, IconCancelSelection } from '../../../base/icons'; |
||||
import { connect } from '../../../base/redux'; |
||||
|
||||
import AbstractMessageRecipient, { |
||||
_mapDispatchToProps, |
||||
_mapStateToProps |
||||
} from '../AbstractMessageRecipient'; |
||||
|
||||
/** |
||||
* Class to implement the displaying of the recipient of the next message. |
||||
*/ |
||||
class MessageRecipient extends AbstractMessageRecipient { |
||||
/** |
||||
* Implements {@code PureComponent#render}. |
||||
* |
||||
* @inheritdoc |
||||
*/ |
||||
render() { |
||||
const { _privateMessageRecipient } = this.props; |
||||
|
||||
if (!_privateMessageRecipient) { |
||||
return null; |
||||
} |
||||
|
||||
const { t } = this.props; |
||||
|
||||
return ( |
||||
<div id = 'chat-recipient'> |
||||
<span> |
||||
{ t('chat.messageTo', { |
||||
recipient: _privateMessageRecipient |
||||
}) } |
||||
</span> |
||||
<div onClick = { this.props._onRemovePrivateMessageRecipient }> |
||||
<Icon |
||||
src = { IconCancelSelection } /> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
||||
} |
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(MessageRecipient)); |
@ -0,0 +1,62 @@ |
||||
// @flow
|
||||
|
||||
import React, { Component } from 'react'; |
||||
|
||||
import { translate } from '../../../base/i18n'; |
||||
import { IconMessage } from '../../../base/icons'; |
||||
import { connect } from '../../../base/redux'; |
||||
import { _mapDispatchToProps, _mapStateToProps, type Props } from '../../../chat/components/PrivateMessageButton'; |
||||
|
||||
import RemoteVideoMenuButton from './RemoteVideoMenuButton'; |
||||
|
||||
/** |
||||
* A custom implementation of the PrivateMessageButton specialized for |
||||
* the web version of the remote video menu. When the web platform starts to use |
||||
* the {@code AbstractButton} component for the remote video menu, we can get rid |
||||
* of this component and use the generic button in the chat feature. |
||||
*/ |
||||
class PrivateMessageMenuButton extends Component<Props> { |
||||
/** |
||||
* Instantiates a new Component instance. |
||||
* |
||||
* @inheritdoc |
||||
*/ |
||||
constructor(props: Props) { |
||||
super(props); |
||||
|
||||
this._onClick = this._onClick.bind(this); |
||||
} |
||||
|
||||
/** |
||||
* Implements React's {@link Component#render()}. |
||||
* |
||||
* @inheritdoc |
||||
* @returns {ReactElement} |
||||
*/ |
||||
render() { |
||||
const { participantID, t } = this.props; |
||||
|
||||
return ( |
||||
<RemoteVideoMenuButton |
||||
buttonText = { t('toolbar.privateMessage') } |
||||
icon = { IconMessage } |
||||
id = { `privmsglink_${participantID}` } |
||||
onClick = { this._onClick } /> |
||||
); |
||||
} |
||||
|
||||
_onClick: () => void; |
||||
|
||||
/** |
||||
* Callback to be invoked on pressing the button. |
||||
* |
||||
* @returns {void} |
||||
*/ |
||||
_onClick() { |
||||
const { _participant, _setPrivateMessageRecipient } = this.props; |
||||
|
||||
_setPrivateMessageRecipient(_participant); |
||||
} |
||||
} |
||||
|
||||
export default translate(connect(_mapStateToProps, _mapDispatchToProps)(PrivateMessageMenuButton)); |
Loading…
Reference in new issue