MM-48836 - Calls: handle slash commands (#6980)

This commit is contained in:
Christopher Poile 2023-01-23 13:08:33 -05:00 committed by GitHub
parent e140a12b6c
commit 9a89259e96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 200 additions and 194 deletions

View file

@ -3,15 +3,14 @@
import React, {useCallback, useEffect, useState} from 'react';
import {useIntl} from 'react-intl';
import {Alert, DeviceEventEmitter} from 'react-native';
import {DeviceEventEmitter} from 'react-native';
import {getChannelTimezones} from '@actions/remote/channel';
import {executeCommand, handleGotoLocation} from '@actions/remote/command';
import {createPost} from '@actions/remote/post';
import {handleReactionToLatestPost} from '@actions/remote/reactions';
import {setStatus} from '@actions/remote/user';
import {canEndCall, endCall, getEndCallMessage} from '@calls/actions/calls';
import ClientError from '@client/rest/error';
import {handleCallsSlashCommand} from '@calls/actions/calls';
import {Events, Screens} from '@constants';
import {PostPriorityType} from '@constants/post';
import {NOTIFY_ALL_MEMBERS} from '@constants/post_draft';
@ -147,54 +146,19 @@ export default function SendHandler({
DraftUtils.alertChannelWideMention(intl, notifyAllMessage, doSubmitMessage, cancel);
}, [intl, isTimezoneEnabled, channelTimezoneCount, doSubmitMessage]);
const handleEndCall = useCallback(async () => {
const hasPermissions = await canEndCall(serverUrl, channelId);
if (!hasPermissions) {
Alert.alert(
intl.formatMessage({
id: 'mobile.calls_end_permission_title',
defaultMessage: 'Error',
}),
intl.formatMessage({
id: 'mobile.calls_end_permission_msg',
defaultMessage: 'You don\'t have permission to end the call. Please ask the call owner to end the call.',
}));
return;
}
const message = await getEndCallMessage(serverUrl, channelId, currentUserId, intl);
const title = intl.formatMessage({id: 'mobile.calls_end_call_title', defaultMessage: 'End call'});
Alert.alert(
title,
message,
[
{
text: intl.formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}),
},
{
text: title,
onPress: async () => {
try {
await endCall(serverUrl, channelId);
} catch (e) {
const err = (e as ClientError).message || 'unable to complete command, see server logs';
Alert.alert('Error', `Error: ${err}`);
}
},
style: 'cancel',
},
],
);
}, [serverUrl, channelId, currentUserId, intl]);
const sendCommand = useCallback(async () => {
if (value.trim() === '/call end') {
await handleEndCall();
setSendingMessage(false);
clearDraft();
return;
if (value.trim().startsWith('/call')) {
const {handled, error} = await handleCallsSlashCommand(value.trim(), serverUrl, channelId, currentUserId, intl);
if (handled) {
setSendingMessage(false);
clearDraft();
return;
}
if (error) {
setSendingMessage(false);
DraftUtils.alertSlashCommandFailed(intl, error);
return;
}
}
const status = DraftUtils.getStatusFromSlashCommand(value);
@ -226,7 +190,7 @@ export default function SendHandler({
if (data?.goto_location && !value.startsWith('/leave')) {
handleGotoLocation(serverUrl, intl, data.goto_location);
}
}, [userIsOutOfOffice, currentUserId, intl, value, serverUrl, channelId, rootId, handleEndCall]);
}, [userIsOutOfOffice, currentUserId, intl, value, serverUrl, channelId, rootId]);
const sendMessage = useCallback(() => {
const notificationsToChannel = enableConfirmNotificationsToChannel && useChannelMentions;

View file

@ -1,11 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {Alert} from 'react-native';
import InCallManager from 'react-native-incall-manager';
import {Navigation} from 'react-native-navigation';
import {forceLogoutIfNecessary} from '@actions/remote/session';
import {fetchUsersByIds} from '@actions/remote/user';
import {needsRecordingWillBePostedAlert} from '@calls/alerts';
import {leaveAndJoinWithAlert, needsRecordingWillBePostedAlert} from '@calls/alerts';
import {
getCallsConfig,
getCallsState,
@ -18,8 +20,10 @@ import {
setCallForChannel,
newCurrentCall,
myselfLeftCall,
getCurrentCall,
getChannelsWithCalls,
} from '@calls/state';
import {General, Preferences} from '@constants';
import {General, Preferences, Screens} from '@constants';
import Calls from '@constants/calls';
import DatabaseManager from '@database/manager';
import {getTeammateNameDisplaySetting} from '@helpers/api/preference';
@ -28,6 +32,8 @@ import {getChannelById} from '@queries/servers/channel';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {getConfig, getLicense} from '@queries/servers/system';
import {getCurrentUser, getUserById} from '@queries/servers/user';
import {dismissAllModalsAndPopToScreen} from '@screens/navigation';
import NavigationStore from '@store/navigation_store';
import {logWarning} from '@utils/log';
import {displayUsername, getUserIdFromChannelName, isSystemAdmin} from '@utils/user';
@ -228,7 +234,13 @@ export const enableChannelCalls = async (serverUrl: string, channelId: string, e
return {};
};
export const joinCall = async (serverUrl: string, channelId: string, userId: string, hasMicPermission: boolean): Promise<{ error?: string | Error; data?: string }> => {
export const joinCall = async (
serverUrl: string,
channelId: string,
userId: string,
hasMicPermission: boolean,
title?: string,
): Promise<{ error?: string | Error; data?: string }> => {
// Edge case: calls was disabled when app loaded, and then enabled, but app hasn't
// reconnected its websocket since then (i.e., hasn't called batchLoadCalls yet)
const {data: enabled} = await checkIsCallsPluginEnabled(serverUrl);
@ -246,7 +258,7 @@ export const joinCall = async (serverUrl: string, channelId: string, userId: str
try {
connection = await newConnection(serverUrl, channelId, () => {
myselfLeftCall();
}, setScreenShareURL, hasMicPermission);
}, setScreenShareURL, hasMicPermission, title);
} catch (error: unknown) {
await forceLogoutIfNecessary(serverUrl, error as ClientError);
return {error: error as Error};
@ -270,6 +282,16 @@ export const leaveCall = () => {
setSpeakerphoneOn(false);
};
export const leaveCallPopCallScreen = async () => {
leaveCall();
// Need to pop the call screen, if it's somewhere in the stack.
if (NavigationStore.getScreensInStack().includes(Screens.CALL)) {
await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call');
Navigation.pop(Screens.CALL).catch(() => null);
}
};
export const muteMyself = () => {
if (connection) {
connection.mute();
@ -419,3 +441,89 @@ export const stopCallRecording = async (serverUrl: string, callId: string) => {
return data;
};
// handleCallsSlashCommand will return true if the slash command was handled
export const handleCallsSlashCommand = async (value: string, serverUrl: string, channelId: string, currentUserId: string, intl: IntlShape):
Promise<{ handled?: boolean; error?: string }> => {
const tokens = value.split(' ');
if (tokens.length < 2 || tokens[0] !== '/call') {
return {handled: false};
}
switch (tokens[1]) {
case 'end':
await handleEndCall(serverUrl, channelId, currentUserId, intl);
return {handled: true};
case 'start': {
if (getChannelsWithCalls(serverUrl)[channelId]) {
return {
error: intl.formatMessage({
id: 'mobile.calls_start_call_exists',
defaultMessage: 'A call is already ongoing in the channel.',
}),
};
}
const title = tokens.length > 2 ? tokens.slice(2).join(' ') : undefined;
await leaveAndJoinWithAlert(intl, serverUrl, channelId, title);
return {handled: true};
}
case 'join':
await leaveAndJoinWithAlert(intl, serverUrl, channelId);
return {handled: true};
case 'leave':
if (getCurrentCall()?.channelId === channelId) {
await leaveCallPopCallScreen();
return {handled: true};
}
return {
error: intl.formatMessage({
id: 'mobile.calls_not_connected',
defaultMessage: 'You\'re not connected to a call in the current channel.',
}),
};
}
return {handled: false};
};
const handleEndCall = async (serverUrl: string, channelId: string, currentUserId: string, intl: IntlShape) => {
const hasPermissions = await canEndCall(serverUrl, channelId);
if (!hasPermissions) {
Alert.alert(
intl.formatMessage({
id: 'mobile.calls_end_permission_title',
defaultMessage: 'Error',
}),
intl.formatMessage({
id: 'mobile.calls_end_permission_msg',
defaultMessage: 'You don\'t have permission to end the call. Please ask the call owner to end the call.',
}));
return;
}
const message = await getEndCallMessage(serverUrl, channelId, currentUserId, intl);
const title = intl.formatMessage({id: 'mobile.calls_end_call_title', defaultMessage: 'End call'});
Alert.alert(
title,
message,
[
{
text: intl.formatMessage({id: 'mobile.post.cancel', defaultMessage: 'Cancel'}),
},
{
text: title,
onPress: async () => {
try {
await endCall(serverUrl, channelId);
} catch (e) {
const err = (e as ClientError).message || 'unable to complete command, see server logs';
Alert.alert('Error', `Error: ${err}`);
}
},
style: 'cancel',
},
],
);
};

View file

@ -12,6 +12,7 @@ export {
raiseHand,
unraiseHand,
setSpeakerphoneOn,
handleCallsSlashCommand,
} from './calls';
export {hasMicrophonePermission} from './permissions';

View file

@ -2,17 +2,22 @@
// See LICENSE.txt for license information.
import {Alert} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {hasMicrophonePermission, joinCall, leaveCall, unmuteMyself} from '@calls/actions';
import {hasMicrophonePermission, joinCall, unmuteMyself} from '@calls/actions';
import {leaveCallPopCallScreen} from '@calls/actions/calls';
import {LimitRestrictedInfo} from '@calls/observers';
import {getCallsConfig, getCallsState, setMicPermissionsGranted} from '@calls/state';
import {
getCallsConfig,
getCallsState,
getChannelsWithCalls,
getCurrentCall,
setMicPermissionsGranted,
} from '@calls/state';
import {errorAlert} from '@calls/utils';
import {Screens} from '@constants';
import DatabaseManager from '@database/manager';
import {getChannelById} from '@queries/servers/channel';
import {getCurrentUser} from '@queries/servers/user';
import {dismissAllModals, dismissAllModalsAndPopToScreen} from '@screens/navigation';
import NavigationStore from '@store/navigation_store';
import {isDMorGM} from '@utils/channel';
import {logError} from '@utils/log';
import {isSystemAdmin} from '@utils/user';
@ -56,17 +61,39 @@ export const showLimitRestrictedAlert = (info: LimitRestrictedInfo, intl: IntlSh
);
};
export const leaveAndJoinWithAlert = (
export const leaveAndJoinWithAlert = async (
intl: IntlShape,
serverUrl: string,
channelId: string,
leaveChannelName: string,
joinChannelName: string,
confirmToJoin: boolean,
newCall: boolean,
isDMorGM: boolean,
joinServerUrl: string,
joinChannelId: string,
title?: string,
) => {
if (confirmToJoin) {
let leaveChannelName = '';
let joinChannelName = '';
let joinChannelIsDMorGM = false;
let leaveServerUrl = '';
let leaveChannelId = '';
const newCall = !getChannelsWithCalls(joinServerUrl)[joinChannelId];
try {
const {database: joinDatabase} = DatabaseManager.getServerDatabaseAndOperator(joinServerUrl);
const joinChannel = await getChannelById(joinDatabase, joinChannelId);
joinChannelName = joinChannel?.displayName || '';
joinChannelIsDMorGM = joinChannel ? isDMorGM(joinChannel) : false;
const currentCall = getCurrentCall();
if (currentCall) {
const {database: leaveDatabase} = DatabaseManager.getServerDatabaseAndOperator(currentCall.serverUrl);
const leaveChannel = await getChannelById(leaveDatabase, currentCall.channelId);
leaveChannelName = leaveChannel?.displayName || '';
leaveServerUrl = currentCall.serverUrl;
leaveChannelId = currentCall.channelId;
}
} catch (error) {
logError('failed to getServerDatabase in leaveAndJoinWithAlert', error);
return;
}
if (leaveServerUrl && leaveChannelId) {
const {formatMessage} = intl;
let joinMessage = formatMessage({
@ -99,17 +126,24 @@ export const leaveAndJoinWithAlert = (
id: 'mobile.leave_and_join_confirmation',
defaultMessage: 'Leave & Join',
}),
onPress: () => doJoinCall(serverUrl, channelId, isDMorGM, newCall, intl),
onPress: () => doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title),
style: 'cancel',
},
],
);
} else {
doJoinCall(serverUrl, channelId, isDMorGM, newCall, intl);
doJoinCall(joinServerUrl, joinChannelId, joinChannelIsDMorGM, newCall, intl, title);
}
};
const doJoinCall = async (serverUrl: string, channelId: string, isDMorGM: boolean, newCall: boolean, intl: IntlShape) => {
const doJoinCall = async (
serverUrl: string,
channelId: string,
joinChannelIsDMorGM: boolean,
newCall: boolean,
intl: IntlShape,
title?: string,
) => {
const {formatMessage} = intl;
let user;
@ -155,14 +189,14 @@ const doJoinCall = async (serverUrl: string, channelId: string, isDMorGM: boolea
const hasPermission = await hasMicrophonePermission();
setMicPermissionsGranted(hasPermission);
const res = await joinCall(serverUrl, channelId, user.id, hasPermission);
const res = await joinCall(serverUrl, channelId, user.id, hasPermission, title);
if (res.error) {
const seeLogs = formatMessage({id: 'mobile.calls_see_logs', defaultMessage: 'See server logs'});
errorAlert(res.error?.toString() || seeLogs, intl);
return;
}
if (isDMorGM) {
if (joinChannelIsDMorGM) {
// FIXME (MM-46048) - HACK
// There's a race condition between unmuting and receiving existing tracks from other participants.
// Fixing this properly requires extensive and potentially breaking changes.
@ -222,14 +256,7 @@ export const recordingAlert = (isHost: boolean, intl: IntlShape) => {
defaultMessage: 'Leave',
}),
onPress: async () => {
leaveCall();
// Need to pop the call screen, if it's somewhere in the stack.
await dismissAllModals();
if (NavigationStore.getScreensInStack().includes(Screens.CALL)) {
await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call');
Navigation.pop(Screens.CALL).catch(() => null);
}
await leaveCallPopCallScreen();
},
style: 'destructive',
},

View file

@ -27,11 +27,8 @@ type Props = {
author?: UserModel;
isMilitaryTime: boolean;
teammateNameDisplay?: string;
currentCallChannelId?: string;
leaveChannelName?: string;
joinChannelName?: string;
joinChannelIsDMorGM?: boolean;
limitRestrictedInfo?: LimitRestrictedInfo;
ccChannelId?: string;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
@ -113,7 +110,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
export const CallsCustomMessage = ({
post, currentUser, author, isMilitaryTime, teammateNameDisplay,
currentCallChannelId, leaveChannelName, joinChannelName, joinChannelIsDMorGM, limitRestrictedInfo,
ccChannelId, limitRestrictedInfo,
}: Props) => {
const intl = useIntl();
const theme = useTheme();
@ -121,8 +118,7 @@ export const CallsCustomMessage = ({
const serverUrl = useServerUrl();
const timezone = getUserTimezone(currentUser);
const confirmToJoin = Boolean(currentCallChannelId && currentCallChannelId !== post.channelId);
const alreadyInTheCall = Boolean(currentCallChannelId && currentCallChannelId === post.channelId);
const alreadyInTheCall = Boolean(ccChannelId && ccChannelId === post.channelId);
const isLimitRestricted = Boolean(limitRestrictedInfo?.limitRestricted);
const joinHandler = () => {
@ -135,7 +131,7 @@ export const CallsCustomMessage = ({
return;
}
leaveAndJoinWithAlert(intl, serverUrl, post.channelId, leaveChannelName || '', joinChannelName || '', confirmToJoin, false, Boolean(joinChannelIsDMorGM));
leaveAndJoinWithAlert(intl, serverUrl, post.channelId);
};
const title = post.props.title ? (

View file

@ -3,19 +3,16 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {combineLatest, of as of$} from 'rxjs';
import {of as of$} from 'rxjs';
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
import {CallsCustomMessage} from '@calls/components/calls_custom_message/calls_custom_message';
import {observeIsCallLimitRestricted} from '@calls/observers';
import {observeCurrentCall} from '@calls/state';
import {Preferences} from '@constants';
import DatabaseManager from '@database/manager';
import {getPreferenceAsBool} from '@helpers/api/preference';
import {observeChannel} from '@queries/servers/channel';
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
import {observeCurrentUser, observeTeammateNameDisplay, observeUser} from '@queries/servers/user';
import {isDMorGM} from '@utils/channel';
import type {WithDatabaseArgs} from '@typings/database/database';
import type PostModel from '@typings/database/models/servers/post';
@ -43,27 +40,8 @@ const enhanced = withObservables(['post'], ({serverUrl, post, database}: OwnProp
};
}
const ccDatabase = observeCurrentCall().pipe(
switchMap((call) => of$(call?.serverUrl || '')),
distinctUntilChanged(),
switchMap((url) => of$(DatabaseManager.serverDatabases[url]?.database)),
);
const currentCallChannelId = observeCurrentCall().pipe(
switchMap((call) => of$(call?.channelId || '')),
distinctUntilChanged(),
);
const leaveChannelName = combineLatest([ccDatabase, currentCallChannelId]).pipe(
switchMap(([db, id]) => (db && id ? observeChannel(db, id) : of$(undefined))),
switchMap((c) => of$(c ? c.displayName : '')),
distinctUntilChanged(),
);
const joinChannel = observeChannel(database, post.channelId);
const joinChannelName = joinChannel.pipe(
switchMap((chan) => of$(chan?.displayName || '')),
distinctUntilChanged(),
);
const joinChannelIsDMorGM = joinChannel.pipe(
switchMap((chan) => of$(chan ? isDMorGM(chan) : false)),
const ccChannelId = observeCurrentCall().pipe(
switchMap((call) => of$(call?.channelId)),
distinctUntilChanged(),
);
@ -72,11 +50,8 @@ const enhanced = withObservables(['post'], ({serverUrl, post, database}: OwnProp
author,
isMilitaryTime,
teammateNameDisplay: observeTeammateNameDisplay(database),
currentCallChannelId,
leaveChannelName,
joinChannelName,
joinChannelIsDMorGM,
limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, post.channelId),
ccChannelId,
};
});

View file

@ -14,26 +14,18 @@ import type {LimitRestrictedInfo} from '@calls/observers';
export interface Props {
serverUrl: string;
displayName: string;
channelId: string;
channelIsDMorGM: boolean;
isACallInCurrentChannel: boolean;
confirmToJoin: boolean;
alreadyInCall: boolean;
currentCallChannelName: string;
dismissChannelInfo: () => void;
limitRestrictedInfo: LimitRestrictedInfo;
}
const ChannelInfoStartButton = ({
serverUrl,
displayName,
channelId,
channelIsDMorGM,
isACallInCurrentChannel,
confirmToJoin,
alreadyInCall,
currentCallChannelName,
dismissChannelInfo,
limitRestrictedInfo,
}: Props) => {
@ -46,11 +38,11 @@ const ChannelInfoStartButton = ({
} else if (isLimitRestricted) {
showLimitRestrictedAlert(limitRestrictedInfo, intl);
} else {
leaveAndJoinWithAlert(intl, serverUrl, channelId, currentCallChannelName, displayName, confirmToJoin, !isACallInCurrentChannel, channelIsDMorGM);
leaveAndJoinWithAlert(intl, serverUrl, channelId);
}
dismissChannelInfo();
}, [isLimitRestricted, alreadyInCall, dismissChannelInfo, intl, serverUrl, channelId, currentCallChannelName, displayName, confirmToJoin, isACallInCurrentChannel]);
}, [isLimitRestricted, alreadyInCall, dismissChannelInfo, intl, serverUrl, channelId, isACallInCurrentChannel]);
const [tryJoin, msgPostfix] = useTryCallsFunction(toggleJoinLeave);

View file

@ -3,15 +3,12 @@
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {combineLatest, of as of$} from 'rxjs';
import {of as of$} from 'rxjs';
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
import ChannelInfoStartButton from '@calls/components/channel_info_start/channel_info_start_button';
import {observeIsCallLimitRestricted} from '@calls/observers';
import {observeChannelsWithCalls, observeCurrentCall} from '@calls/state';
import DatabaseManager from '@database/manager';
import {observeChannel} from '@queries/servers/channel';
import {isDMorGM} from '@utils/channel';
import type {WithDatabaseArgs} from '@typings/database/database';
@ -21,43 +18,21 @@ type EnhanceProps = WithDatabaseArgs & {
}
const enhanced = withObservables([], ({serverUrl, channelId, database}: EnhanceProps) => {
const channel = observeChannel(database, channelId);
const displayName = channel.pipe(
switchMap((c) => of$(c?.displayName || '')),
distinctUntilChanged(),
);
const channelIsDMorGM = channel.pipe(
switchMap((chan) => of$(chan ? isDMorGM(chan) : false)),
distinctUntilChanged(),
);
const isACallInCurrentChannel = observeChannelsWithCalls(serverUrl).pipe(
switchMap((calls) => of$(Boolean(calls[channelId]))),
distinctUntilChanged(),
);
const ccDatabase = observeCurrentCall().pipe(
switchMap((call) => of$(call?.serverUrl || '')),
distinctUntilChanged(),
switchMap((url) => of$(DatabaseManager.serverDatabases[url]?.database)),
);
const ccChannelId = observeCurrentCall().pipe(
switchMap((call) => of$(call?.channelId)),
distinctUntilChanged(),
);
const confirmToJoin = ccChannelId.pipe(switchMap((ccId) => of$(ccId && ccId !== channelId)));
const alreadyInCall = ccChannelId.pipe(switchMap((ccId) => of$(ccId && ccId === channelId)));
const currentCallChannelName = combineLatest([ccDatabase, ccChannelId]).pipe(
switchMap(([db, id]) => (db && id ? observeChannel(db, id) : of$(undefined))),
switchMap((c) => of$(c?.displayName || '')),
distinctUntilChanged(),
);
return {
displayName,
channelIsDMorGM,
isACallInCurrentChannel,
confirmToJoin,
alreadyInCall,
currentCallChannelName,
limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, channelId),
};
});

View file

@ -8,11 +8,9 @@ import {distinctUntilChanged, switchMap} from 'rxjs/operators';
import JoinCallBanner from '@calls/components/join_call_banner/join_call_banner';
import {observeIsCallLimitRestricted} from '@calls/observers';
import {observeCallsState, observeCurrentCall} from '@calls/state';
import {observeCallsState} from '@calls/state';
import {idsAreEqual} from '@calls/utils';
import {observeChannel} from '@queries/servers/channel';
import {queryUsersById} from '@queries/servers/user';
import {isDMorGM} from '@utils/channel';
import type {WithDatabaseArgs} from '@typings/database/database';
@ -26,15 +24,6 @@ const enhanced = withObservables(['serverUrl', 'channelId'], ({
channelId,
database,
}: OwnProps & WithDatabaseArgs) => {
const channel = observeChannel(database, channelId);
const displayName = channel.pipe(
switchMap((c) => of$(c?.displayName)),
distinctUntilChanged(),
);
const channelIsDMorGM = channel.pipe(
switchMap((chan) => of$(chan ? isDMorGM(chan) : false)),
distinctUntilChanged(),
);
const callsState = observeCallsState(serverUrl);
const participants = callsState.pipe(
switchMap((state) => of$(state.calls[channelId])),
@ -43,30 +32,13 @@ const enhanced = withObservables(['serverUrl', 'channelId'], ({
distinctUntilChanged((prev, curr) => idsAreEqual(prev, curr)), // Continue only if we have a different set of participant ids
switchMap((ids) => (ids.length > 0 ? queryUsersById(database, ids).observeWithColumns(['last_picture_update']) : of$([]))),
);
const currentCallChannelId = observeCurrentCall().pipe(
switchMap((call) => of$(call?.channelId || undefined)),
distinctUntilChanged(),
);
const inACall = currentCallChannelId.pipe(
switchMap((id) => of$(Boolean(id))),
distinctUntilChanged(),
);
const currentCallChannelName = currentCallChannelId.pipe(
switchMap((id) => observeChannel(database, id || '')),
switchMap((c) => of$(c ? c.displayName : '')),
distinctUntilChanged(),
);
const channelCallStartTime = callsState.pipe(
switchMap((cs) => of$(cs.calls[channelId]?.startTime || 0)),
distinctUntilChanged(),
);
return {
displayName,
channelIsDMorGM,
participants,
inACall,
currentCallChannelName,
channelCallStartTime,
limitRestrictedInfo: observeIsCallLimitRestricted(database, serverUrl, channelId),
};

View file

@ -21,11 +21,7 @@ import type UserModel from '@typings/database/models/servers/user';
type Props = {
channelId: string;
serverUrl: string;
displayName: string;
channelIsDMorGM: boolean;
inACall: boolean;
participants: UserModel[];
currentCallChannelName: string;
channelCallStartTime: number;
limitRestrictedInfo: LimitRestrictedInfo;
}
@ -86,11 +82,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
const JoinCallBanner = ({
channelId,
serverUrl,
displayName,
channelIsDMorGM,
participants,
inACall,
currentCallChannelName,
channelCallStartTime,
limitRestrictedInfo,
}: Props) => {
@ -104,7 +96,7 @@ const JoinCallBanner = ({
showLimitRestrictedAlert(limitRestrictedInfo, intl);
return;
}
leaveAndJoinWithAlert(intl, serverUrl, channelId, currentCallChannelName, displayName, inACall, false, channelIsDMorGM);
leaveAndJoinWithAlert(intl, serverUrl, channelId);
};
return (

View file

@ -32,6 +32,7 @@ export async function newConnection(
closeCb: () => void,
setScreenShareURL: (url: string) => void,
hasMicPermission: boolean,
title?: string,
) {
let peer: Peer | null = null;
let stream: MediaStream;
@ -250,6 +251,7 @@ export async function newConnection(
} else {
ws.send('join', {
channelID,
title,
});
}
});

View file

@ -408,6 +408,7 @@
"mobile.calls_not_available_msg": "Please contact your System Admin to enable the feature.",
"mobile.calls_not_available_option": "(Not available)",
"mobile.calls_not_available_title": "Calls is not enabled",
"mobile.calls_not_connected": "You're not connected to a call in the current channel.",
"mobile.calls_ok": "OK",
"mobile.calls_okay": "Okay",
"mobile.calls_open_channel": "Open Channel",
@ -423,6 +424,7 @@
"mobile.calls_see_logs": "See server logs",
"mobile.calls_speaker": "Speaker",
"mobile.calls_start_call": "Start Call",
"mobile.calls_start_call_exists": "A call is already ongoing in the channel.",
"mobile.calls_stop_recording": "Stop Recording",
"mobile.calls_unmute": "Unmute",
"mobile.calls_viewing_screen": "You are viewing {name}'s screen",