Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ var config = {
// Disables polls feature.
// disablePolls: false,

// Disables chat feature entirely including notifications, sounds, and private messages.
// disableChat: false,

// Disables demote button from self-view
// disableSelfDemote: false,

Expand Down
10 changes: 10 additions & 0 deletions lang/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,16 @@
"messagebox": "Type a message",
"newMessages": "New messages",
"nickname": {
"featureChat": "chat",
"featureClosedCaptions": "closed captions",
"featureFileSharing": "file sharing",
"featurePolls": "polls",
"popover": "Choose a nickname",
"title": "Enter a nickname to use chat",
"titleWith1Features": "Enter a nickname to use {{feature1}}",
"titleWith2Features": "Enter a nickname to use {{feature1}} and {{feature2}}",
"titleWith3Features": "Enter a nickname to use {{feature1}}, {{feature2}} and {{feature3}}",
"titleWith4Features": "Enter a nickname to use {{feature1}}, {{feature2}}, {{feature3}} and {{feature4}}",
"titleWithCC": "Enter a nickname to use chat and closed captions",
"titleWithPolls": "Enter a nickname to use chat and polls",
"titleWithPollsAndCC": "Enter a nickname to use chat, polls and closed captions",
Expand Down Expand Up @@ -1429,6 +1437,7 @@
"exitFullScreen": "Exit full screen",
"exitTileView": "Exit tile view",
"feedback": "Leave feedback",
"fileSharing": "File sharing",
"giphy": "Toggle GIPHY menu",
"hangup": "Leave the meeting",
"help": "Help",
Expand Down Expand Up @@ -1464,6 +1473,7 @@
"openReactionsMenu": "Open reactions menu",
"participants": "Participants",
"pip": "Enter Picture-in-Picture mode",
"polls": "Polls",
"privateMessage": "Send private message",
"profile": "Edit your profile",
"raiseHand": "Raise your hand",
Expand Down
1 change: 1 addition & 0 deletions react/features/base/config/configType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ export interface IConfig {
disableAudioLevels?: boolean;
disableBeforeUnloadHandlers?: boolean;
disableCameraTintForeground?: boolean;
disableChat?: boolean;
disableChatSmileys?: boolean;
disableDeepLinking?: boolean;
disableFilmstripAutohiding?: boolean;
Expand Down
1 change: 1 addition & 0 deletions react/features/base/config/configWhitelist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default [
'disableAudioLevels',
'disableBeforeUnloadHandlers',
'disableCameraTintForeground',
'disableChat',
'disableChatSmileys',
'disableDeepLinking',
'disabledNotifications',
Expand Down
28 changes: 28 additions & 0 deletions react/features/chat/actions.any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,34 @@ export function openCCPanel() {
};
}

/**
* Opens the chat panel with polls tab active.
*
* @returns {Object} The redux action.
*/
export function openPollsPanel() {
return async (dispatch: IStore['dispatch']) => {
dispatch(setFocusedTab(ChatTabs.POLLS));
dispatch({
type: OPEN_CHAT
});
};
}

/**
* Opens the chat panel with file sharing tab active.
*
* @returns {Object} The redux action.
*/
export function openFileSharingPanel() {
return async (dispatch: IStore['dispatch']) => {
dispatch(setFocusedTab(ChatTabs.FILE_SHARING));
dispatch({
type: OPEN_CHAT
});
};
}


/**
* Initiates the sending of messages between a moderator and a lobby attendee.
Expand Down
27 changes: 15 additions & 12 deletions react/features/chat/actions.native.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
import { IStore } from '../app/types';
import { IParticipant } from '../base/participants/types';
import { navigate } from '../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { screen } from '../mobile/navigation/routes';

import { OPEN_CHAT } from './actionTypes';
import { setFocusedTab } from './actions.any';
import { ChatTabs } from './constants';

export * from './actions.any';

/**
* Displays the chat panel.
* Displays the chat panel with the CHAT tab active.
*
* @param {Object} participant - The recipient for the private chat.
* @param {boolean} disablePolls - Checks if polls are disabled.
*
* @returns {{
* participant: participant,
* type: OPEN_CHAT
* }}
* @returns {Function}
*/
export function openChat(participant?: IParticipant | undefined | Object, disablePolls?: boolean) {
if (disablePolls) {
navigate(screen.conference.chat);
}
navigate(screen.conference.chatandpolls.main);
return (dispatch: IStore['dispatch']) => {
if (disablePolls) {
navigate(screen.conference.chat);
}
navigate(screen.conference.chatandpolls.main);

return {
participant,
type: OPEN_CHAT
dispatch(setFocusedTab(ChatTabs.CHAT));
dispatch({
participant,
type: OPEN_CHAT
});
};
}
6 changes: 4 additions & 2 deletions react/features/chat/actions.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import {
SET_CHAT_WIDTH,
SET_USER_CHAT_WIDTH
} from './actionTypes';
import { closeChat } from './actions.any';
import { closeChat, setFocusedTab } from './actions.any';
import { ChatTabs } from './constants';

export * from './actions.any';

/**
* Displays the chat panel.
* Displays the chat panel with the CHAT tab active.
*
* @param {Object} participant - The recipient for the private chat.
* @param {Object} _disablePolls - Used on native.
Expand All @@ -24,6 +25,7 @@ export * from './actions.any';
*/
export function openChat(participant?: Object, _disablePolls?: boolean) {
return function(dispatch: IStore['dispatch']) {
dispatch(setFocusedTab(ChatTabs.CHAT));
dispatch({
participant,
type: OPEN_CHAT
Expand Down
4 changes: 2 additions & 2 deletions react/features/chat/components/native/ChatButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { arePollsDisabled } from '../../../conference/functions.any';
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { screen } from '../../../mobile/navigation/routes';
import { getUnreadPollCount } from '../../../polls/functions';
import { getUnreadCount, getUnreadFilesCount } from '../../functions';
import { getUnreadCount, getUnreadFilesCount, isChatDisabled } from '../../functions';

interface IProps extends AbstractButtonProps {

Expand Down Expand Up @@ -65,7 +65,7 @@ class ChatButton extends AbstractButton<IProps> {
* @returns {IProps}
*/
function _mapStateToProps(state: IReduxState, ownProps: any) {
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
const enabled = getFeatureFlag(state, CHAT_ENABLED, true) && !isChatDisabled(state);
const { visible = enabled } = ownProps;

return {
Expand Down
44 changes: 34 additions & 10 deletions react/features/chat/components/web/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
toggleChat
} from '../../actions.web';
import { CHAT_SIZE, ChatTabs, OPTION_GROUPCHAT, SMALL_WIDTH_THRESHOLD } from '../../constants';
import { getChatMaxSize } from '../../functions';
import { getChatMaxSize, getFocusedTab, isChatDisabled } from '../../functions';
import { IChatProps as AbstractProps } from '../../types';

import ChatHeader from './ChatHeader';
Expand All @@ -41,13 +41,18 @@ interface IProps extends AbstractProps {
/**
* The currently focused tab.
*/
_focusedTab: ChatTabs;
_focusedTab?: ChatTabs;

/**
* True if the CC tab is enabled and false otherwise.
*/
_isCCTabEnabled: boolean;

/**
* True if chat is disabled.
*/
_isChatDisabled: boolean;

/**
* True if file sharing tab is enabled.
*/
Expand Down Expand Up @@ -217,6 +222,7 @@ const Chat = ({
_isOpen,
_isPollsEnabled,
_isCCTabEnabled,
_isChatDisabled,
_isFileSharingTabEnabled,
_focusedTab,
_isResizing,
Expand All @@ -229,6 +235,11 @@ const Chat = ({
dispatch,
t
}: IProps) => {
// If no tabs are available, don't render the chat panel at all.
if (_isChatDisabled && !_isPollsEnabled && !_isCCTabEnabled && !_isFileSharingTabEnabled) {
return null;
}

const { classes, cx } = useStyles({ _isResizing, width: _width });
const [ isMouseDown, setIsMouseDown ] = useState(false);
const [ mousePosition, setMousePosition ] = useState<number | null>(null);
Expand Down Expand Up @@ -416,7 +427,7 @@ const Chat = ({
return (
<>
{renderTabs()}
<div
{!_isChatDisabled && (<div
aria-labelledby = { ChatTabs.CHAT }
className = { cx(
classes.chatPanel,
Expand All @@ -442,7 +453,7 @@ const Chat = ({
)}
<ChatInput
onSend = { onSendMessage } />
</div>
</div>) }
{ _isPollsEnabled && (
<>
<div
Expand Down Expand Up @@ -484,17 +495,27 @@ const Chat = ({
* @returns {ReactElement}
*/
function renderTabs() {
let tabs = [
{
// The only way focused tab will be undefined is when no tab is enabled. Therefore this function won't be
// executed because Chat component won't render anything. This should never happen but adding the check
// here to make TS happy (when passing the _focusedTab in the selected prop for Tabs).
if (!_focusedTab) {
return null;
}

let tabs = [];

// Only add chat tab if chat is not disabled.
if (!_isChatDisabled) {
tabs.push({
accessibilityLabel: t('chat.tabs.chat'),
countBadge:
_focusedTab !== ChatTabs.CHAT && _unreadMessagesCount > 0 ? _unreadMessagesCount : undefined,
id: ChatTabs.CHAT,
controlsId: `${ChatTabs.CHAT}-panel`,
icon: IconMessage,
title: t('chat.tabs.chat')
}
];
});
}

if (_isPollsEnabled) {
tabs.push({
Expand Down Expand Up @@ -564,6 +585,8 @@ const Chat = ({
{_showNamePrompt
? <DisplayNameForm
isCCTabEnabled = { _isCCTabEnabled }
isChatDisabled = { _isChatDisabled }
isFileSharingEnabled = { _isFileSharingTabEnabled }
isPollsEnabled = { _isPollsEnabled } />
: renderChat()}
<div
Expand Down Expand Up @@ -602,7 +625,7 @@ const Chat = ({
* }}
*/
function _mapStateToProps(state: IReduxState, _ownProps: any) {
const { isOpen, focusedTab, messages, unreadMessagesCount, unreadFilesCount, width, isResizing } = state['features/chat'];
const { isOpen, messages, unreadMessagesCount, unreadFilesCount, width, isResizing } = state['features/chat'];
const { unreadPollsCount } = state['features/polls'];
const _localParticipant = getLocalParticipant(state);

Expand All @@ -611,8 +634,9 @@ function _mapStateToProps(state: IReduxState, _ownProps: any) {
_isOpen: isOpen,
_isPollsEnabled: !arePollsDisabled(state),
_isCCTabEnabled: isCCTabEnabled(state),
_isChatDisabled: isChatDisabled(state),
_isFileSharingTabEnabled: isFileSharingEnabled(state),
_focusedTab: focusedTab,
_focusedTab: getFocusedTab(state),
_messages: messages,
_unreadMessagesCount: unreadMessagesCount,
_unreadPollsCount: unreadPollsCount,
Expand Down
4 changes: 3 additions & 1 deletion react/features/chat/components/web/ChatButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { IconMessage } from '../../../base/icons/svg';
import AbstractButton, { IProps as AbstractButtonProps } from '../../../base/toolbox/components/AbstractButton';
import { closeOverflowMenuIfOpen } from '../../../toolbox/actions.web';
import { toggleChat } from '../../actions.web';
import { isChatDisabled } from '../../functions';

import ChatCounter from './ChatCounter';

Expand Down Expand Up @@ -91,7 +92,8 @@ class ChatButton extends AbstractButton<IProps> {
*/
const mapStateToProps = (state: IReduxState) => {
return {
_chatOpen: state['features/chat'].isOpen
_chatOpen: state['features/chat'].isOpen,
visible: !isChatDisabled(state)
};
};

Expand Down
12 changes: 9 additions & 3 deletions react/features/chat/components/web/ChatHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';

import { IReduxState } from '../../../app/types';
import Icon from '../../../base/icons/components/Icon';
import { IconCloseLarge } from '../../../base/icons/svg';
import { isFileSharingEnabled } from '../../../file-sharing/functions.any';
import { toggleChat } from '../../actions.web';
import { ChatTabs } from '../../constants';
import { getFocusedTab, isChatDisabled } from '../../functions';

interface IProps {

Expand Down Expand Up @@ -40,7 +40,8 @@ interface IProps {
function ChatHeader({ className, isCCTabEnabled, isPollsEnabled }: IProps) {
const dispatch = useDispatch();
const { t } = useTranslation();
const { focusedTab } = useSelector((state: IReduxState) => state['features/chat']);
const _isChatDisabled = useSelector(isChatDisabled);
const focusedTab = useSelector(getFocusedTab);
const fileSharingTabEnabled = useSelector(isFileSharingEnabled);

const onCancel = useCallback(() => {
Expand All @@ -56,14 +57,19 @@ function ChatHeader({ className, isCCTabEnabled, isPollsEnabled }: IProps) {

let title = 'chat.title';

if (focusedTab === ChatTabs.CHAT) {
if (!_isChatDisabled && focusedTab === ChatTabs.CHAT) {
title = 'chat.tabs.chat';
} else if (isPollsEnabled && focusedTab === ChatTabs.POLLS) {
title = 'chat.tabs.polls';
} else if (isCCTabEnabled && focusedTab === ChatTabs.CLOSED_CAPTIONS) {
title = 'chat.tabs.closedCaptions';
} else if (fileSharingTabEnabled && focusedTab === ChatTabs.FILE_SHARING) {
title = 'chat.tabs.fileSharing';
} else {
// If the focused tab is not enabled, don't render the header.
// This should not happen in normal circumstances since Chat.tsx already checks
// if any tabs are available before rendering.
return null;
}

return (
Expand Down
Loading