MM-54117 - Calls: Support wiredHeadsets; generalize panel_item (#7545)
* generalize panel_item; support wiredHeadsets * i18n
This commit is contained in:
parent
f24642989b
commit
0ec2b09fd5
20 changed files with 178 additions and 109 deletions
|
|
@ -35,7 +35,7 @@ const CopyChannelLinkOption = ({channelName, teamName, showAsLabel, testID}: Pro
|
|||
<SlideUpPanelItem
|
||||
onPress={onCopyLink}
|
||||
text={intl.formatMessage({id: 'channel_info.copy_link', defaultMessage: 'Copy Link'})}
|
||||
icon='link-variant'
|
||||
leftIcon='link-variant'
|
||||
testID={testID}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const InfoBox = ({channelId, containerStyle, showAsLabel = false, testID}: Props
|
|||
if (showAsLabel) {
|
||||
return (
|
||||
<SlideUpPanelItem
|
||||
icon='information-outline'
|
||||
leftIcon='information-outline'
|
||||
onPress={onViewInfo}
|
||||
testID={testID}
|
||||
text={intl.formatMessage({id: 'channel_header.info', defaultMessage: 'View info'})}
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ const LeaveChannelLabel = ({canLeave, channelId, displayName, isOptionItem, type
|
|||
return (
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon={icon}
|
||||
leftIcon={icon}
|
||||
onPress={onLeave}
|
||||
text={leaveText}
|
||||
testID={testID}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ const AtMention = ({
|
|||
style={style.bottomSheet}
|
||||
>
|
||||
<SlideUpPanelItem
|
||||
icon='content-copy'
|
||||
leftIcon='content-copy'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
let username = mentionName;
|
||||
|
|
@ -182,7 +182,7 @@ const AtMention = ({
|
|||
/>
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon='cancel'
|
||||
leftIcon='cancel'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ const MarkdownCodeBlock = ({language = '', content, textStyle}: MarkdownCodeBloc
|
|||
style={style.bottomSheet}
|
||||
>
|
||||
<SlideUpPanelItem
|
||||
icon='content-copy'
|
||||
leftIcon='content-copy'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
Clipboard.setString(content);
|
||||
|
|
@ -133,7 +133,7 @@ const MarkdownCodeBlock = ({language = '', content, textStyle}: MarkdownCodeBloc
|
|||
/>
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon='cancel'
|
||||
leftIcon='cancel'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ const MarkdownImage = ({
|
|||
style={style.bottomSheet}
|
||||
>
|
||||
<SlideUpPanelItem
|
||||
icon='content-copy'
|
||||
leftIcon='content-copy'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
Clipboard.setString(linkDestination || source);
|
||||
|
|
@ -167,7 +167,7 @@ const MarkdownImage = ({
|
|||
/>
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon='cancel'
|
||||
leftIcon='cancel'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ const LatexCodeBlock = ({content, theme}: Props) => {
|
|||
style={styles.bottomSheet}
|
||||
>
|
||||
<SlideUpPanelItem
|
||||
icon='content-copy'
|
||||
leftIcon='content-copy'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
Clipboard.setString(content);
|
||||
|
|
@ -149,7 +149,7 @@ const LatexCodeBlock = ({content, theme}: Props) => {
|
|||
/>
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon='cancel'
|
||||
leftIcon='cancel'
|
||||
onPress={dismissBottomSheet}
|
||||
testID='at_mention.bottom_sheet.cancel'
|
||||
text={intl.formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'})}
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteU
|
|||
style={style.bottomSheet}
|
||||
>
|
||||
<SlideUpPanelItem
|
||||
icon='content-copy'
|
||||
leftIcon='content-copy'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
Clipboard.setString(href);
|
||||
|
|
@ -126,7 +126,7 @@ const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteU
|
|||
/>
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon='cancel'
|
||||
leftIcon='cancel'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -66,13 +66,13 @@ const CameraType = ({onPress}: Props) => {
|
|||
/>
|
||||
}
|
||||
<SlideUpPanelItem
|
||||
icon='camera-outline'
|
||||
leftIcon='camera-outline'
|
||||
onPress={onPhoto}
|
||||
testID='camera_type.photo'
|
||||
text={intl.formatMessage({id: 'camera_type.photo.option', defaultMessage: 'Capture Photo'})}
|
||||
/>
|
||||
<SlideUpPanelItem
|
||||
icon='video-outline'
|
||||
leftIcon='video-outline'
|
||||
onPress={onVideo}
|
||||
testID='camera_type.video'
|
||||
text={intl.formatMessage({id: 'camera_type.video.option', defaultMessage: 'Record Video'})}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ const Failed = ({post, theme}: FailedProps) => {
|
|||
style={styles.bottomSheet}
|
||||
>
|
||||
<SlideUpPanelItem
|
||||
icon='send-outline'
|
||||
leftIcon='send-outline'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
retryFailedPost(serverUrl, post);
|
||||
|
|
@ -54,7 +54,7 @@ const Failed = ({post, theme}: FailedProps) => {
|
|||
/>
|
||||
<SlideUpPanelItem
|
||||
destructive={true}
|
||||
icon='close-circle-outline'
|
||||
leftIcon='close-circle-outline'
|
||||
onPress={() => {
|
||||
dismissBottomSheet();
|
||||
removePost(serverUrl, post);
|
||||
|
|
|
|||
|
|
@ -14,10 +14,12 @@ import {isValidUrl} from '@utils/url';
|
|||
|
||||
type SlideUpPanelProps = {
|
||||
destructive?: boolean;
|
||||
icon?: string | Source;
|
||||
rightIcon?: boolean;
|
||||
imageStyles?: StyleProp<ImageStyle>;
|
||||
iconStyles?: StyleProp<TextStyle>;
|
||||
leftIcon?: string | Source;
|
||||
leftImageStyles?: StyleProp<ImageStyle>;
|
||||
leftIconStyles?: StyleProp<TextStyle>;
|
||||
rightIcon?: string | Source;
|
||||
rightImageStyles?: StyleProp<ImageStyle>;
|
||||
rightIconStyles?: StyleProp<TextStyle>;
|
||||
onPress: () => void;
|
||||
textStyles?: TextStyle;
|
||||
testID?: string;
|
||||
|
|
@ -65,13 +67,55 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const SlideUpPanelItem = ({destructive, icon, imageStyles, onPress, testID, text, textStyles, iconStyles, rightIcon = false}: SlideUpPanelProps) => {
|
||||
const SlideUpPanelItem = ({
|
||||
destructive = false,
|
||||
leftIcon,
|
||||
leftImageStyles,
|
||||
leftIconStyles,
|
||||
rightIcon,
|
||||
rightImageStyles,
|
||||
rightIconStyles,
|
||||
onPress,
|
||||
testID,
|
||||
text,
|
||||
textStyles,
|
||||
}: SlideUpPanelProps) => {
|
||||
const theme = useTheme();
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
const {image: leftImage, iconStyle: leftIconStyle} = useImageAndStyle(leftIcon, leftImageStyles, leftIconStyles, destructive);
|
||||
const {image: rightImage, iconStyle: rightIconStyle} = useImageAndStyle(rightIcon, rightImageStyles, rightIconStyles, destructive);
|
||||
|
||||
const handleOnPress = useCallback(preventDoubleTap(onPress, 500), []);
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
onPress={handleOnPress}
|
||||
style={style.container}
|
||||
testID={testID}
|
||||
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
|
||||
>
|
||||
<View style={style.row}>
|
||||
{Boolean(leftImage) &&
|
||||
<View style={leftIconStyle}>{leftImage}</View>
|
||||
}
|
||||
<View style={style.textContainer}>
|
||||
<Text style={[style.text, destructive && style.destructive, textStyles]}>{text}</Text>
|
||||
</View>
|
||||
{Boolean(rightImage) &&
|
||||
<View style={rightIconStyle}>{rightImage}</View>
|
||||
}
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
};
|
||||
|
||||
const useImageAndStyle = (icon: string | Source | undefined, imageStyles: StyleProp<ImageStyle>, iconStyles: StyleProp<TextStyle>, destructive: boolean) => {
|
||||
const theme = useTheme();
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
let image;
|
||||
let iconStyle: StyleProp<ViewStyle> = [style.iconContainer];
|
||||
let iconStyle: Array<StyleProp<ViewStyle>> = [style.iconContainer];
|
||||
if (icon) {
|
||||
if (typeof icon === 'object') {
|
||||
if (icon.uri && isValidUrl(icon.uri)) {
|
||||
|
|
@ -101,26 +145,7 @@ const SlideUpPanelItem = ({destructive, icon, imageStyles, onPress, testID, text
|
|||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
onPress={handleOnPress}
|
||||
style={style.container}
|
||||
testID={testID}
|
||||
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
|
||||
>
|
||||
<View style={style.row}>
|
||||
{Boolean(image) && !rightIcon &&
|
||||
<View style={iconStyle}>{image}</View>
|
||||
}
|
||||
<View style={style.textContainer}>
|
||||
<Text style={[style.text, destructive && style.destructive, textStyles]}>{text}</Text>
|
||||
</View>
|
||||
{Boolean(image) && rightIcon &&
|
||||
<View style={iconStyle}>{image}</View>
|
||||
}
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
return {image, iconStyle};
|
||||
};
|
||||
|
||||
export default SlideUpPanelItem;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import {Device} from '@constants';
|
|||
import {useTheme} from '@context/theme';
|
||||
import {bottomSheet, dismissBottomSheet} from '@screens/navigation';
|
||||
import {bottomSheetSnapPoint} from '@utils/helpers';
|
||||
import {typography} from '@utils/typography';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
pressableStyle: StyleProp<ViewStyle>;
|
||||
|
|
@ -23,13 +23,16 @@ type Props = {
|
|||
currentCall: CurrentCall;
|
||||
}
|
||||
|
||||
const style = {
|
||||
bold: typography('Body', 200, 'SemiBold'),
|
||||
};
|
||||
const getStyleFromTheme = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
checkIcon: {
|
||||
color: theme.buttonBg,
|
||||
},
|
||||
}));
|
||||
|
||||
export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, currentCall}: Props) => {
|
||||
const intl = useIntl();
|
||||
const theme = useTheme();
|
||||
const style = getStyleFromTheme(theme);
|
||||
const {bottom} = useSafeAreaInsets();
|
||||
const isTablet = Device.IS_TABLET; // not `useIsTablet` because even if we're in splitView, we're still using a tablet.
|
||||
const color = theme.awayIndicator;
|
||||
|
|
@ -38,10 +41,14 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
|
|||
const tabletLabel = intl.formatMessage({id: 'mobile.calls_tablet', defaultMessage: 'Tablet'});
|
||||
const speakerLabel = intl.formatMessage({id: 'mobile.calls_speaker', defaultMessage: 'SpeakerPhone'});
|
||||
const bluetoothLabel = intl.formatMessage({id: 'mobile.calls_bluetooth', defaultMessage: 'Bluetooth'});
|
||||
const headsetLabel = intl.formatMessage({id: 'mobile.calls_headset', defaultMessage: 'Headset'});
|
||||
|
||||
const deviceSelector = useCallback(async () => {
|
||||
const currentDevice = audioDeviceInfo.selectedAudioDevice;
|
||||
const available = audioDeviceInfo.availableAudioDeviceList;
|
||||
let available = audioDeviceInfo.availableAudioDeviceList;
|
||||
if (available.includes(AudioDevice.WiredHeadset)) {
|
||||
available = available.filter((d) => d !== AudioDevice.Earpiece);
|
||||
}
|
||||
const selectDevice = (device: AudioDevice) => {
|
||||
setPreferredAudioRoute(device);
|
||||
dismissBottomSheet();
|
||||
|
|
@ -52,34 +59,47 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
|
|||
<View>
|
||||
{available.includes(AudioDevice.Earpiece) && isTablet &&
|
||||
<SlideUpPanelItem
|
||||
icon={'tablet'}
|
||||
leftIcon={'tablet'}
|
||||
onPress={() => selectDevice(AudioDevice.Earpiece)}
|
||||
text={tabletLabel}
|
||||
textStyles={currentDevice === AudioDevice.Earpiece ? {...style.bold, color} : {}}
|
||||
rightIcon={currentDevice === AudioDevice.Earpiece ? 'check' : undefined}
|
||||
rightIconStyles={currentDevice === AudioDevice.Earpiece ? style.checkIcon : {}}
|
||||
/>
|
||||
}
|
||||
{available.includes(AudioDevice.Earpiece) && !isTablet &&
|
||||
<SlideUpPanelItem
|
||||
icon={'cellphone'}
|
||||
leftIcon={'cellphone'}
|
||||
onPress={() => selectDevice(AudioDevice.Earpiece)}
|
||||
text={phoneLabel}
|
||||
textStyles={currentDevice === AudioDevice.Earpiece ? {...style.bold, color} : {}}
|
||||
rightIcon={currentDevice === AudioDevice.Earpiece ? 'check' : undefined}
|
||||
rightIconStyles={currentDevice === AudioDevice.Earpiece ? style.checkIcon : {}}
|
||||
/>
|
||||
}
|
||||
{available.includes(AudioDevice.Speakerphone) &&
|
||||
<SlideUpPanelItem
|
||||
icon={'volume-high'}
|
||||
leftIcon={'volume-high'}
|
||||
onPress={() => selectDevice(AudioDevice.Speakerphone)}
|
||||
text={speakerLabel}
|
||||
textStyles={currentDevice === AudioDevice.Speakerphone ? {...style.bold, color} : {}}
|
||||
rightIcon={currentDevice === AudioDevice.Speakerphone ? 'check' : undefined}
|
||||
rightIconStyles={currentDevice === AudioDevice.Speakerphone ? style.checkIcon : {}}
|
||||
/>
|
||||
}
|
||||
{available.includes(AudioDevice.Bluetooth) &&
|
||||
<SlideUpPanelItem
|
||||
icon={'bluetooth'}
|
||||
leftIcon={'bluetooth'}
|
||||
onPress={() => selectDevice(AudioDevice.Bluetooth)}
|
||||
text={bluetoothLabel}
|
||||
textStyles={currentDevice === AudioDevice.Bluetooth ? {...style.bold, color} : {}}
|
||||
rightIcon={currentDevice === AudioDevice.Bluetooth ? 'check' : undefined}
|
||||
rightIconStyles={currentDevice === AudioDevice.Bluetooth ? style.checkIcon : {}}
|
||||
/>
|
||||
}
|
||||
{available.includes(AudioDevice.WiredHeadset) &&
|
||||
<SlideUpPanelItem
|
||||
leftIcon={'headphones'}
|
||||
onPress={() => selectDevice(AudioDevice.WiredHeadset)}
|
||||
text={headsetLabel}
|
||||
rightIcon={currentDevice === AudioDevice.WiredHeadset ? 'check' : undefined}
|
||||
rightIconStyles={currentDevice === AudioDevice.WiredHeadset ? style.checkIcon : {}}
|
||||
/>
|
||||
}
|
||||
</View>
|
||||
|
|
@ -89,7 +109,7 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
|
|||
await bottomSheet({
|
||||
closeButtonId: 'close-other-actions',
|
||||
renderContent,
|
||||
snapPoints: [1, bottomSheetSnapPoint(audioDeviceInfo.availableAudioDeviceList.length + 1, ITEM_HEIGHT, bottom)],
|
||||
snapPoints: [1, bottomSheetSnapPoint(available.length + 1, ITEM_HEIGHT, bottom)],
|
||||
title: intl.formatMessage({id: 'mobile.calls_audio_device', defaultMessage: 'Select audio device'}),
|
||||
theme,
|
||||
});
|
||||
|
|
@ -106,6 +126,10 @@ export const AudioDeviceButton = ({pressableStyle, iconStyle, buttonTextStyle, c
|
|||
icon = 'bluetooth';
|
||||
label = bluetoothLabel;
|
||||
break;
|
||||
case AudioDevice.WiredHeadset:
|
||||
icon = 'headphones';
|
||||
label = headsetLabel;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import {RTCMonitor, RTCPeer} from '@mattermost/calls/lib';
|
||||
import {deflate} from 'pako';
|
||||
import {DeviceEventEmitter, type EmitterSubscription, Platform} from 'react-native';
|
||||
import {DeviceEventEmitter, type EmitterSubscription, NativeEventEmitter, NativeModules, Platform} from 'react-native';
|
||||
import InCallManager from 'react-native-incall-manager';
|
||||
import {mediaDevices, MediaStream, MediaStreamTrack, RTCPeerConnection} from 'react-native-webrtc';
|
||||
|
||||
|
|
@ -24,6 +24,8 @@ import type {EmojiData} from '@mattermost/calls/lib/types';
|
|||
const peerConnectTimeout = 5000;
|
||||
const rtcMonitorInterval = 4000;
|
||||
|
||||
const InCallManagerEmitter = new NativeEventEmitter(NativeModules.InCallManager);
|
||||
|
||||
export async function newConnection(
|
||||
serverUrl: string,
|
||||
channelID: string,
|
||||
|
|
@ -40,6 +42,7 @@ export async function newConnection(
|
|||
let isClosed = false;
|
||||
let onCallEnd: EmitterSubscription | null = null;
|
||||
let audioDeviceChanged: EmitterSubscription | null = null;
|
||||
let wiredHeadsetEvent: EmitterSubscription | null = null;
|
||||
const streams: MediaStream[] = [];
|
||||
let rtcMonitor: RTCMonitor | null = null;
|
||||
const logger = {
|
||||
|
|
@ -106,6 +109,7 @@ export async function newConnection(
|
|||
peer = null;
|
||||
InCallManager.stop();
|
||||
audioDeviceChanged?.remove();
|
||||
wiredHeadsetEvent?.remove();
|
||||
|
||||
if (closeCb) {
|
||||
closeCb();
|
||||
|
|
@ -224,29 +228,50 @@ export async function newConnection(
|
|||
let btInitialized = false;
|
||||
let speakerInitialized = false;
|
||||
|
||||
audioDeviceChanged = DeviceEventEmitter.addListener('onAudioDeviceChanged', (data: AudioDeviceInfoRaw) => {
|
||||
const info: AudioDeviceInfo = {
|
||||
availableAudioDeviceList: JSON.parse(data.availableAudioDeviceList),
|
||||
selectedAudioDevice: data.selectedAudioDevice,
|
||||
};
|
||||
setAudioDeviceInfo(info);
|
||||
if (Platform.OS === 'android') {
|
||||
audioDeviceChanged = DeviceEventEmitter.addListener('onAudioDeviceChanged', (data: AudioDeviceInfoRaw) => {
|
||||
const info: AudioDeviceInfo = {
|
||||
availableAudioDeviceList: JSON.parse(data.availableAudioDeviceList),
|
||||
selectedAudioDevice: data.selectedAudioDevice,
|
||||
};
|
||||
setAudioDeviceInfo(info);
|
||||
logDebug('AudioDeviceChanged. info:', info);
|
||||
|
||||
// Auto switch to bluetooth the first time we connect to bluetooth, but not after.
|
||||
if (!btInitialized) {
|
||||
if (info.availableAudioDeviceList.includes(AudioDevice.Bluetooth)) {
|
||||
setPreferredAudioRoute(AudioDevice.Bluetooth);
|
||||
btInitialized = true;
|
||||
} else if (!speakerInitialized) {
|
||||
// If we don't have bluetooth available, default to speakerphone on.
|
||||
setPreferredAudioRoute(AudioDevice.Speakerphone);
|
||||
speakerInitialized = true;
|
||||
// Auto switch to bluetooth the first time we connect to bluetooth, but not after.
|
||||
if (!btInitialized) {
|
||||
if (info.availableAudioDeviceList.includes(AudioDevice.Bluetooth)) {
|
||||
setPreferredAudioRoute(AudioDevice.Bluetooth);
|
||||
btInitialized = true;
|
||||
} else if (!speakerInitialized) {
|
||||
// If we don't have bluetooth available, default to speakerphone on.
|
||||
setPreferredAudioRoute(AudioDevice.Speakerphone);
|
||||
speakerInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// We default to speakerphone (Android is handled above in the onAudioDeviceChanged handler above).
|
||||
// We default to speakerphone, but not if the WiredHeadset is plugged in.
|
||||
if (Platform.OS === 'ios') {
|
||||
setSpeakerphoneOn(true);
|
||||
wiredHeadsetEvent = InCallManagerEmitter.addListener('WiredHeadset', (data) => {
|
||||
// Log for customer debugging. For the moment we're not changing output labels because of incall-manager iOS
|
||||
// limitations with how it reports Bluetooth -- namely that it doesn't, so we don't know when Bluetooth is
|
||||
// overriding the earpiece and/or headset.
|
||||
logDebug('WiredHeadset plugged in. Data:', data);
|
||||
|
||||
// iOS switches to the headset when we connect it, so turn off speakerphone to keep UI in sync.
|
||||
if (data.isPlugged) {
|
||||
setSpeakerphoneOn(false);
|
||||
}
|
||||
});
|
||||
|
||||
// If headset is plugged in when the call starts, use it.
|
||||
const report = await InCallManager.getIsWiredHeadsetPluggedIn();
|
||||
if (report.isWiredHeadsetPluggedIn) {
|
||||
setSpeakerphoneOn(false);
|
||||
} else {
|
||||
setSpeakerphoneOn(true);
|
||||
}
|
||||
}
|
||||
|
||||
peer = new RTCPeer({
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ const CallScreen = ({
|
|||
{
|
||||
showStartRecording &&
|
||||
<SlideUpPanelItem
|
||||
icon={'record-circle-outline'}
|
||||
leftIcon={'record-circle-outline'}
|
||||
onPress={startRecording}
|
||||
text={recordOptionTitle}
|
||||
/>
|
||||
|
|
@ -485,14 +485,14 @@ const CallScreen = ({
|
|||
{
|
||||
showStopRecording &&
|
||||
<SlideUpPanelItem
|
||||
icon={'record-square-outline'}
|
||||
leftIcon={'record-square-outline'}
|
||||
onPress={stopRecording}
|
||||
text={stopRecordingOptionTitle}
|
||||
textStyles={style.denimDND}
|
||||
/>
|
||||
}
|
||||
<SlideUpPanelItem
|
||||
icon='message-text-outline'
|
||||
leftIcon='message-text-outline'
|
||||
onPress={switchToThread}
|
||||
text={callThreadOptionTitle}
|
||||
/>
|
||||
|
|
@ -764,7 +764,6 @@ const CallScreen = ({
|
|||
iconStyle={[
|
||||
style.buttonIcon,
|
||||
isLandscape && style.buttonIconLandscape,
|
||||
style.speakerphoneIcon,
|
||||
currentCall.speakerphoneOn && style.buttonOn,
|
||||
]}
|
||||
buttonTextStyle={style.buttonText}
|
||||
|
|
|
|||
|
|
@ -42,11 +42,6 @@ export default function DropdownSlideup({
|
|||
const style = getStyleFromTheme(theme);
|
||||
const isTablet = useIsTablet();
|
||||
|
||||
const commonProps = {
|
||||
rightIcon: true,
|
||||
iconStyles: style.checkIcon,
|
||||
};
|
||||
|
||||
const handlePublicPress = useCallback(() => {
|
||||
dismissBottomSheet();
|
||||
onPress(PUBLIC);
|
||||
|
|
@ -73,16 +68,16 @@ export default function DropdownSlideup({
|
|||
onPress={handlePublicPress}
|
||||
testID='browse_channels.dropdown_slideup_item.public_channels'
|
||||
text={intl.formatMessage({id: 'browse_channels.publicChannels', defaultMessage: 'Public Channels'})}
|
||||
icon={selected === PUBLIC ? 'check' : undefined}
|
||||
{...commonProps}
|
||||
rightIcon={selected === PUBLIC ? 'check' : undefined}
|
||||
rightIconStyles={style.checkIcon}
|
||||
/>
|
||||
{canShowArchivedChannels && (
|
||||
<SlideUpPanelItem
|
||||
onPress={handleArchivedPress}
|
||||
testID='browse_channels.dropdown_slideup_item.archived_channels'
|
||||
text={intl.formatMessage({id: 'browse_channels.archivedChannels', defaultMessage: 'Archived Channels'})}
|
||||
icon={selected === ARCHIVED ? 'check' : undefined}
|
||||
{...commonProps}
|
||||
rightIcon={selected === ARCHIVED ? 'check' : undefined}
|
||||
rightIconStyles={style.checkIcon}
|
||||
/>
|
||||
)}
|
||||
{sharedChannelsEnabled && (
|
||||
|
|
@ -90,8 +85,8 @@ export default function DropdownSlideup({
|
|||
onPress={handleSharedPress}
|
||||
testID='browse_channels.dropdown_slideup_item.shared_channels'
|
||||
text={intl.formatMessage({id: 'browse_channels.sharedChannels', defaultMessage: 'Shared Channels'})}
|
||||
icon={selected === SHARED ? 'check' : undefined}
|
||||
{...commonProps}
|
||||
rightIcon={selected === SHARED ? 'check' : undefined}
|
||||
rightIconStyles={style.checkIcon}
|
||||
/>
|
||||
)}
|
||||
</BottomSheetContent>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ const PanelItem = ({pickerAction, pictureUtils, onRemoveProfileImage}: PanelItem
|
|||
|
||||
return (
|
||||
<SlideUpPanelItem
|
||||
icon={item.icon}
|
||||
leftIcon={item.icon}
|
||||
onPress={item.onPress}
|
||||
testID={item.testID}
|
||||
text={intl.formatMessage(item.text)}
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ const UserStatus = ({currentUser}: Props) => {
|
|||
</View>
|
||||
)}
|
||||
<SlideUpPanelItem
|
||||
icon='check-circle'
|
||||
iconStyles={{color: theme.onlineIndicator}}
|
||||
leftIcon='check-circle'
|
||||
leftIconStyles={{color: theme.onlineIndicator}}
|
||||
onPress={() => setUserStatus(ONLINE)}
|
||||
testID='user_status.online.option'
|
||||
text={intl.formatMessage({
|
||||
|
|
@ -89,8 +89,8 @@ const UserStatus = ({currentUser}: Props) => {
|
|||
textStyles={styles.label}
|
||||
/>
|
||||
<SlideUpPanelItem
|
||||
icon='clock'
|
||||
iconStyles={{color: theme.awayIndicator}}
|
||||
leftIcon='clock'
|
||||
leftIconStyles={{color: theme.awayIndicator}}
|
||||
onPress={() => setUserStatus(AWAY)}
|
||||
testID='user_status.away.option'
|
||||
text={intl.formatMessage({
|
||||
|
|
@ -100,8 +100,8 @@ const UserStatus = ({currentUser}: Props) => {
|
|||
textStyles={styles.label}
|
||||
/>
|
||||
<SlideUpPanelItem
|
||||
icon='minus-circle'
|
||||
iconStyles={{color: theme.dndIndicator}}
|
||||
leftIcon='minus-circle'
|
||||
leftIconStyles={{color: theme.dndIndicator}}
|
||||
onPress={() => setUserStatus(DND)}
|
||||
testID='user_status.dnd.option'
|
||||
text={intl.formatMessage({
|
||||
|
|
@ -111,8 +111,8 @@ const UserStatus = ({currentUser}: Props) => {
|
|||
textStyles={styles.label}
|
||||
/>
|
||||
<SlideUpPanelItem
|
||||
icon='circle-outline'
|
||||
iconStyles={{color: changeOpacity('#B8B8B8', 0.64)}}
|
||||
leftIcon='circle-outline'
|
||||
leftIconStyles={{color: changeOpacity('#B8B8B8', 0.64)}}
|
||||
onPress={() => setUserStatus(OFFLINE)}
|
||||
testID='user_status.offline.option'
|
||||
text={intl.formatMessage({
|
||||
|
|
|
|||
|
|
@ -435,6 +435,7 @@
|
|||
"mobile.calls_ended_at": "Ended at",
|
||||
"mobile.calls_error_message": "Error: {error}",
|
||||
"mobile.calls_error_title": "Error",
|
||||
"mobile.calls_headset": "Headset",
|
||||
"mobile.calls_host": "host",
|
||||
"mobile.calls_host_rec": "You are recording this meeting. Consider letting everyone know that this meeting is being recorded.",
|
||||
"mobile.calls_host_rec_error": "Please try to record again. You can also contact your system admin for troubleshooting help.",
|
||||
|
|
|
|||
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -18,7 +18,7 @@
|
|||
"@formatjs/intl-relativetimeformat": "11.2.4",
|
||||
"@gorhom/bottom-sheet": "4.4.7",
|
||||
"@mattermost/calls": "github:mattermost/calls-common#v0.17.0",
|
||||
"@mattermost/compass-icons": "0.1.37",
|
||||
"@mattermost/compass-icons": "0.1.38",
|
||||
"@mattermost/react-native-emm": "1.3.5",
|
||||
"@mattermost/react-native-network-client": "1.4.1",
|
||||
"@mattermost/react-native-paste-input": "0.6.4",
|
||||
|
|
@ -3436,9 +3436,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@mattermost/compass-icons": {
|
||||
"version": "0.1.37",
|
||||
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.37.tgz",
|
||||
"integrity": "sha512-4me1W0hj1nu8A1gpdQA6cij/hyb2P7uIYMJQ+xrNvn5ImTRfQ67LEdyNOa/LY+oT1NO2ui6kKOs8oLUehIaneg=="
|
||||
"version": "0.1.38",
|
||||
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.38.tgz",
|
||||
"integrity": "sha512-JfLQJtvxD++7lw+jiLWs55+SOhF8wPQgfTCOEi/uyl9bRxfY736a9fPzRcRJwF80se7lPMxvAx8itwvTz0o7CQ=="
|
||||
},
|
||||
"node_modules/@mattermost/react-native-emm": {
|
||||
"version": "1.3.5",
|
||||
|
|
@ -25415,9 +25415,9 @@
|
|||
}
|
||||
},
|
||||
"@mattermost/compass-icons": {
|
||||
"version": "0.1.37",
|
||||
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.37.tgz",
|
||||
"integrity": "sha512-4me1W0hj1nu8A1gpdQA6cij/hyb2P7uIYMJQ+xrNvn5ImTRfQ67LEdyNOa/LY+oT1NO2ui6kKOs8oLUehIaneg=="
|
||||
"version": "0.1.38",
|
||||
"resolved": "https://registry.npmjs.org/@mattermost/compass-icons/-/compass-icons-0.1.38.tgz",
|
||||
"integrity": "sha512-JfLQJtvxD++7lw+jiLWs55+SOhF8wPQgfTCOEi/uyl9bRxfY736a9fPzRcRJwF80se7lPMxvAx8itwvTz0o7CQ=="
|
||||
},
|
||||
"@mattermost/react-native-emm": {
|
||||
"version": "1.3.5",
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"@formatjs/intl-relativetimeformat": "11.2.4",
|
||||
"@gorhom/bottom-sheet": "4.4.7",
|
||||
"@mattermost/calls": "github:mattermost/calls-common#v0.17.0",
|
||||
"@mattermost/compass-icons": "0.1.37",
|
||||
"@mattermost/compass-icons": "0.1.38",
|
||||
"@mattermost/react-native-emm": "1.3.5",
|
||||
"@mattermost/react-native-network-client": "1.4.1",
|
||||
"@mattermost/react-native-paste-input": "0.6.4",
|
||||
|
|
|
|||
Loading…
Reference in a new issue