Refactor carmnode
- open as a modal - add long press to talk - add long press analytics - video mute keeps the previous state after carmode closes - and more
This commit is contained in:
parent
ac965b86bc
commit
698ab32a62
|
@ -83,6 +83,7 @@
|
||||||
"selectSoundDevice": "Select sound device"
|
"selectSoundDevice": "Select sound device"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
|
"buttonLabel": "Car mode",
|
||||||
"title": "Safe driving mode",
|
"title": "Safe driving mode",
|
||||||
"videoStopped": "Your video is stopped"
|
"videoStopped": "Your video is stopped"
|
||||||
}
|
}
|
||||||
|
@ -1050,6 +1051,7 @@
|
||||||
"muteEveryoneElse": "Mute everyone else",
|
"muteEveryoneElse": "Mute everyone else",
|
||||||
"muteEveryoneElsesVideoStream": "Stop everyone else's video",
|
"muteEveryoneElsesVideoStream": "Stop everyone else's video",
|
||||||
"muteEveryonesVideoStream": "Stop everyone's video",
|
"muteEveryonesVideoStream": "Stop everyone's video",
|
||||||
|
"carmode": "Carmode",
|
||||||
"participants": "Participants",
|
"participants": "Participants",
|
||||||
"pip": "Toggle Picture-in-Picture mode",
|
"pip": "Toggle Picture-in-Picture mode",
|
||||||
"privateMessage": "Send private message",
|
"privateMessage": "Send private message",
|
||||||
|
|
|
@ -641,18 +641,20 @@ export function createSharedVideoEvent(action, attributes = {}) {
|
||||||
* of ACTION_SHORTCUT_PRESSED, ACTION_SHORTCUT_RELEASED
|
* of ACTION_SHORTCUT_PRESSED, ACTION_SHORTCUT_RELEASED
|
||||||
* or ACTION_SHORTCUT_TRIGGERED).
|
* or ACTION_SHORTCUT_TRIGGERED).
|
||||||
* @param {Object} attributes - Attributes to attach to the event.
|
* @param {Object} attributes - Attributes to attach to the event.
|
||||||
|
* @param {string} source - The event's source.
|
||||||
* @returns {Object} The event in a format suitable for sending via
|
* @returns {Object} The event in a format suitable for sending via
|
||||||
* sendAnalytics.
|
* sendAnalytics.
|
||||||
*/
|
*/
|
||||||
export function createShortcutEvent(
|
export function createShortcutEvent(
|
||||||
shortcut,
|
shortcut,
|
||||||
action = ACTION_SHORTCUT_TRIGGERED,
|
action = ACTION_SHORTCUT_TRIGGERED,
|
||||||
attributes = {}) {
|
attributes = {},
|
||||||
|
source = 'keyboard.shortcut') {
|
||||||
return {
|
return {
|
||||||
action,
|
action,
|
||||||
actionSubjectId: shortcut,
|
actionSubjectId: shortcut,
|
||||||
attributes,
|
attributes,
|
||||||
source: 'keyboard.shortcut',
|
source,
|
||||||
type: TYPE_UI
|
type: TYPE_UI
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -901,7 +903,7 @@ export function createBreakoutRoomsEvent(actionSubject) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and event which indicates a GIF was sent.
|
* Creates an event which indicates a GIF was sent.
|
||||||
*
|
*
|
||||||
* @returns {Object} The event in a format suitable for sending via
|
* @returns {Object} The event in a format suitable for sending via
|
||||||
* sendAnalytics.
|
* sendAnalytics.
|
||||||
|
|
|
@ -166,7 +166,7 @@ export function setVideoAvailable(available: boolean) {
|
||||||
*/
|
*/
|
||||||
export function setVideoMuted(
|
export function setVideoMuted(
|
||||||
muted: boolean,
|
muted: boolean,
|
||||||
mediaType: MediaType = MEDIA_TYPE.VIDEO,
|
mediaType: string = MEDIA_TYPE.VIDEO,
|
||||||
authority: number = VIDEO_MUTISM_AUTHORITY.USER,
|
authority: number = VIDEO_MUTISM_AUTHORITY.USER,
|
||||||
ensureTrack: boolean = false) {
|
ensureTrack: boolean = false) {
|
||||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||||
|
|
|
@ -45,7 +45,8 @@ export const SCREENSHARE_MUTISM_AUTHORITY = {
|
||||||
export const VIDEO_MUTISM_AUTHORITY = {
|
export const VIDEO_MUTISM_AUTHORITY = {
|
||||||
AUDIO_ONLY: 1 << 0,
|
AUDIO_ONLY: 1 << 0,
|
||||||
BACKGROUND: 1 << 1,
|
BACKGROUND: 1 << 1,
|
||||||
USER: 1 << 2
|
USER: 1 << 2,
|
||||||
|
CAR_MODE: 1 << 3
|
||||||
};
|
};
|
||||||
|
|
||||||
/* eslint-enable no-bitwise */
|
/* eslint-enable no-bitwise */
|
||||||
|
|
|
@ -16,7 +16,6 @@ import { PollsPane } from '../../../polls/components';
|
||||||
|
|
||||||
const ChatTab = createMaterialTopTabNavigator();
|
const ChatTab = createMaterialTopTabNavigator();
|
||||||
|
|
||||||
|
|
||||||
const ChatAndPolls = () => {
|
const ChatAndPolls = () => {
|
||||||
const clientHeight = useSelector(getClientHeight);
|
const clientHeight = useSelector(getClientHeight);
|
||||||
const clientWidth = useSelector(getClientWidth);
|
const clientWidth = useSelector(getClientWidth);
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
import { TypedNavigator, useIsFocused } from '@react-navigation/native';
|
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
|
||||||
|
|
||||||
import { Chat, ChatAndPolls } from '../../../chat';
|
|
||||||
import { SharedDocument } from '../../../etherpad';
|
|
||||||
import { GifsMenu } from '../../../gifs/components';
|
|
||||||
import AddPeopleDialog
|
|
||||||
from '../../../invite/components/add-people-dialog/native/AddPeopleDialog';
|
|
||||||
import LobbyNavigationContainer
|
|
||||||
from '../../../mobile/navigation/components/lobby/components/LobbyNavigationContainer';
|
|
||||||
import { screen } from '../../../mobile/navigation/routes';
|
|
||||||
import {
|
|
||||||
chatScreenOptions,
|
|
||||||
conferenceScreenOptions,
|
|
||||||
gifsMenuOptions,
|
|
||||||
inviteScreenOptions,
|
|
||||||
liveStreamScreenOptions,
|
|
||||||
participantsScreenOptions,
|
|
||||||
recordingScreenOptions,
|
|
||||||
salesforceScreenOptions,
|
|
||||||
securityScreenOptions,
|
|
||||||
sharedDocumentScreenOptions,
|
|
||||||
speakerStatsScreenOptions
|
|
||||||
} from '../../../mobile/navigation/screenOptions';
|
|
||||||
import { ParticipantsPane } from '../../../participants-pane/components/native';
|
|
||||||
import { StartLiveStreamDialog } from '../../../recording';
|
|
||||||
import { StartRecordingDialog }
|
|
||||||
from '../../../recording/components/Recording/native';
|
|
||||||
import SalesforceLinkDialog
|
|
||||||
from '../../../salesforce/components/native/SalesforceLinkDialog';
|
|
||||||
import SecurityDialog
|
|
||||||
from '../../../security/components/security-dialog/native/SecurityDialog';
|
|
||||||
import SpeakerStats
|
|
||||||
from '../../../speaker-stats/components/native/SpeakerStats';
|
|
||||||
import { setIsCarmode } from '../../../video-layout/actions';
|
|
||||||
import { getDisablePolls } from '../../functions';
|
|
||||||
|
|
||||||
import Conference from './Conference';
|
|
||||||
|
|
||||||
const ConferenceStack : TypedNavigator = createStackNavigator();
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback on component focused.
|
|
||||||
* Passes the route name to the embedder.
|
|
||||||
*/
|
|
||||||
onFocused: Function
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main conference screen navigator.
|
|
||||||
*
|
|
||||||
* @param {Props} props - The React props passed to this component.
|
|
||||||
* @returns {JSX.Element} - The conference tab.
|
|
||||||
*/
|
|
||||||
const ConferenceTab = ({ onFocused }: Props) : JSX.Element => {
|
|
||||||
const isFocused = useIsFocused();
|
|
||||||
const dispatch = useDispatch();
|
|
||||||
const isPollsDisabled = useSelector(getDisablePolls);
|
|
||||||
let ChatScreen;
|
|
||||||
let chatScreenName;
|
|
||||||
let chatTitleString;
|
|
||||||
|
|
||||||
if (isPollsDisabled) {
|
|
||||||
ChatScreen = Chat;
|
|
||||||
chatScreenName = screen.conference.chat;
|
|
||||||
chatTitleString = 'chat.title';
|
|
||||||
} else {
|
|
||||||
ChatScreen = ChatAndPolls;
|
|
||||||
chatScreenName = screen.conference.chatandpolls.main;
|
|
||||||
chatTitleString = 'chat.titleWithPolls';
|
|
||||||
}
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isFocused) {
|
|
||||||
dispatch(setIsCarmode(false));
|
|
||||||
onFocused(screen.conference.container);
|
|
||||||
}
|
|
||||||
}, [ isFocused ]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConferenceStack.Navigator
|
|
||||||
initialRouteName = { screen.conference.main }
|
|
||||||
screenOptions = {{
|
|
||||||
presentation: 'modal'
|
|
||||||
}}>
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { Conference }
|
|
||||||
name = { screen.conference.main }
|
|
||||||
options = { conferenceScreenOptions } />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { ChatScreen }
|
|
||||||
name = { chatScreenName }
|
|
||||||
options = {{
|
|
||||||
...chatScreenOptions,
|
|
||||||
title: t(chatTitleString)
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { ParticipantsPane }
|
|
||||||
name = { screen.conference.participants }
|
|
||||||
options = {{
|
|
||||||
...participantsScreenOptions,
|
|
||||||
title: t('participantsPane.header')
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { SecurityDialog }
|
|
||||||
name = { screen.conference.security }
|
|
||||||
options = {{
|
|
||||||
...securityScreenOptions,
|
|
||||||
title: t('security.header')
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { StartRecordingDialog }
|
|
||||||
name = { screen.conference.recording }
|
|
||||||
options = {{
|
|
||||||
...recordingScreenOptions
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { StartLiveStreamDialog }
|
|
||||||
name = { screen.conference.liveStream }
|
|
||||||
options = {{
|
|
||||||
...liveStreamScreenOptions
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { SpeakerStats }
|
|
||||||
name = { screen.conference.speakerStats }
|
|
||||||
options = {{
|
|
||||||
...speakerStatsScreenOptions,
|
|
||||||
title: t('speakerStats.speakerStats')
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { SalesforceLinkDialog }
|
|
||||||
name = { screen.conference.salesforce }
|
|
||||||
options = {{
|
|
||||||
...salesforceScreenOptions,
|
|
||||||
title: t('notify.linkToSalesforce')
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { GifsMenu }
|
|
||||||
name = { screen.conference.gifsMenu }
|
|
||||||
options = {{
|
|
||||||
...gifsMenuOptions,
|
|
||||||
title: t('notify.gifsMenu')
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { LobbyNavigationContainer }
|
|
||||||
name = { screen.lobby.root }
|
|
||||||
options = {{
|
|
||||||
gestureEnabled: false,
|
|
||||||
headerShown: false
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { AddPeopleDialog }
|
|
||||||
name = { screen.conference.invite }
|
|
||||||
options = {{
|
|
||||||
...inviteScreenOptions,
|
|
||||||
title: t('addPeople.add')
|
|
||||||
}} />
|
|
||||||
<ConferenceStack.Screen
|
|
||||||
component = { SharedDocument }
|
|
||||||
name = { screen.conference.sharedDocument }
|
|
||||||
options = {{
|
|
||||||
...sharedDocumentScreenOptions,
|
|
||||||
title: t('documentSharing.title')
|
|
||||||
}} />
|
|
||||||
</ConferenceStack.Navigator>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ConferenceTab;
|
|
|
@ -1,13 +1,11 @@
|
||||||
import { useIsFocused } from '@react-navigation/native';
|
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Text, SafeAreaView, View } from 'react-native';
|
import { Text, SafeAreaView, View } from 'react-native';
|
||||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import { batch, useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import JitsiScreen from '../../../../base/modal/components/JitsiScreen';
|
||||||
|
|
||||||
import { setAudioOnly } from '../../../../base/audio-only';
|
import { LoadingIndicator, TintedView } from '../../../../base/react';
|
||||||
import { Container, LoadingIndicator, TintedView } from '../../../../base/react';
|
|
||||||
import { screen } from '../../../../mobile/navigation/routes';
|
|
||||||
import { setIsCarmode } from '../../../../video-layout/actions';
|
import { setIsCarmode } from '../../../../video-layout/actions';
|
||||||
import ConferenceTimer from '../../ConferenceTimer';
|
import ConferenceTimer from '../../ConferenceTimer';
|
||||||
import { isConnecting } from '../../functions';
|
import { isConnecting } from '../../functions';
|
||||||
|
@ -17,42 +15,34 @@ import MicrophoneButton from './MicrophoneButton';
|
||||||
import SoundDeviceButton from './SoundDeviceButton';
|
import SoundDeviceButton from './SoundDeviceButton';
|
||||||
import TitleBar from './TitleBar';
|
import TitleBar from './TitleBar';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import { isLocalVideoTrackDesktop } from '../../../../base/tracks';
|
||||||
type Props = {
|
import { setPictureInPictureDisabled } from '../../../../mobile/picture-in-picture/functions';
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback on component focused.
|
|
||||||
* Passes the route name to the embedder.
|
|
||||||
*/
|
|
||||||
onFocused: Function
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the carmode tab.
|
* Implements the carmode tab.
|
||||||
*
|
*
|
||||||
* @param { Props } - - The component's props.
|
|
||||||
* @returns { JSX.Element} - The carmode tab.
|
* @returns { JSX.Element} - The carmode tab.
|
||||||
*/
|
*/
|
||||||
const CarmodeTab = ({ onFocused }: Props): JSX.Element => {
|
const CarmodeTab = (): JSX.Element => {
|
||||||
const isFocused = useIsFocused();
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const connecting = useSelector(isConnecting);
|
const connecting = useSelector(isConnecting);
|
||||||
|
const isSharing = useSelector(isLocalVideoTrackDesktop);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isFocused) {
|
|
||||||
batch(() => {
|
|
||||||
dispatch(setAudioOnly(true));
|
|
||||||
dispatch(setIsCarmode(true));
|
dispatch(setIsCarmode(true));
|
||||||
});
|
setPictureInPictureDisabled(true);
|
||||||
|
|
||||||
onFocused(screen.car);
|
return () => {
|
||||||
|
dispatch(setIsCarmode(false));
|
||||||
|
if (!isSharing) {
|
||||||
|
setPictureInPictureDisabled(false);
|
||||||
}
|
}
|
||||||
}, [ isFocused ]);
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container style = { styles.conference }>
|
<JitsiScreen style = { styles.conference }>
|
||||||
{/*
|
{/*
|
||||||
* The activity/loading indicator goes above everything, except
|
* The activity/loading indicator goes above everything, except
|
||||||
* the toolbox/toolbars and the dialogs.
|
* the toolbox/toolbars and the dialogs.
|
||||||
|
@ -62,22 +52,21 @@ const CarmodeTab = ({ onFocused }: Props): JSX.Element => {
|
||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
</TintedView>
|
</TintedView>
|
||||||
}
|
}
|
||||||
<SafeAreaView
|
<View
|
||||||
pointerEvents = 'box-none'
|
pointerEvents = 'box-none'
|
||||||
style = { styles.titleBarSafeViewColor }>
|
style = { styles.titleBarSafeViewColor }>
|
||||||
<View style = { styles.titleView }>
|
|
||||||
<Text style = { styles.title }>
|
|
||||||
{t('carmode.labels.title')}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
<View
|
<View
|
||||||
style = { styles.titleBar }>
|
style = { styles.titleBar }>
|
||||||
<TitleBar />
|
<TitleBar />
|
||||||
</View>
|
</View>
|
||||||
<ConferenceTimer textStyle = { styles.roomTimer } />
|
<ConferenceTimer textStyle = { styles.roomTimer } />
|
||||||
</SafeAreaView>
|
</View>
|
||||||
|
<View
|
||||||
|
pointerEvents = 'box-none'
|
||||||
|
style = { styles.microphoneContainer }>
|
||||||
<MicrophoneButton />
|
<MicrophoneButton />
|
||||||
<SafeAreaView
|
</View>
|
||||||
|
<View
|
||||||
pointerEvents = 'box-none'
|
pointerEvents = 'box-none'
|
||||||
style = { styles.bottomContainer }>
|
style = { styles.bottomContainer }>
|
||||||
<Text style = { styles.videoStoppedLabel }>
|
<Text style = { styles.videoStoppedLabel }>
|
||||||
|
@ -85,8 +74,8 @@ const CarmodeTab = ({ onFocused }: Props): JSX.Element => {
|
||||||
</Text>
|
</Text>
|
||||||
<SoundDeviceButton />
|
<SoundDeviceButton />
|
||||||
<EndMeetingButton />
|
<EndMeetingButton />
|
||||||
</SafeAreaView>
|
</View>
|
||||||
</Container>
|
</JitsiScreen>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
import { useState } from 'react';
|
||||||
import { View, TouchableOpacity } from 'react-native';
|
import { View, TouchableOpacity } from 'react-native';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import {
|
||||||
|
createShortcutEvent,
|
||||||
|
sendAnalytics,
|
||||||
|
ACTION_SHORTCUT_PRESSED as PRESSED,
|
||||||
|
ACTION_SHORTCUT_RELEASED as RELEASED
|
||||||
|
} from '../../../../analytics';
|
||||||
|
|
||||||
import { getFeatureFlag, AUDIO_MUTE_BUTTON_ENABLED } from '../../../../base/flags';
|
import { getFeatureFlag, AUDIO_MUTE_BUTTON_ENABLED } from '../../../../base/flags';
|
||||||
import { Icon, IconMicrophone, IconMicrophoneEmptySlash } from '../../../../base/icons';
|
import { Icon, IconMicrophone, IconMicrophoneEmptySlash } from '../../../../base/icons';
|
||||||
|
@ -11,6 +18,8 @@ import { muteLocal } from '../../../../video-menu/actions';
|
||||||
|
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
|
||||||
|
const LONG_PRESS = 'long.press';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a round audio mute/unmute button of a custom size.
|
* Implements a round audio mute/unmute button of a custom size.
|
||||||
*
|
*
|
||||||
|
@ -21,18 +30,45 @@ const MicrophoneButton = () : JSX.Element => {
|
||||||
const audioMuted = useSelector(state => isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO));
|
const audioMuted = useSelector(state => isLocalTrackMuted(state['features/base/tracks'], MEDIA_TYPE.AUDIO));
|
||||||
const disabled = useSelector(isAudioMuteButtonDisabled);
|
const disabled = useSelector(isAudioMuteButtonDisabled);
|
||||||
const enabledFlag = useSelector(state => getFeatureFlag(state, AUDIO_MUTE_BUTTON_ENABLED, true));
|
const enabledFlag = useSelector(state => getFeatureFlag(state, AUDIO_MUTE_BUTTON_ENABLED, true));
|
||||||
|
const [ longPress, setLongPress ] = useState(false);
|
||||||
|
|
||||||
if (!enabledFlag) {
|
if (!enabledFlag) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleMute = useCallback(() => {
|
const onPressIn = useCallback(() => {
|
||||||
!disabled && dispatch(muteLocal(!audioMuted, MEDIA_TYPE.AUDIO));
|
!disabled && dispatch(muteLocal(!audioMuted, MEDIA_TYPE.AUDIO));
|
||||||
}, [ audioMuted, disabled ]);
|
}, [ audioMuted, disabled ]);
|
||||||
|
|
||||||
|
const onLongPress = useCallback(() => {
|
||||||
|
if ( !disabled && !audioMuted) {
|
||||||
|
sendAnalytics(createShortcutEvent(
|
||||||
|
'push.to.talk',
|
||||||
|
PRESSED,
|
||||||
|
{},
|
||||||
|
LONG_PRESS));
|
||||||
|
setLongPress(true);
|
||||||
|
}
|
||||||
|
}, [audioMuted, disabled, setLongPress]);
|
||||||
|
|
||||||
|
const onPressOut = useCallback(() => {
|
||||||
|
if (longPress) {
|
||||||
|
setLongPress(false);
|
||||||
|
sendAnalytics(createShortcutEvent(
|
||||||
|
'push.to.talk',
|
||||||
|
RELEASED,
|
||||||
|
{},
|
||||||
|
LONG_PRESS
|
||||||
|
));
|
||||||
|
dispatch(muteLocal(true, MEDIA_TYPE.AUDIO));
|
||||||
|
}
|
||||||
|
}, [longPress, setLongPress]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress = { toggleMute }>
|
onPressIn = { onPressIn }
|
||||||
|
onLongPress={ onLongPress }
|
||||||
|
onPressOut={ onPressOut } >
|
||||||
<View
|
<View
|
||||||
style = { [
|
style = { [
|
||||||
styles.microphoneStyles.container,
|
styles.microphoneStyles.container,
|
||||||
|
|
|
@ -4,8 +4,7 @@ import { Text, View } from 'react-native';
|
||||||
import { getConferenceName } from '../../../../base/conference/functions';
|
import { getConferenceName } from '../../../../base/conference/functions';
|
||||||
import { getFeatureFlag, MEETING_NAME_ENABLED } from '../../../../base/flags';
|
import { getFeatureFlag, MEETING_NAME_ENABLED } from '../../../../base/flags';
|
||||||
import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../../../../base/lib-jitsi-meet';
|
||||||
import { connect } from '../../../../base/redux';
|
import { connect } from '../../../../base/redux';;
|
||||||
import { PictureInPictureButton } from '../../../../mobile/picture-in-picture';
|
|
||||||
import { RecordingLabel } from '../../../../recording';
|
import { RecordingLabel } from '../../../../recording';
|
||||||
import { VideoQualityLabel } from '../../../../video-quality';
|
import { VideoQualityLabel } from '../../../../video-quality';
|
||||||
|
|
||||||
|
@ -40,9 +39,6 @@ const TitleBar = (props: Props) : JSX.Element => (<>
|
||||||
<View
|
<View
|
||||||
pointerEvents = 'box-none'
|
pointerEvents = 'box-none'
|
||||||
style = { styles.roomNameWrapper }>
|
style = { styles.roomNameWrapper }>
|
||||||
<View style = { styles.headerLabels }>
|
|
||||||
<PictureInPictureButton styles = { styles.pipButton } />
|
|
||||||
</View>
|
|
||||||
<View style = { styles.headerLabels }>
|
<View style = { styles.headerLabels }>
|
||||||
<VideoQualityLabel />
|
<VideoQualityLabel />
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -5,8 +5,6 @@ import BaseTheme from '../../../../base/ui/components/BaseTheme.native';
|
||||||
*/
|
*/
|
||||||
const MICROPHONE_SIZE = 180;
|
const MICROPHONE_SIZE = 180;
|
||||||
|
|
||||||
const TITLE_BAR_BUTTON_SIZE = 24;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base button style.
|
* Base button style.
|
||||||
*/
|
*/
|
||||||
|
@ -59,11 +57,9 @@ export default {
|
||||||
* {@code Conference} Style.
|
* {@code Conference} Style.
|
||||||
*/
|
*/
|
||||||
conference: {
|
conference: {
|
||||||
alignSelf: 'stretch',
|
|
||||||
backgroundColor: BaseTheme.palette.uiBackground,
|
backgroundColor: BaseTheme.palette.uiBackground,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center'
|
||||||
alignItems: 'center'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
microphoneStyles: {
|
microphoneStyles: {
|
||||||
|
@ -100,14 +96,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
pipButton: {
|
|
||||||
iconStyle: {
|
|
||||||
color: BaseTheme.palette.icon01,
|
|
||||||
fontSize: TITLE_BAR_BUTTON_SIZE
|
|
||||||
},
|
|
||||||
underlayColor: BaseTheme.spacing.underlay01
|
|
||||||
},
|
|
||||||
|
|
||||||
roomTimer: {
|
roomTimer: {
|
||||||
color: BaseTheme.palette.text01,
|
color: BaseTheme.palette.text01,
|
||||||
...BaseTheme.typography.bodyShortBold,
|
...BaseTheme.typography.bodyShortBold,
|
||||||
|
@ -165,6 +153,12 @@ export default {
|
||||||
backgroundColor: BaseTheme.palette.uiBackground
|
backgroundColor: BaseTheme.palette.uiBackground
|
||||||
},
|
},
|
||||||
|
|
||||||
|
microphoneContainer: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
},
|
||||||
|
|
||||||
titleBarWrapper: {
|
titleBarWrapper: {
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const conferenceNavigationRef = React.createRef();
|
||||||
* @param {Object} params - Params to pass to the destination route.
|
* @param {Object} params - Params to pass to the destination route.
|
||||||
* @returns {Function}
|
* @returns {Function}
|
||||||
*/
|
*/
|
||||||
export function navigate(name: string, params: Object) {
|
export function navigate(name: string, params?: Object) {
|
||||||
return conferenceNavigationRef.current?.navigate(name, params);
|
return conferenceNavigationRef.current?.navigate(name, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,67 +1,165 @@
|
||||||
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
|
import { NavigationContainer } from '@react-navigation/native';
|
||||||
import { NavigationContainer, TypedNavigator } from '@react-navigation/native';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import ConferenceTab from '../../../../../conference/components/native/ConferenceTab';
|
import { Chat, ChatAndPolls } from '../../../../../chat';
|
||||||
|
|
||||||
|
import Conference from '../../../../../conference/components/native/Conference';
|
||||||
import CarmodeTab from '../../../../../conference/components/native/carmode/Conference';
|
import CarmodeTab from '../../../../../conference/components/native/carmode/Conference';
|
||||||
|
import { getDisablePolls } from '../../../../../conference/functions';
|
||||||
|
import { SharedDocument } from '../../../../../etherpad';
|
||||||
|
import { GifsMenu } from '../../../../../gifs/components';
|
||||||
|
import AddPeopleDialog
|
||||||
|
from '../../../../../invite/components/add-people-dialog/native/AddPeopleDialog';
|
||||||
|
import { ParticipantsPane } from '../../../../../participants-pane/components/native';
|
||||||
|
import { StartLiveStreamDialog } from '../../../../../recording';
|
||||||
|
import { StartRecordingDialog }
|
||||||
|
from '../../../../../recording/components/Recording/native';
|
||||||
|
import SalesforceLinkDialog
|
||||||
|
from '../../../../../salesforce/components/native/SalesforceLinkDialog';
|
||||||
|
import SecurityDialog
|
||||||
|
from '../../../../../security/components/security-dialog/native/SecurityDialog';
|
||||||
|
import SpeakerStats
|
||||||
|
from '../../../../../speaker-stats/components/native/SpeakerStats';
|
||||||
import { screen } from '../../../routes';
|
import { screen } from '../../../routes';
|
||||||
import { navigationContainerTheme } from '../../../screenOptions';
|
import {
|
||||||
|
carmodeScreenOptions,
|
||||||
|
chatScreenOptions,
|
||||||
|
conferenceScreenOptions,
|
||||||
|
gifsMenuOptions,
|
||||||
|
inviteScreenOptions,
|
||||||
|
liveStreamScreenOptions,
|
||||||
|
navigationContainerTheme,
|
||||||
|
participantsScreenOptions,
|
||||||
|
recordingScreenOptions,
|
||||||
|
salesforceScreenOptions,
|
||||||
|
securityScreenOptions,
|
||||||
|
sharedDocumentScreenOptions,
|
||||||
|
speakerStatsScreenOptions
|
||||||
|
} from '../../../screenOptions';
|
||||||
|
import LobbyNavigationContainer
|
||||||
|
from '../../lobby/components/LobbyNavigationContainer';
|
||||||
import {
|
import {
|
||||||
conferenceNavigationRef
|
conferenceNavigationRef
|
||||||
} from '../ConferenceNavigationContainerRef';
|
} from '../ConferenceNavigationContainerRef';
|
||||||
|
|
||||||
import NavigationThumb, { THUMBS } from './NavigationThumb';
|
const ConferenceStack = createStackNavigator();
|
||||||
import styles from './styles';
|
|
||||||
|
|
||||||
const ConferenceTabs: TypedNavigator = createMaterialTopTabNavigator();
|
const ConferenceNavigationContainer = () => {
|
||||||
|
const isPollsDisabled = useSelector(getDisablePolls);
|
||||||
|
let ChatScreen;
|
||||||
|
let chatScreenName;
|
||||||
|
let chatTitleString;
|
||||||
|
|
||||||
/**
|
if (isPollsDisabled) {
|
||||||
* Navigation container component for the conference.
|
ChatScreen = Chat;
|
||||||
*
|
chatScreenName = screen.conference.chat;
|
||||||
* @returns {JSX.Element} - the container.
|
chatTitleString = 'chat.title';
|
||||||
*/
|
|
||||||
const ConferenceNavigationContainer = () : JSX.Element => {
|
|
||||||
const [ selectedThumb , setSelectedThumb ] = useState(THUMBS.CONFERENCE_VIEW);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lights up the correct bottom navigation circle
|
|
||||||
* in regards with the focused screen.
|
|
||||||
*/
|
|
||||||
const onFocused = useCallback(selected => {
|
|
||||||
if (selected === screen.car) {
|
|
||||||
setSelectedThumb(THUMBS.CAR_VIEW);
|
|
||||||
} else {
|
} else {
|
||||||
setSelectedThumb(THUMBS.CONFERENCE_VIEW);
|
ChatScreen = ChatAndPolls;
|
||||||
|
chatScreenName = screen.conference.chatandpolls.main;
|
||||||
|
chatTitleString = 'chat.titleWithPolls';
|
||||||
}
|
}
|
||||||
}, []);
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const Carmode = useCallback(() => (
|
|
||||||
<CarmodeTab
|
|
||||||
onFocused = { onFocused } />
|
|
||||||
), []);
|
|
||||||
|
|
||||||
const Conference = useCallback(() => (
|
|
||||||
<ConferenceTab
|
|
||||||
onFocused = { onFocused } />
|
|
||||||
), []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationContainer
|
<NavigationContainer
|
||||||
independent = { true }
|
independent = { true }
|
||||||
ref = { conferenceNavigationRef }
|
ref = { conferenceNavigationRef }
|
||||||
theme = { navigationContainerTheme }>
|
theme = { navigationContainerTheme }>
|
||||||
<ConferenceTabs.Navigator
|
<ConferenceStack.Navigator
|
||||||
backBehavior = 'none'
|
screenOptions = {{
|
||||||
screenOptions = { styles.tabBarOptions }>
|
presentation: 'modal'
|
||||||
<ConferenceTabs.Screen
|
}}>
|
||||||
|
<ConferenceStack.Screen
|
||||||
component = { Conference }
|
component = { Conference }
|
||||||
name = { screen.conference.container } />
|
name = { screen.conference.main }
|
||||||
<ConferenceTabs.Screen
|
options = { conferenceScreenOptions } />
|
||||||
component = { Carmode }
|
<ConferenceStack.Screen
|
||||||
headerShown = { false }
|
component = { ChatScreen }
|
||||||
name = { screen.car } />
|
name = { chatScreenName }
|
||||||
</ConferenceTabs.Navigator>
|
options = {{
|
||||||
<NavigationThumb selectedThumb = { selectedThumb } />
|
...chatScreenOptions,
|
||||||
|
title: t(chatTitleString)
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { ParticipantsPane }
|
||||||
|
name = { screen.conference.participants }
|
||||||
|
options = {{
|
||||||
|
...participantsScreenOptions,
|
||||||
|
title: t('participantsPane.header')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { SecurityDialog }
|
||||||
|
name = { screen.conference.security }
|
||||||
|
options = {{
|
||||||
|
...securityScreenOptions,
|
||||||
|
title: t('security.header')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { StartRecordingDialog }
|
||||||
|
name = { screen.conference.recording }
|
||||||
|
options = {{
|
||||||
|
...recordingScreenOptions
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { StartLiveStreamDialog }
|
||||||
|
name = { screen.conference.liveStream }
|
||||||
|
options = {{
|
||||||
|
...liveStreamScreenOptions
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { SpeakerStats }
|
||||||
|
name = { screen.conference.speakerStats }
|
||||||
|
options = {{
|
||||||
|
...speakerStatsScreenOptions,
|
||||||
|
title: t('speakerStats.speakerStats')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { SalesforceLinkDialog }
|
||||||
|
name = { screen.conference.salesforce }
|
||||||
|
options = {{
|
||||||
|
...salesforceScreenOptions,
|
||||||
|
title: t('notify.linkToSalesforce')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { GifsMenu }
|
||||||
|
name = { screen.conference.gifsMenu }
|
||||||
|
options = {{
|
||||||
|
...gifsMenuOptions,
|
||||||
|
title: t('notify.gifsMenu')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { LobbyNavigationContainer }
|
||||||
|
name = { screen.lobby.root }
|
||||||
|
options = {{
|
||||||
|
gestureEnabled: false,
|
||||||
|
headerShown: false
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { AddPeopleDialog }
|
||||||
|
name = { screen.conference.invite }
|
||||||
|
options = {{
|
||||||
|
...inviteScreenOptions,
|
||||||
|
title: t('addPeople.add')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { SharedDocument }
|
||||||
|
name = { screen.conference.sharedDocument }
|
||||||
|
options = {{
|
||||||
|
...sharedDocumentScreenOptions,
|
||||||
|
title: t('documentSharing.title')
|
||||||
|
}} />
|
||||||
|
<ConferenceStack.Screen
|
||||||
|
component = { CarmodeTab }
|
||||||
|
name = { screen.conference.carmode }
|
||||||
|
options = {{
|
||||||
|
...carmodeScreenOptions,
|
||||||
|
title: t('carmode.labels.title')
|
||||||
|
}}/>
|
||||||
|
</ConferenceStack.Navigator>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { SafeAreaView } from 'react-native';
|
|
||||||
|
|
||||||
import { Icon, IconCircle } from '../../../../../base/icons';
|
|
||||||
|
|
||||||
import styles, { ICON_ACTIVE_COLOR, ICON_INACTIVE_COLOR } from './styles';
|
|
||||||
|
|
||||||
export const enum THUMBS {
|
|
||||||
CONFERENCE_VIEW = 'CONFERENCE_VIEW ',
|
|
||||||
CAR_VIEW = 'CAR_VIEW'
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Which thumb is selected.
|
|
||||||
*/
|
|
||||||
selectedThumb: THUMBS
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bottom tab navigation screen indicator.
|
|
||||||
*
|
|
||||||
* @returns {JSX.Element} - The tab navigation indicator.
|
|
||||||
*/
|
|
||||||
const NavigationThumb = ({ selectedThumb }: Props): JSX.Element => (
|
|
||||||
<SafeAreaView
|
|
||||||
style = { styles.navigationThumbContainer }>
|
|
||||||
{
|
|
||||||
Object.values(THUMBS)
|
|
||||||
.map(value =>
|
|
||||||
(<Icon
|
|
||||||
key = { `thumb-${value.toLowerCase()}` }
|
|
||||||
size = { 8 }
|
|
||||||
color = { value === selectedThumb ? ICON_ACTIVE_COLOR : ICON_INACTIVE_COLOR}
|
|
||||||
src = { IconCircle }
|
|
||||||
style = { styles.navigationThumbIcon } />)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</SafeAreaView>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default NavigationThumb;
|
|
|
@ -1,31 +0,0 @@
|
||||||
import BaseTheme from '../../../../../base/ui/components/BaseTheme';
|
|
||||||
|
|
||||||
export const ICON_ACTIVE_COLOR = BaseTheme.palette.icon01;
|
|
||||||
|
|
||||||
export const ICON_INACTIVE_COLOR = BaseTheme.palette.icon03;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The styles navigation components.
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
|
|
||||||
navigationThumbContainer: {
|
|
||||||
alignSelf: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 13,
|
|
||||||
height: 8,
|
|
||||||
flex: 1
|
|
||||||
},
|
|
||||||
|
|
||||||
navigationThumbIcon: {
|
|
||||||
marginRight: 10
|
|
||||||
},
|
|
||||||
|
|
||||||
tabBarOptions: {
|
|
||||||
tabBarStyle: {
|
|
||||||
display: 'none'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
|
@ -11,12 +11,12 @@ export const screen = {
|
||||||
privacy: 'Privacy',
|
privacy: 'Privacy',
|
||||||
help: 'Help'
|
help: 'Help'
|
||||||
},
|
},
|
||||||
car: 'Car Mode',
|
|
||||||
dialInSummary: 'Dial-In Info',
|
dialInSummary: 'Dial-In Info',
|
||||||
connecting: 'Connecting',
|
connecting: 'Connecting',
|
||||||
conference: {
|
conference: {
|
||||||
root: 'Conference root',
|
root: 'Conference root',
|
||||||
main: 'Conference',
|
main: 'Conference',
|
||||||
|
carmode: 'Car Mode',
|
||||||
chat: 'Chat',
|
chat: 'Chat',
|
||||||
chatandpolls: {
|
chatandpolls: {
|
||||||
main: 'Chat and Polls',
|
main: 'Chat and Polls',
|
||||||
|
|
|
@ -198,6 +198,11 @@ export const presentationScreenOptions = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screen options for car mode.
|
||||||
|
*/
|
||||||
|
export const carmodeScreenOptions = presentationScreenOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen options for chat.
|
* Screen options for chat.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { translate } from '../../../base/i18n';
|
||||||
|
import { IconCar } from '../../../base/icons';
|
||||||
|
import { connect } from '../../../base/redux';
|
||||||
|
import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
|
||||||
|
import { navigate }
|
||||||
|
from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
|
||||||
|
import { screen } from '../../../mobile/navigation/routes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements an {@link AbstractButton} to open the carmode.
|
||||||
|
*/
|
||||||
|
class OpenCarmodeButton extends AbstractButton<AbstractButtonProps, any, any> {
|
||||||
|
accessibilityLabel = 'toolbar.accessibilityLabel.carmode';
|
||||||
|
icon = IconCar;
|
||||||
|
label = 'carmode.labels.buttonLabel';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles clicking / pressing the button, and opens the carmode mode.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
_handleClick() {
|
||||||
|
return navigate(screen.conference.carmode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate(connect()(OpenCarmodeButton));
|
|
@ -24,6 +24,7 @@ import HelpButton from '../HelpButton';
|
||||||
|
|
||||||
import AudioOnlyButton from './AudioOnlyButton';
|
import AudioOnlyButton from './AudioOnlyButton';
|
||||||
import LinkToSalesforceButton from './LinkToSalesforceButton';
|
import LinkToSalesforceButton from './LinkToSalesforceButton';
|
||||||
|
import OpenCarmodeButton from './OpenCarmodeButton';
|
||||||
import RaiseHandButton from './RaiseHandButton';
|
import RaiseHandButton from './RaiseHandButton';
|
||||||
import ScreenSharingButton from './ScreenSharingButton.js';
|
import ScreenSharingButton from './ScreenSharingButton.js';
|
||||||
import ToggleCameraButton from './ToggleCameraButton';
|
import ToggleCameraButton from './ToggleCameraButton';
|
||||||
|
@ -143,6 +144,7 @@ class OverflowMenu extends PureComponent<Props, State> {
|
||||||
? this._renderReactionMenu
|
? this._renderReactionMenu
|
||||||
: null }>
|
: null }>
|
||||||
<ParticipantsPaneButton { ...topButtonProps } />
|
<ParticipantsPaneButton { ...topButtonProps } />
|
||||||
|
<OpenCarmodeButton { ...topButtonProps } />
|
||||||
<AudioOnlyButton { ...buttonProps } />
|
<AudioOnlyButton { ...buttonProps } />
|
||||||
{!_reactionsEnabled && !toolbarButtons.has('raisehand') && <RaiseHandButton { ...buttonProps } />}
|
{!_reactionsEnabled && !toolbarButtons.has('raisehand') && <RaiseHandButton { ...buttonProps } />}
|
||||||
<Divider style = { styles.divider } />
|
<Divider style = { styles.divider } />
|
||||||
|
|
|
@ -1 +1,24 @@
|
||||||
|
import { MEDIA_TYPE, setVideoMuted, VIDEO_MUTISM_AUTHORITY } from '../base/media';
|
||||||
|
import { MiddlewareRegistry } from '../base/redux';
|
||||||
|
|
||||||
|
import { SET_CAR_MODE } from './actionTypes';
|
||||||
import './middleware.any';
|
import './middleware.any';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Middleware which intercepts actions and updates the legacy component.
|
||||||
|
*
|
||||||
|
* @param {Store} store - The redux store.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
MiddlewareRegistry.register(store => next => action => {
|
||||||
|
const result = next(action);
|
||||||
|
const { dispatch } = store;
|
||||||
|
|
||||||
|
switch (action.type) {
|
||||||
|
case SET_CAR_MODE:
|
||||||
|
dispatch(setVideoMuted(action.enabled, MEDIA_TYPE.VIDEO, VIDEO_MUTISM_AUTHORITY.CAR_MODE));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue