MM-48836 - Calls: handle slash commands (#6980)
This commit is contained in:
parent
e140a12b6c
commit
9a89259e96
12 changed files with 200 additions and 194 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export {
|
|||
raiseHand,
|
||||
unraiseHand,
|
||||
setSpeakerphoneOn,
|
||||
handleCallsSlashCommand,
|
||||
} from './calls';
|
||||
|
||||
export {hasMicrophonePermission} from './permissions';
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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 ? (
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue