Compare commits

...

11 Commits

Author SHA1 Message Date
Duduman Bogdan Vlad
243a330318 feat(thumbnail,filmstrip) show blackend thumbnail for participant on stage 2022-11-21 10:03:03 +01:00
_norbert
98bc87ea18 lang: fixing typo in a hungarian lang file (#12559)
* fixing typo in a hungarian lang file

* revert end of line

Co-authored-by: bartuczns <bartucz.norbertsandor@nisz.hu>
2022-11-19 15:35:43 -06:00
Saúl Ibarra Corretgé
f7926c9cfb fixup! 2022-11-18 19:56:36 +01:00
Saúl Ibarra Corretgé
533501deb6 fixup! 2022-11-18 19:56:36 +01:00
Saúl Ibarra Corretgé
f38c9f5450 feat(notification,external-api) notify bridge channel failures 2022-11-18 19:56:36 +01:00
Jaya Allamsetty
55b80c948f chore(deps) lib-jitsi-meet@latest
https://github.com/jitsi/lib-jitsi-meet/compare/v1535.0.0+e6263e7c...v1538.0.0+871968af
2022-11-18 13:38:37 -05:00
Calinteodor
971fe0481f feat(chat/polls/native) Update chat and polls UI (#12550)
* feat(chat/polls/native): update ui
2022-11-18 14:46:54 +02:00
Calin-Teodor
1259e54d46 fix(conference/native): apply width and height only on the connection indicator 2022-11-18 13:22:55 +01:00
Calin-Teodor
0cb95f1dd6 fix(conference/native): video quality label ui updates 2022-11-18 13:22:55 +01:00
Calin-Teodor
5cde9a138b fix(conference/native): fixed title bar indicators style 2022-11-18 13:22:55 +01:00
robertpin
867c488e10 fix(dialog) Update max height 2022-11-18 13:22:43 +01:00
37 changed files with 459 additions and 273 deletions

View File

@@ -44,6 +44,7 @@ import {
conferenceUniqueIdSet,
conferenceWillJoin,
conferenceWillLeave,
dataChannelClosed,
dataChannelOpened,
e2eRttChanged,
getConferenceOptions,
@@ -134,9 +135,12 @@ import {
import { maybeSetLobbyChatMessageListener } from './react/features/lobby/actions.any';
import { setNoiseSuppressionEnabled } from './react/features/noise-suppression/actions';
import {
DATA_CHANNEL_CLOSED_NOTIFICATION_ID,
NOTIFICATION_TIMEOUT_TYPE,
hideNotification,
isModerationNotificationDisplayed,
showNotification
showNotification,
showWarningNotification
} from './react/features/notifications';
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
import { suspendDetected } from './react/features/power-monitor';
@@ -2067,6 +2071,18 @@ export default {
room.on(
JitsiConferenceEvents.DATA_CHANNEL_OPENED, () => {
APP.store.dispatch(dataChannelOpened());
APP.store.dispatch(hideNotification(DATA_CHANNEL_CLOSED_NOTIFICATION_ID));
}
);
room.on(
JitsiConferenceEvents.DATA_CHANNEL_CLOSED, ev => {
APP.store.dispatch(dataChannelClosed(ev.code, ev.reason));
APP.store.dispatch(showWarningNotification({
descriptionKey: 'notify.dataChannelClosedDescription',
titleKey: 'notify.dataChannelClosed',
uid: DATA_CHANNEL_CLOSED_NOTIFICATION_ID
}, NOTIFICATION_TIMEOUT_TYPE.STICKY));
}
);

View File

@@ -657,7 +657,7 @@
"login": "Bejelentkezés",
"logout": "Kijelentkezés",
"lowerYourHand": "Kéz leengedése",
"moreActions": "További műveltek",
"moreActions": "További műveletek",
"moreOptions": "További beállítások",
"mute": "Némítás / Visszahangosítás",
"muteEveryone": "Mindenki elnémítása",

View File

@@ -649,6 +649,8 @@
"connectedOneMember": "{{name}} joined the meeting",
"connectedThreePlusMembers": "{{name}} and many others joined the meeting",
"connectedTwoMembers": "{{first}} and {{second}} joined the meeting",
"dataChannelClosed": "Video quality impaired",
"dataChannelClosedDescription": "The bridge channel has been disconnected and thus video quality is limited to its lowest setting.",
"disconnected": "disconnected",
"displayNotifications": "Display notifications for",
"focus": "Conference focus",

View File

@@ -1450,6 +1450,22 @@ class API {
});
}
/**
* Notify external application that the data channel has been closed.
*
* @param {number} code - The close code.
* @param {string} reason - The close reason.
*
* @returns {void}
*/
notifyDataChannelClosed(code: number, reason: string) {
this._sendEvent({
name: 'data-channel-closed',
code,
reason
});
}
/**
* Notify external application that the data channel has been opened.
*

View File

@@ -106,6 +106,7 @@ const events = {
'camera-error': 'cameraError',
'chat-updated': 'chatUpdated',
'content-sharing-participants-changed': 'contentSharingParticipantsChanged',
'data-channel-closed': 'dataChannelClosed',
'data-channel-opened': 'dataChannelOpened',
'device-list-changed': 'deviceListChanged',
'display-name-change': 'displayNameChange',

10
package-lock.json generated
View File

@@ -74,7 +74,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1538.0.0+871968af/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -13497,8 +13497,8 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
"integrity": "sha512-RgMoesoWyscWi2fL9Hxp8PUwDlUtHbo+GhXosD3GeKR0zmihu/kxTONMUifGQnF8XdtcjaZfL2jCJynLwYKlkw==",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1538.0.0+871968af/lib-jitsi-meet.tgz",
"integrity": "sha512-Nd6r6BWQXUE46lnXCtIa/kZoROBQN1Cbn5FEswrFBxhZ0/+JFpsMAwrNa/HThaNsGYkgN7fPoP4Xlq5r/M2o4Q==",
"license": "Apache-2.0",
"dependencies": {
"@jitsi/js-utils": "2.0.0",
@@ -30510,8 +30510,8 @@
}
},
"lib-jitsi-meet": {
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
"integrity": "sha512-RgMoesoWyscWi2fL9Hxp8PUwDlUtHbo+GhXosD3GeKR0zmihu/kxTONMUifGQnF8XdtcjaZfL2jCJynLwYKlkw==",
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1538.0.0+871968af/lib-jitsi-meet.tgz",
"integrity": "sha512-Nd6r6BWQXUE46lnXCtIa/kZoROBQN1Cbn5FEswrFBxhZ0/+JFpsMAwrNa/HThaNsGYkgN7fPoP4Xlq5r/M2o4Q==",
"requires": {
"@jitsi/js-utils": "2.0.0",
"@jitsi/logger": "2.0.0",

View File

@@ -79,7 +79,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1535.0.0+e6263e7c/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1538.0.0+871968af/lib-jitsi-meet.tgz",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",

View File

@@ -1,5 +1,3 @@
// @flow
import { ColorPalette, getRGBAFormat } from '../styles';
/**
@@ -14,21 +12,6 @@ export default {
icon: 'rgb(28, 32, 37)',
text: 'rgb(28, 32, 37)'
},
'Chat': {
displayName: 'rgb(94, 109, 121)',
localMsgBackground: 'rgb(215, 230, 249)',
lobbyMsgBackground: 'rgb(106, 80, 211)',
lobbyMsgNotice: 'rgb(16, 10, 41)',
privateMsgBackground: 'rgb(250, 219, 219)',
privateMsgNotice: 'rgb(186, 39, 58)',
remoteMsgBackground: 'rgb(241, 242, 246)',
replyBorder: 'rgb(219, 197, 200)',
replyIcon: 'rgb(94, 109, 121)'
},
'Conference': {
inviteButtonBackground: 'rgb(0, 119, 225)',
onVideoText: 'white'
},
'Dialog': {},
'Header': {
background: ColorPalette.blue,

View File

@@ -138,6 +138,18 @@ export const CONFERENCE_WILL_LEAVE = 'CONFERENCE_WILL_LEAVE';
*/
export const DATA_CHANNEL_OPENED = 'DATA_CHANNEL_OPENED';
/**
* The type of (redux) action which signals that the data channel with the
* bridge has been closed.
*
* {
* type: DATA_CHANNEL_CLOSED,
* code: number,
* reason: string
* }
*/
export const DATA_CHANNEL_CLOSED = 'DATA_CHANNEL_CLOSED';
/**
* The type of action which signals that the user has been kicked out from
* the conference.

View File

@@ -41,6 +41,7 @@ import {
CONFERENCE_UNIQUE_ID_SET,
CONFERENCE_WILL_JOIN,
CONFERENCE_WILL_LEAVE,
DATA_CHANNEL_CLOSED,
DATA_CHANNEL_OPENED,
E2E_RTT_CHANGED,
KICKED_OUT,
@@ -581,6 +582,26 @@ export function dataChannelOpened() {
};
}
/**
* Signals the data channel with the bridge was abruptly closed.
*
* @param {number} code - Close code.
* @param {string} reason - Close reason.
*
* @returns {{
* type: DATA_CHANNEL_CLOSED,
* code: number,
* reason: string
* }}
*/
export function dataChannelClosed(code: number, reason: string) {
return {
type: DATA_CHANNEL_CLOSED,
code,
reason
};
}
/**
* Action to end a conference for all participants.
*

View File

@@ -19,7 +19,12 @@ type Props = {
/**
* The extra styles to be applied to links.
*/
linkStyle: StyleType
linkStyle: StyleType,
/**
* The extra styles to be applied to text.
*/
style?: StyleType
};
/**
@@ -46,7 +51,9 @@ export default class Linkify extends Component<Props> {
return (
<ReactLinkify
componentDecorator = { this._componentDecorator }>
<Text selectable = { true }>
<Text
selectable = { true }
style = { this.props.style }>
{ this.props.children }
</Text>
</ReactLinkify>

View File

@@ -67,7 +67,7 @@ const useStyles = makeStyles()(theme => {
flexDirection: 'column',
height: 'auto',
minHeight: '200px',
maxHeight: '560px',
maxHeight: '660px',
marginTop: '64px',
animation: `${keyframes`
0% {

View File

@@ -1,4 +1,4 @@
// @flow
/* eslint-disable react/no-multi-comp */
import { useIsFocused } from '@react-navigation/native';
import React, { useEffect } from 'react';
@@ -6,7 +6,8 @@ import React, { useEffect } from 'react';
import { translate } from '../../../base/i18n';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import { connect } from '../../../base/redux';
import { closeChat } from '../../actions.any';
import { TabBarLabelCounter } from '../../../mobile/navigation/components/TabBarLabelCounter';
import { closeChat } from '../../actions.native';
import AbstractChat, {
type Props as AbstractProps,
_mapStateToProps
@@ -17,14 +18,8 @@ import MessageContainer from './MessageContainer';
import MessageRecipient from './MessageRecipient';
import styles from './styles';
type Props = AbstractProps & {
/**
* Is this screen focused or not(React Navigation).
*/
isChatScreenFocused: boolean,
/**
* Default prop for navigating between screen components(React Navigation).
*/
@@ -41,7 +36,6 @@ type Props = AbstractProps & {
* the mobile client.
*/
class Chat extends AbstractChat<Props> {
/**
* Implements React's {@link Component#render()}.
*
@@ -49,7 +43,7 @@ class Chat extends AbstractChat<Props> {
*/
render() {
const { _messages, route } = this.props;
const privateMessageRecipient = route.params?.privateMessageRecipient;
const privateMessageRecipient = route?.params?.privateMessageRecipient;
return (
<JitsiScreen
@@ -68,28 +62,26 @@ class Chat extends AbstractChat<Props> {
}
export default translate(connect(_mapStateToProps)(props => {
const {
_nbUnreadMessages,
navigation,
t
} = props;
const isChatScreenFocused = useIsFocused();
const { _nbUnreadMessages, dispatch, navigation, t } = props;
const unreadMessagesNr = _nbUnreadMessages > 0;
const nrUnreadMessages
= !isChatScreenFocused && _nbUnreadMessages > 0
? `(${_nbUnreadMessages})` : '';
const isFocused = useIsFocused();
useEffect(() => {
navigation.setOptions({
tabBarLabel: `${t('chat.tabs.chat')} ${nrUnreadMessages}`
navigation?.setOptions({
tabBarLabel: () => (
<TabBarLabelCounter
activeUnreadNr = { unreadMessagesNr }
isFocused = { isFocused }
label = { t('chat.tabs.chat') }
nbUnread = { _nbUnreadMessages } />
)
});
return () => props.dispatch(closeChat());
}, [ nrUnreadMessages ]);
return () => isFocused && dispatch(closeChat());
}, [ isFocused, _nbUnreadMessages ]);
return (
<Chat
{ ...props }
isChatScreenFocused = { isChatScreenFocused } />
<Chat { ...props } />
);
}));

View File

@@ -1,5 +1,3 @@
// @flow
import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
import { translate } from '../../../base/i18n';
import { IconChatUnread, IconMessage } from '../../../base/icons';
@@ -10,9 +8,9 @@ import {
} from '../../../base/toolbox/components';
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { screen } from '../../../mobile/navigation/routes';
import { getUnreadPollCount } from '../../../polls/functions';
import { getUnreadCount } from '../../functions';
type Props = AbstractButtonProps & {
/**
@@ -72,7 +70,9 @@ function _mapStateToProps(state, ownProps) {
return {
_isPollsDisabled: disablePolls,
_unreadMessageCount: getUnreadCount(state),
// The toggled icon should also be available for new polls
_unreadMessageCount: getUnreadCount(state) || getUnreadPollCount(state),
visible
};
}

View File

@@ -1,30 +1,19 @@
// @flow
import React from 'react';
import { Text, View } from 'react-native';
import { Avatar } from '../../../base/avatar';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { translate } from '../../../base/i18n';
import { Linkify } from '../../../base/react';
import { connect } from '../../../base/redux';
import { type StyleType } from '../../../base/styles';
import { isGifMessage } from '../../../gifs/functions';
import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../../constants';
import { replaceNonUnicodeEmojis } from '../../functions';
import AbstractChatMessage, { type Props as AbstractProps } from '../AbstractChatMessage';
import AbstractChatMessage, { type Props } from '../AbstractChatMessage';
import GifMessage from './GifMessage';
import PrivateMessageButton from './PrivateMessageButton';
import styles from './styles';
type Props = AbstractProps & {
/**
* The color-schemed stylesheet of the feature.
*/
_styles: StyleType
};
/**
* Renders a single chat message.
@@ -36,7 +25,7 @@ class ChatMessage extends AbstractChatMessage<Props> {
* @inheritdoc
*/
render() {
const { _styles, message, knocking } = this.props;
const { message, knocking } = this.props;
const localMessage = message.messageType === MESSAGE_TYPE_LOCAL;
const { privateMessage, lobbyChat } = message;
@@ -56,7 +45,7 @@ class ChatMessage extends AbstractChatMessage<Props> {
detailsWrapperStyle.push(styles.ownMessageDetailsWrapper);
// The bubble needs some additional styling
messageBubbleStyle.push(_styles.localMessageBubble);
messageBubbleStyle.push(styles.localMessageBubble);
} else if (message.messageType === MESSAGE_TYPE_ERROR) {
// This is a system message.
@@ -66,15 +55,15 @@ class ChatMessage extends AbstractChatMessage<Props> {
// This is a remote message sent by a remote participant.
// The bubble needs some additional styling
messageBubbleStyle.push(_styles.remoteMessageBubble);
messageBubbleStyle.push(styles.remoteMessageBubble);
}
if (privateMessage) {
messageBubbleStyle.push(_styles.privateMessageBubble);
messageBubbleStyle.push(styles.privateMessageBubble);
}
if (lobbyChat && !knocking) {
messageBubbleStyle.push(_styles.lobbyMessageBubble);
messageBubbleStyle.push(styles.lobbyMessageBubble);
}
const messageText = replaceNonUnicodeEmojis(this._getMessageText());
@@ -86,11 +75,13 @@ class ChatMessage extends AbstractChatMessage<Props> {
<View style = { messageBubbleStyle }>
<View style = { styles.textWrapper } >
{ this._renderDisplayName() }
{isGifMessage(messageText)
{ isGifMessage(messageText)
? <GifMessage message = { messageText } />
: (
<Linkify linkStyle = { styles.chatLink }>
{messageText}
<Linkify
linkStyle = { styles.chatLink }
style = { styles.chatMessage }>
{ messageText }
</Linkify>
)}
{ this._renderPrivateNotice() }
@@ -134,14 +125,14 @@ class ChatMessage extends AbstractChatMessage<Props> {
* @returns {React$Element<*> | null}
*/
_renderDisplayName() {
const { _styles, message, showDisplayName } = this.props;
const { message, showDisplayName } = this.props;
if (!showDisplayName) {
return null;
}
return (
<Text style = { _styles.displayName }>
<Text style = { styles.senderDisplayName }>
{ message.displayName }
</Text>
);
@@ -153,14 +144,14 @@ class ChatMessage extends AbstractChatMessage<Props> {
* @returns {React$Element<*> | null}
*/
_renderPrivateNotice() {
const { _styles, message, knocking } = this.props;
const { message, knocking } = this.props;
if (!(message.privateMessage || (message.lobbyChat && !knocking))) {
return null;
}
return (
<Text style = { message.lobbyChat ? _styles.lobbyMsgNotice : _styles.privateNotice }>
<Text style = { message.lobbyChat ? styles.lobbyMsgNotice : styles.privateNotice }>
{ this._getPrivateNoticeMessage() }
</Text>
);
@@ -172,7 +163,7 @@ class ChatMessage extends AbstractChatMessage<Props> {
* @returns {React$Element<*> | null}
*/
_renderPrivateReplyButton() {
const { _styles, message, knocking } = this.props;
const { message, knocking } = this.props;
const { messageType, privateMessage, lobbyChat } = message;
if (!(privateMessage || lobbyChat) || messageType === MESSAGE_TYPE_LOCAL || knocking) {
@@ -180,13 +171,13 @@ class ChatMessage extends AbstractChatMessage<Props> {
}
return (
<View style = { _styles.replyContainer }>
<View style = { styles.replyContainer }>
<PrivateMessageButton
isLobbyMessage = { lobbyChat }
participantID = { message.id }
reply = { true }
showLabel = { false }
toggledStyles = { _styles.replyStyles } />
toggledStyles = { styles.replyStyles } />
</View>
);
}
@@ -217,7 +208,6 @@ class ChatMessage extends AbstractChatMessage<Props> {
*/
function _mapStateToProps(state) {
return {
_styles: ColorSchemeRegistry.get(state, 'Chat'),
knocking: state['features/lobby'].knocking
};
}

View File

@@ -1,6 +1,4 @@
// @flow
import React, { Component } from 'react';
import React, { Component, ReactElement } from 'react';
import { FlatList } from 'react-native';
import { MESSAGE_TYPE_LOCAL, MESSAGE_TYPE_REMOTE } from '../../constants';
@@ -60,7 +58,7 @@ export default class ChatMessageGroup extends Component<Props> {
return `key_${index}`;
}
_renderMessage: Object => React$Element<*>;
_renderMessage: Object => ReactElement;
/**
* Renders a single chat message.

View File

@@ -1,5 +1,3 @@
// @flow
import React from 'react';
import { ConfirmDialog } from '../../../base/dialog';

View File

@@ -1,12 +1,8 @@
// @flow
import React from 'react';
import React, { ReactElement } from 'react';
import { FlatList, Text, View } from 'react-native';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { translate } from '../../../base/i18n';
import { connect } from '../../../base/redux';
import { StyleType } from '../../../base/styles';
import AbstractMessageContainer, { type Props as AbstractProps }
from '../AbstractMessageContainer';
@@ -15,11 +11,6 @@ import styles from './styles';
type Props = AbstractProps & {
/**
* The color-schemed stylesheet of the feature.
*/
_styles: StyleType,
/**
* Function to be used to translate i18n labels.
*/
@@ -82,7 +73,7 @@ class MessageContainer extends AbstractMessageContainer<Props> {
return `key_${index}`;
}
_renderListEmptyComponent: () => React$Element<any>;
_renderListEmptyComponent: () => ReactElement;
/**
* Renders a message when there are no messages in the chat yet.
@@ -90,18 +81,18 @@ class MessageContainer extends AbstractMessageContainer<Props> {
* @returns {React$Element<any>}
*/
_renderListEmptyComponent() {
const { _styles, t } = this.props;
const { t } = this.props;
return (
<View style = { styles.emptyComponentWrapper }>
<Text style = { _styles.emptyComponentText }>
<Text style = { styles.emptyComponentText }>
{ t('chat.noMessagesMessage') }
</Text>
</View>
);
}
_renderMessageGroup: Object => React$Element<any>;
_renderMessageGroup: Object => ReactElement;
/**
* Renders a single chat message.
@@ -114,16 +105,4 @@ class MessageContainer extends AbstractMessageContainer<Props> {
}
}
/**
* Maps part of the redux state to the props of this component.
*
* @param {Object} state - The Redux state.
* @returns {Props}
*/
function _mapStateToProps(state) {
return {
_styles: ColorSchemeRegistry.get(state, 'Chat')
};
}
export default translate(connect(_mapStateToProps)(MessageContainer));
export default translate(connect()(MessageContainer));

View File

@@ -1,13 +1,9 @@
// @flow
import React from 'react';
import { Text, TouchableHighlight, View } from 'react-native';
import { ColorSchemeRegistry } from '../../../base/color-scheme';
import { translate } from '../../../base/i18n';
import { Icon, IconCloseCircle } from '../../../base/icons';
import { Icon, IconCloseLarge } from '../../../base/icons';
import { connect } from '../../../base/redux';
import { type StyleType } from '../../../base/styles';
import {
setParams
} from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
@@ -16,14 +12,11 @@ import AbstractMessageRecipient, {
type Props as AbstractProps
} from '../AbstractMessageRecipient';
import styles from './styles';
type Props = AbstractProps & {
/**
* The color-schemed stylesheet of the feature.
*/
_styles: StyleType,
/**
* The Redux dispatch function.
*/
@@ -99,14 +92,17 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
* @returns {ReactElement}
*/
render() {
const { _styles, privateMessageRecipient, t,
isLobbyChatActive, lobbyMessageRecipient } = this.props;
const {
isLobbyChatActive,
lobbyMessageRecipient,
privateMessageRecipient,
t
} = this.props;
if (isLobbyChatActive) {
return (
<View style = { _styles.lobbyMessageRecipientContainer }>
<Text style = { _styles.messageRecipientText }>
<View style = { styles.lobbyMessageRecipientContainer }>
<Text style = { styles.messageRecipientText }>
{ t('chat.lobbyChatMessageTo', {
recipient: lobbyMessageRecipient.name
}) }
@@ -114,8 +110,8 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
<TouchableHighlight
onPress = { this._onResetLobbyMessageRecipient }>
<Icon
src = { IconCloseCircle }
style = { _styles.messageRecipientCancelIcon } />
src = { IconCloseLarge }
style = { styles.messageRecipientCancelIcon } />
</TouchableHighlight>
</View>
);
@@ -126,8 +122,8 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
}
return (
<View style = { _styles.messageRecipientContainer }>
<Text style = { _styles.messageRecipientText }>
<View style = { styles.messageRecipientContainer }>
<Text style = { styles.messageRecipientText }>
{ t('chat.messageTo', {
recipient: privateMessageRecipient.name
}) }
@@ -136,8 +132,8 @@ class MessageRecipient extends AbstractMessageRecipient<Props> {
onPress = { this._onResetPrivateMessageRecipient }
underlayColor = { 'transparent' }>
<Icon
src = { IconCloseCircle }
style = { _styles.messageRecipientCancelIcon } />
src = { IconCloseLarge }
style = { styles.messageRecipientCancelIcon } />
</TouchableHighlight>
</View>
);
@@ -154,7 +150,6 @@ function _mapStateToProps(state) {
const { lobbyMessageRecipient, isLobbyChatActive } = state['features/chat'];
return {
_styles: ColorSchemeRegistry.get(state, 'Chat'),
isLobbyChatActive,
lobbyMessageRecipient
};

View File

@@ -1,5 +1,3 @@
// @flow
import { CHAT_ENABLED, getFeatureFlag } from '../../../base/flags';
import { translate } from '../../../base/i18n';
import { IconMessage, IconReply } from '../../../base/icons';
@@ -10,7 +8,6 @@ import { handleLobbyChatInitialized, openChat } from '../../../chat/actions';
import { navigate } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { screen } from '../../../mobile/navigation/routes';
export type Props = AbstractButtonProps & {
/**
@@ -103,7 +100,7 @@ class PrivateMessageButton extends AbstractButton<Props, any> {
* @param {Props} ownProps - The own props of the component.
* @returns {Props}
*/
export function _mapStateToProps(state: Object, ownProps: Props): $Shape<Props> {
export function _mapStateToProps(state: Object, ownProps: Props) {
const enabled = getFeatureFlag(state, CHAT_ENABLED, true);
const { disablePolls } = state['features/base/config'];
const { visible = enabled, isLobbyMessage, participantID } = ownProps;

View File

@@ -1,11 +1,19 @@
// @flow
import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
import { BoxModel, ColorPalette } from '../../../base/styles';
import { BoxModel } from '../../../base/styles';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
const BUBBLE_RADIUS = 8;
const recipientContainer = {
alignItems: 'center',
backgroundColor: BaseTheme.palette.support05,
borderRadius: BaseTheme.shape.borderRadius,
flexDirection: 'row',
height: 48,
marginBottom: BaseTheme.spacing[3],
marginHorizontal: BaseTheme.spacing[3],
padding: BaseTheme.spacing[2]
};
/**
* The styles of the feature chat.
*
@@ -16,16 +24,72 @@ const BUBBLE_RADIUS = 8;
*/
export default {
/**
* Background of the chat screen.
*/
backdrop: {
backgroundColor: BaseTheme.palette.ui10,
flex: 1
},
emptyComponentText: {
color: BaseTheme.palette.text03,
textAlign: 'center'
},
lobbyMessageBubble: {
backgroundColor: BaseTheme.palette.support06
},
lobbyMsgNotice: {
color: BaseTheme.palette.text04,
fontSize: 11,
marginTop: 6
},
privateNotice: {
...BaseTheme.palette.bodyShortRegular,
color: BaseTheme.palette.text02
},
privateMessageBubble: {
backgroundColor: BaseTheme.palette.support05
},
remoteMessageBubble: {
backgroundColor: BaseTheme.palette.ui02,
borderTopLeftRadius: 0
},
replyContainer: {
alignSelf: 'stretch',
justifyContent: 'center'
},
replyStyles: {
iconStyle: {
color: BaseTheme.palette.icon01,
fontSize: 22,
padding: BaseTheme.spacing[2]
},
underlayColor: 'transparent'
},
/**
* Wrapper View for the avatar.
*/
avatarWrapper: {
marginRight: 8,
marginRight: BaseTheme.spacing[2],
width: 32
},
chatLink: {
color: ColorPalette.blue
color: BaseTheme.palette.link01
},
chatMessage: {
...BaseTheme.typography.bodyShortRegular,
color: BaseTheme.palette.text01
},
/**
@@ -61,7 +125,7 @@ export default {
},
customInput: {
width: 280
width: 272
},
messageBubble: {
@@ -117,7 +181,7 @@ export default {
* Text node for the timestamp.
*/
timeText: {
color: 'rgb(164, 184, 209)',
color: BaseTheme.palette.text03,
fontSize: 13
},
@@ -154,97 +218,35 @@ export default {
width: 250,
height: undefined,
flexGrow: 1
}
};
ColorSchemeRegistry.register('Chat', {
/**
* Background of the chat screen.
*/
backdrop: {
backgroundColor: schemeColor('background'),
flex: 1
},
/**
* The text node for the display name.
*/
displayName: {
color: schemeColor('displayName'),
fontSize: 13
},
emptyComponentText: {
color: BaseTheme.palette.text03,
textAlign: 'center'
},
lobbyMessageBubble: {
backgroundColor: schemeColor('lobbyMsgBackground')
},
lobbyMsgNotice: {
color: schemeColor('lobbyMsgNotice'),
fontSize: 11,
marginTop: 6
},
lobbyMessageRecipientContainer: {
alignItems: 'center',
backgroundColor: schemeColor('lobbyMsgBackground'),
flexDirection: 'row',
padding: BoxModel.padding
senderDisplayName: {
...BaseTheme.typography.bodyShortBold,
color: BaseTheme.palette.text02
},
localMessageBubble: {
backgroundColor: schemeColor('localMsgBackground'),
backgroundColor: BaseTheme.palette.ui04,
borderTopRightRadius: 0
},
lobbyMessageRecipientContainer: {
...recipientContainer,
backgroundColor: BaseTheme.palette.support06
},
messageRecipientCancelIcon: {
color: schemeColor('icon'),
color: BaseTheme.palette.icon01,
fontSize: 18
},
messageRecipientContainer: {
alignItems: 'center',
backgroundColor: schemeColor('privateMsgBackground'),
flexDirection: 'row',
padding: BoxModel.padding
...recipientContainer
},
messageRecipientText: {
color: schemeColor('text'),
...BaseTheme.typography.bodyShortRegular,
color: BaseTheme.palette.text01,
flex: 1
},
privateNotice: {
color: schemeColor('privateMsgNotice'),
fontSize: 11,
marginTop: 6
},
privateMessageBubble: {
backgroundColor: schemeColor('privateMsgBackground')
},
remoteMessageBubble: {
backgroundColor: schemeColor('remoteMsgBackground'),
borderTopLeftRadius: 0
},
replyContainer: {
alignSelf: 'stretch',
borderLeftColor: schemeColor('replyBorder'),
borderLeftWidth: 1,
justifyContent: 'center'
},
replyStyles: {
iconStyle: {
color: schemeColor('replyIcon'),
fontSize: 22,
padding: 8
}
}
});
};

View File

@@ -1,5 +1,3 @@
// @flow
import clsx from 'clsx';
import React from 'react';

View File

@@ -71,8 +71,7 @@ export default {
},
qualityLabelContainer: {
borderBottomLeftRadius: 3,
borderTopLeftRadius: 3,
borderRadius: BaseTheme.shape.borderRadius,
flexShrink: 1,
paddingHorizontal: 2,
justifyContent: 'center',

View File

@@ -3,6 +3,7 @@ import { getJitsiMeetTransport } from '../../../modules/transport';
import {
CONFERENCE_FAILED,
CONFERENCE_JOINED,
DATA_CHANNEL_CLOSED,
DATA_CHANNEL_OPENED,
KICKED_OUT
} from '../base/conference/actionTypes';
@@ -124,6 +125,10 @@ MiddlewareRegistry.register(store => next => action => {
break;
}
case DATA_CHANNEL_CLOSED:
APP.API.notifyDataChannelClosed(action.code, action.reason);
break;
case DATA_CHANNEL_OPENED:
APP.API.notifyDataChannelOpened();
break;

View File

@@ -1,5 +1,3 @@
// @flow
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import { SMALL_THUMBNAIL_SIZE } from '../../constants';
@@ -10,7 +8,7 @@ export const AVATAR_SIZE = 50;
const indicatorContainer = {
backgroundColor: 'rgba(0, 0, 0, 0.7)',
borderRadius: 4,
borderRadius: BaseTheme.shape.borderRadius,
margin: 2,
padding: 2
};
@@ -119,7 +117,16 @@ export default {
width: SMALL_THUMBNAIL_SIZE
},
indicatorContainer,
indicatorContainer: {
...indicatorContainer,
flexShrink: 1,
height: 32,
justifyContent: 'center',
marginBottom: BaseTheme.spacing[0],
marginHorizontal: BaseTheme.spacing[1],
marginTop: BaseTheme.spacing[2],
width: 32
},
/**
* The thumbnails indicator container.

View File

@@ -198,6 +198,11 @@ export interface IProps {
*/
_raisedHand: boolean;
/**
* Whether or not to display a tint background over tile.
*/
_shouldDisplayTintBackground: boolean;
/**
* Whether or not the current layout is stage filmstrip layout.
*/
@@ -360,6 +365,15 @@ const defaultStyles = (theme: Theme) => {
objectFit: 'contain',
flexGrow: '1'
}
},
tintBackground: {
position: 'absolute' as const,
zIndex: 1,
width: '100%',
height: '100%',
backgroundColor: `${theme.palette.uiBackground}`,
opacity: 0.8
}
};
};
@@ -965,6 +979,7 @@ class Thumbnail extends Component<IProps, IState> {
_isTestModeEnabled,
_localFlipX,
_participant,
_shouldDisplayTintBackground,
_thumbnailType,
_videoTrack,
classes,
@@ -1043,6 +1058,7 @@ class Thumbnail extends Component<IProps, IState> {
showPopover = { this._showPopover }
thumbnailType = { _thumbnailType } />
</div>
{_shouldDisplayTintBackground && <div className = { classes.tintBackground } />}
<div
className = { clsx(classes.indicatorsContainer,
classes.indicatorsBottomContainer,
@@ -1090,7 +1106,12 @@ class Thumbnail extends Component<IProps, IState> {
* @returns {ReactElement}
*/
render() {
const { _participant, _isTestModeEnabled, _isVirtualScreenshareParticipant } = this.props;
const {
_isTestModeEnabled,
_isVirtualScreenshareParticipant,
_participant,
_shouldDisplayTintBackground
} = this.props;
const videoEventListeners: any = {};
if (!_participant) {
@@ -1136,6 +1157,7 @@ class Thumbnail extends Component<IProps, IState> {
onTouchMove = { this._onTouchMove }
onTouchStart = { this._onTouchStart }
participantId = { _participant.id }
shouldDisplayTintBackground = { _shouldDisplayTintBackground }
styles = { this._getStyles() }
thumbnailType = { _thumbnailType }
videoTrack = { _videoTrack } />
@@ -1264,6 +1286,11 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
const { gifUrl: gifSrc } = getGifForParticipant(state, id ?? '');
const mode = getGifDisplayMode(state);
const participantId = isLocal ? getLocalParticipant(state)?.id : participantID;
const isActiveParticipant = activeParticipants.find((pId: string) => pId === participantId);
const participantCurrentlyOnLargeVideo = state['features/large-video']?.participantId === id;
const shouldDisplayTintBackground
= _currentLayout !== LAYOUTS.TILE_VIEW && filmstripType === FILMSTRIP_TYPE.MAIN
&& (isActiveParticipant || participantCurrentlyOnLargeVideo);
return {
_audioTrack,
@@ -1271,10 +1298,10 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
_defaultLocalDisplayName: defaultLocalDisplayName,
_disableLocalVideoFlip: Boolean(disableLocalVideoFlip),
_disableTileEnlargement: Boolean(disableTileEnlargement),
_isActiveParticipant: activeParticipants.find((pId: string) => pId === participantId),
_isActiveParticipant: isActiveParticipant,
_isHidden: isLocal && iAmRecorder && !iAmSipGateway,
_isAudioOnly: Boolean(state['features/base/audio-only'].enabled),
_isCurrentlyOnLargeVideo: state['features/large-video']?.participantId === id,
_isCurrentlyOnLargeVideo: participantCurrentlyOnLargeVideo,
_isDominantSpeakerDisabled: interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR,
_isMobile,
_isMobilePortrait,
@@ -1287,6 +1314,7 @@ function _mapStateToProps(state: IReduxState, ownProps: any): Object {
_raisedHand: hasRaisedHand(participant),
_stageFilmstripLayout: isStageFilmstripAvailable(state),
_stageParticipantsVisible: _currentLayout === LAYOUTS.STAGE_FILMSTRIP_VIEW,
_shouldDisplayTintBackground: shouldDisplayTintBackground,
_thumbnailType: tileType,
_videoObjectPosition: getVideoObjectPosition(state, participant?.id),
_videoTrack,

View File

@@ -77,6 +77,11 @@ type Props = {
*/
participantId: string,
/**
* Whether or not to display a tint background over tile.
*/
shouldDisplayTintBackground: boolean,
/**
* An object with the styles for thumbnail.
*/
@@ -107,6 +112,7 @@ const VirtualScreenshareParticipant = ({
onTouchMove,
onTouchStart,
participantId,
shouldDisplayTintBackground,
styles,
videoTrack,
thumbnailType
@@ -150,6 +156,7 @@ const VirtualScreenshareParticipant = ({
participantId = { participantId }
thumbnailType = { thumbnailType } />
</div>
{shouldDisplayTintBackground && <div className = { classes.tintBackground } />}
<div
className = { clsx(classes.indicatorsContainer,
classes.indicatorsBottomContainer,

View File

@@ -0,0 +1,41 @@
// @ts-ignore
import React from 'react';
import { StyleProp, Text, TextStyle, View } from 'react-native';
// @ts-ignore
import { navigationStyles } from './styles';
interface ITabBarLabelCounterProps {
activeUnreadNr: boolean;
isFocused: boolean;
label: string;
nbUnread?: number;
}
export const TabBarLabelCounter = ({ activeUnreadNr, isFocused, label, nbUnread }: ITabBarLabelCounterProps) => {
const labelStyles = isFocused
? navigationStyles.unreadCounterDescriptionFocused
: navigationStyles.unreadCounterDescription;
return (
<View
style = {
navigationStyles.unreadCounterContainer as StyleProp<TextStyle> }>
<Text
style = { labelStyles }>
{ label && label }
</Text>
{
activeUnreadNr && (
<View
style = { navigationStyles.unreadCounterCircle as StyleProp<TextStyle> }>
<Text
style = { navigationStyles.unreadCounter as StyleProp<TextStyle> }>
{ nbUnread }
</Text>
</View>
)
}
</View>
);
};

View File

@@ -1,9 +1,11 @@
/* eslint-disable lines-around-comment */
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
// @ts-ignore
import React from 'react';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';
import { IReduxState } from '../../../../../app/types';
import {
getClientHeight,
getClientWidth
@@ -11,6 +13,8 @@ import {
} from '../../../../../base/modal/components/functions';
// @ts-ignore
import { Chat } from '../../../../../chat';
import { setIsPollsTabFocused } from '../../../../../chat/actions.native';
import { resetNbUnreadPollsMessages } from '../../../../../polls/actions';
// @ts-ignore
import { PollsPane } from '../../../../../polls/components';
// @ts-ignore
@@ -23,6 +27,11 @@ const ChatTab = createMaterialTopTabNavigator();
const ChatAndPolls = () => {
const clientHeight = useSelector(getClientHeight);
const clientWidth = useSelector(getClientWidth);
const dispatch = useDispatch();
const { isPollsTabFocused } = useSelector((state: IReduxState) => state['features/chat']);
const initialRouteName = isPollsTabFocused
? screen.conference.chatandpolls.tab.polls
: screen.conference.chatandpolls.tab.chat;
return (
// @ts-ignore
@@ -32,12 +41,24 @@ const ChatAndPolls = () => {
height: clientHeight,
width: clientWidth
}}
initialRouteName = { initialRouteName }
screenOptions = { chatTabBarOptions }>
<ChatTab.Screen
component = { Chat }
listeners = {{
tabPress: () => {
dispatch(setIsPollsTabFocused(false));
}
}}
name = { screen.conference.chatandpolls.tab.chat } />
<ChatTab.Screen
component = { PollsPane }
listeners = {{
tabPress: () => {
dispatch(setIsPollsTabFocused(true));
dispatch(resetNbUnreadPollsMessages);
}
}}
name = { screen.conference.chatandpolls.tab.polls } />
</ChatTab.Navigator>
);

View File

@@ -1,9 +1,14 @@
import { BoxModel } from '../../../base/styles';
import BaseTheme from '../../../base/ui/components/BaseTheme';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
export const TEXT_COLOR = BaseTheme.palette.text01;
const unreadCounterDescription = {
...BaseTheme.typography.bodyShortBoldLarge,
color: BaseTheme.palette.text03
};
/**
* Styles of the navigation feature.
*/
@@ -27,5 +32,35 @@ export const navigationStyles = {
connectingScreenText: {
color: TEXT_COLOR
},
unreadCounterContainer: {
alignItems: 'center',
display: 'flex',
flexDirection: 'row'
},
unreadCounterDescription: {
...unreadCounterDescription
},
unreadCounterDescriptionFocused: {
...unreadCounterDescription,
color: BaseTheme.palette.text01
},
unreadCounterCircle: {
backgroundColor: BaseTheme.palette.warning01,
borderRadius: BaseTheme.spacing[4] / 2,
height: BaseTheme.spacing[4],
justifyContent: 'center',
marginLeft: BaseTheme.spacing[2],
width: BaseTheme.spacing[4]
},
unreadCounter: {
...BaseTheme.typography.bodyShortBold,
alignSelf: 'center',
color: BaseTheme.palette.text04
}
};

View File

@@ -67,19 +67,14 @@ export const conferenceScreenOptions = fullScreenOptions;
* Tab bar options for chat screen.
*/
export const chatTabBarOptions = {
tabBarActiveTintColor: BaseTheme.palette.field02,
tabBarLabelStyle: {
fontSize: BaseTheme.typography.labelRegular.fontSize,
textTransform: 'capitalize'
},
tabBarInactiveTintColor: BaseTheme.palette.text03,
swipeEnabled: false,
tabBarIndicatorStyle: {
backgroundColor: BaseTheme.palette.field02
backgroundColor: BaseTheme.palette.link01Active
},
tabBarStyle: {
backgroundColor: BaseTheme.palette.ui01,
borderBottomColor: BaseTheme.palette.border05,
borderBottomWidth: 1
borderBottomWidth: 0.4
}
};

View File

@@ -56,6 +56,13 @@ export const NOTIFICATION_ICON = {
PARTICIPANTS: 'participants'
};
/**
* The identifier of the disable self view notification.
*
* @type {string}
*/
export const DATA_CHANNEL_CLOSED_NOTIFICATION_ID = 'DATA_CHANNEL_CLOSED_NOTIFICATION_ID';
/**
* The identifier of the disable self view notification.
*

View File

@@ -4,7 +4,7 @@ import { FlatList, View } from 'react-native';
import { Text } from 'react-native-paper';
import { useSelector } from 'react-redux';
import { Icon, IconChatUnread } from '../../../base/icons';
import { Icon, IconMessage } from '../../../base/icons';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
@@ -41,7 +41,7 @@ const PollsList = () => {
<Icon
color = { BaseTheme.palette.icon03 }
size = { 160 }
src = { IconChatUnread } />
src = { IconMessage } />
<Text style = { chatStyles.noPollText } >
{
t('polls.results.empty')

View File

@@ -1,14 +1,14 @@
/* eslint-disable react-native/no-color-literals */
// @flow
import { useIsFocused, useNavigation } from '@react-navigation/native';
import { useNavigation } from '@react-navigation/native';
import React, { useEffect } from 'react';
import { useSelector } from 'react-redux';
import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import Button from '../../../base/ui/components/native/Button';
import { BUTTON_TYPES } from '../../../base/ui/constants.native';
import { getUnreadPollCount } from '../../functions';
import { TabBarLabelCounter }
from '../../../mobile/navigation/components/TabBarLabelCounter';
import AbstractPollsPane from '../AbstractPollsPane';
import type { AbstractProps } from '../AbstractPollsPane';
@@ -19,19 +19,25 @@ import { chatStyles } from './styles';
const PollsPane = (props: AbstractProps) => {
const { createMode, onCreate, setCreateMode, t } = props;
const isPollsScreenFocused = useIsFocused();
const navigation = useNavigation();
const nbUnreadPolls = useSelector(getUnreadPollCount);
const nrUnreadPolls = !isPollsScreenFocused && nbUnreadPolls > 0
? `(${nbUnreadPolls})`
: '';
const { isPollsTabFocused } = useSelector(state => state['features/chat']);
const { nbUnreadPolls } = useSelector(state => state['features/polls']);
useEffect(() => {
const activeUnreadPollsNr = !isPollsTabFocused && nbUnreadPolls > 0;
navigation.setOptions({
tabBarLabel: `${t('chat.tabs.polls')} ${nrUnreadPolls}`
// eslint-disable-next-line react/no-multi-comp
tabBarLabel: () => (
<TabBarLabelCounter
activeUnreadNr = { activeUnreadPollsNr }
isFocused = { isPollsTabFocused }
label = { t('chat.tabs.polls') }
nbUnread = { nbUnreadPolls } />
)
});
}, [ nrUnreadPolls ]);
}, [ isPollsTabFocused, nbUnreadPolls ]);
return (
<JitsiScreen

View File

@@ -110,10 +110,12 @@ export const chatStyles = createStyleSheet({
noPollContent: {
alignItems: 'center',
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
paddingTop: '4%'
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
top: '25%'
},
noPollText: {
@@ -149,7 +151,7 @@ export const chatStyles = createStyleSheet({
pollCreateButton: {
flex: 1,
marginHorizontal: BaseTheme.spacing[2]
marginHorizontal: BaseTheme.spacing[1]
},
pollSendLabel: {
@@ -191,7 +193,8 @@ export const chatStyles = createStyleSheet({
},
pollCreateAddButton: {
margin: BaseTheme.spacing[2]
marginHorizontal: BaseTheme.spacing[1],
marginVertical: BaseTheme.spacing[2]
},
toggleText: {
@@ -200,8 +203,8 @@ export const chatStyles = createStyleSheet({
},
createPollButton: {
marginHorizontal: BaseTheme.spacing[4],
marginVertical: '8%'
marginHorizontal: BaseTheme.spacing[3],
marginVertical: 34
},
pollPane: {
@@ -218,5 +221,28 @@ export const chatStyles = createStyleSheet({
flexDirection: 'row',
justifyContent: 'space-between',
marginHorizontal: BaseTheme.spacing[2]
},
unreadPollsCounterContainer: {
display: 'flex',
flexDirection: 'row'
},
unreadPollsCounterDescription: {
color: BaseTheme.palette.text01
},
unreadPollsCounterCircle: {
backgroundColor: BaseTheme.palette.warning01,
borderRadius: BaseTheme.spacing[3] / 2,
height: BaseTheme.spacing[3],
justifyContent: 'center',
marginLeft: BaseTheme.spacing[2],
width: BaseTheme.spacing[3]
},
unreadPollsCounter: {
alignSelf: 'center',
color: BaseTheme.palette.text04
}
});

View File

@@ -1,4 +1,5 @@
/* eslint-disable lines-around-comment */
// @ts-ignore
import React from 'react';
import Button from '../../../base/ui/components/web/Button';

View File

@@ -1,6 +1,5 @@
// @flow
import { ColorPalette, createStyleSheet } from '../../base/styles';
import BaseTheme from '../../base/ui/components/BaseTheme.native';
export const AUD_LABEL_COLOR = ColorPalette.green;
@@ -13,6 +12,8 @@ export default createStyleSheet({
* Style for the audio-only indicator.
*/
indicatorAudioOnly: {
backgroundColor: AUD_LABEL_COLOR
backgroundColor: AUD_LABEL_COLOR,
borderRadius: BaseTheme.shape.borderRadius,
height: 32
}
});