forked from Ivasoft/mattermost-mobile
MM-45754 - Calls: Add current call bar to thread screen (#6628)
* remove isCallsPluginEnabled; add current call bar to thread screen * popTo thread/call screen; updateProps in dismissAllModalsAndPopToScreen * remove unneeded withServerUrl; only updateProps if needed
This commit is contained in:
committed by
GitHub
parent
bb051b83b9
commit
67342246eb
@@ -13,7 +13,7 @@ import CompassIcon from '@components/compass_icon';
|
||||
import {Events, Screens, WebsocketEvents} from '@constants';
|
||||
import {CURRENT_CALL_BAR_HEIGHT} from '@constants/view';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {goToScreen} from '@screens/navigation';
|
||||
import {dismissAllModalsAndPopToScreen} from '@screens/navigation';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {displayUsername} from '@utils/user';
|
||||
|
||||
@@ -24,6 +24,7 @@ type Props = {
|
||||
currentCall: CurrentCall | null;
|
||||
userModelsDict: Dictionary<UserModel>;
|
||||
teammateNameDisplay: string;
|
||||
threadScreen?: boolean;
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
@@ -85,6 +86,7 @@ const CurrentCallBar = ({
|
||||
currentCall,
|
||||
userModelsDict,
|
||||
teammateNameDisplay,
|
||||
threadScreen,
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const {formatMessage} = useIntl();
|
||||
@@ -128,7 +130,7 @@ const CurrentCallBar = ({
|
||||
}
|
||||
}, [speaker, setTalkingMessage]);
|
||||
|
||||
const goToCallScreen = useCallback(() => {
|
||||
const goToCallScreen = useCallback(async () => {
|
||||
const options: Options = {
|
||||
layout: {
|
||||
backgroundColor: '#000',
|
||||
@@ -143,8 +145,8 @@ const CurrentCallBar = ({
|
||||
},
|
||||
};
|
||||
const title = formatMessage({id: 'mobile.calls_call_screen', defaultMessage: 'Call'});
|
||||
goToScreen(Screens.CALL, title, {}, options);
|
||||
}, []);
|
||||
await dismissAllModalsAndPopToScreen(Screens.CALL, title, {fromThreadScreen: threadScreen}, options);
|
||||
}, [formatMessage, threadScreen]);
|
||||
|
||||
const myParticipant = currentCall?.participants[currentCall.myUserId];
|
||||
|
||||
|
||||
@@ -29,12 +29,13 @@ const style = StyleSheet.create({
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
threadScreen?: boolean;
|
||||
}
|
||||
|
||||
const FloatingCallContainer = (props: Props) => {
|
||||
const FloatingCallContainer = ({threadScreen, ...props}: Props) => {
|
||||
const insets = useSafeAreaInsets();
|
||||
const wrapperTop = {
|
||||
top: topBarHeight + insets.top,
|
||||
top: insets.top + (threadScreen ? 0 : topBarHeight),
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -38,7 +38,13 @@ import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
||||
import {WebsocketEvents, Screens} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {bottomSheet, dismissBottomSheet, goToScreen, popTopScreen} from '@screens/navigation';
|
||||
import {
|
||||
bottomSheet,
|
||||
dismissAllModalsAndPopToScreen,
|
||||
dismissBottomSheet,
|
||||
goToScreen,
|
||||
popTopScreen,
|
||||
} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {bottomSheetSnapPoint} from '@utils/helpers';
|
||||
import {mergeNavigationOptions} from '@utils/navigation';
|
||||
@@ -50,6 +56,7 @@ export type Props = {
|
||||
currentCall: CurrentCall | null;
|
||||
participantsDict: Dictionary<CallParticipant>;
|
||||
teammateNameDisplay: string;
|
||||
fromThreadScreen?: boolean;
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
@@ -247,18 +254,20 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDisplay}: Props) => {
|
||||
const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDisplay, fromThreadScreen}: Props) => {
|
||||
const intl = useIntl();
|
||||
const theme = useTheme();
|
||||
const insets = useSafeAreaInsets();
|
||||
const {width, height} = useWindowDimensions();
|
||||
const isLandscape = width > height;
|
||||
const [showControlsInLandscape, setShowControlsInLandscape] = useState(false);
|
||||
const myParticipant = currentCall?.participants[currentCall.myUserId];
|
||||
const style = getStyleSheet(theme);
|
||||
const showControls = !isLandscape || showControlsInLandscape;
|
||||
const [speakers, setSpeakers] = useState<Dictionary<boolean>>({});
|
||||
|
||||
const style = getStyleSheet(theme);
|
||||
const isLandscape = width > height;
|
||||
const showControls = !isLandscape || showControlsInLandscape;
|
||||
const myParticipant = currentCall?.participants[currentCall.myUserId];
|
||||
const chatThreadTitle = intl.formatMessage({id: 'mobile.calls_chat_thread', defaultMessage: 'Chat thread'});
|
||||
|
||||
useEffect(() => {
|
||||
mergeNavigationOptions('Call', {
|
||||
layout: {
|
||||
@@ -329,17 +338,20 @@ const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDis
|
||||
|
||||
const activeUrl = await DatabaseManager.getActiveServerUrl();
|
||||
if (activeUrl === currentCall.serverUrl) {
|
||||
goToScreen(Screens.THREAD, '', {rootId: currentCall.threadId});
|
||||
await dismissAllModalsAndPopToScreen(Screens.THREAD, chatThreadTitle, {rootId: currentCall.threadId});
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: this is a temporary solution until we have a proper cross-team thread view.
|
||||
// https://mattermost.atlassian.net/browse/MM-45752
|
||||
popTopScreen(componentId);
|
||||
await popTopScreen(componentId);
|
||||
if (fromThreadScreen) {
|
||||
await popTopScreen(Screens.THREAD);
|
||||
}
|
||||
await DatabaseManager.setActiveServerDatabase(currentCall.serverUrl);
|
||||
await appEntry(currentCall.serverUrl, Date.now());
|
||||
goToScreen(Screens.THREAD, '', {rootId: currentCall.threadId});
|
||||
}, [currentCall?.serverUrl, currentCall?.threadId]);
|
||||
await goToScreen(Screens.THREAD, chatThreadTitle, {rootId: currentCall.threadId});
|
||||
}, [currentCall?.serverUrl, currentCall?.threadId, fromThreadScreen, componentId, chatThreadTitle]);
|
||||
|
||||
const showOtherActions = useCallback(() => {
|
||||
const renderContent = () => {
|
||||
@@ -348,7 +360,7 @@ const CallScreen = ({componentId, currentCall, participantsDict, teammateNameDis
|
||||
<SlideUpPanelItem
|
||||
icon='message-text-outline'
|
||||
onPress={switchToThread}
|
||||
text={intl.formatMessage({id: 'mobile.calls_chat_thread', defaultMessage: 'Chat thread'})}
|
||||
text={chatThreadTitle}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -28,7 +28,6 @@ type ChannelProps = {
|
||||
serverUrl: string;
|
||||
channelId: string;
|
||||
componentId?: string;
|
||||
isCallsPluginEnabled: boolean;
|
||||
isCallInCurrentChannel: boolean;
|
||||
isInACall: boolean;
|
||||
isInCurrentChannelCall: boolean;
|
||||
@@ -47,7 +46,6 @@ const Channel = ({
|
||||
serverUrl,
|
||||
channelId,
|
||||
componentId,
|
||||
isCallsPluginEnabled,
|
||||
isCallInCurrentChannel,
|
||||
isInACall,
|
||||
isInCurrentChannelCall,
|
||||
@@ -120,7 +118,7 @@ const Channel = ({
|
||||
|
||||
let callsComponents: JSX.Element | null = null;
|
||||
const showJoinCallBanner = isCallInCurrentChannel && !isInCurrentChannelCall;
|
||||
if (isCallsPluginEnabled && (showJoinCallBanner || isInACall)) {
|
||||
if (showJoinCallBanner || isInACall) {
|
||||
callsComponents = (
|
||||
<FloatingCallContainer>
|
||||
{showJoinCallBanner &&
|
||||
|
||||
@@ -20,10 +20,6 @@ type EnhanceProps = WithDatabaseArgs & {
|
||||
|
||||
const enhanced = withObservables([], ({database, serverUrl}: EnhanceProps) => {
|
||||
const channelId = observeCurrentChannelId(database);
|
||||
const isCallsPluginEnabled = observeCallsConfig(serverUrl).pipe(
|
||||
switchMap((config) => of$(config.pluginEnabled)),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
const isCallInCurrentChannel = combineLatest([channelId, observeChannelsWithCalls(serverUrl)]).pipe(
|
||||
switchMap(([id, calls]) => of$(Boolean(calls[id]))),
|
||||
distinctUntilChanged(),
|
||||
@@ -60,7 +56,6 @@ const enhanced = withObservables([], ({database, serverUrl}: EnhanceProps) => {
|
||||
|
||||
return {
|
||||
channelId,
|
||||
isCallsPluginEnabled,
|
||||
isCallInCurrentChannel,
|
||||
isInACall,
|
||||
isInCurrentChannelCall,
|
||||
|
||||
@@ -403,7 +403,7 @@ export async function dismissAllModalsAndPopToRoot() {
|
||||
* (if the screen is not in the stack, it will push a new one)
|
||||
* @param screenId Screen to pop or display
|
||||
* @param title Title to be shown in the top bar
|
||||
* @param passProps Props to pass to the screen (Only if the screen does not exist in the stack)
|
||||
* @param passProps Props to pass to the screen
|
||||
* @param options Navigation options
|
||||
*/
|
||||
export async function dismissAllModalsAndPopToScreen(screenId: string, title: string, passProps = {}, options = {}) {
|
||||
@@ -421,6 +421,9 @@ export async function dismissAllModalsAndPopToScreen(screenId: string, title: st
|
||||
}
|
||||
try {
|
||||
await Navigation.popTo(screenId, mergeOptions);
|
||||
if (Object.keys(passProps).length > 0) {
|
||||
await Navigation.updateProps(screenId, passProps);
|
||||
}
|
||||
} catch {
|
||||
// catch in case there is nothing to pop
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeCurrentCall} from '@calls/state';
|
||||
import {observePost} from '@queries/servers/post';
|
||||
|
||||
import Thread from './thread';
|
||||
@@ -11,8 +14,14 @@ import Thread from './thread';
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
const enhanced = withObservables(['rootId'], ({database, rootId}: WithDatabaseArgs & {rootId: string}) => {
|
||||
const isInACall = observeCurrentCall().pipe(
|
||||
switchMap((call) => of$(Boolean(call))),
|
||||
distinctUntilChanged(),
|
||||
);
|
||||
|
||||
return {
|
||||
rootPost: observePost(database, rootId),
|
||||
isInACall,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import {DeviceEventEmitter, LayoutChangeEvent, StyleSheet, View} from 'react-nat
|
||||
import {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view';
|
||||
import {Edge, SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import CurrentCallBar from '@calls/components/current_call_bar';
|
||||
import FloatingCallContainer from '@calls/components/floating_call_container';
|
||||
import FreezeScreen from '@components/freeze_screen';
|
||||
import PostDraft from '@components/post_draft';
|
||||
import RoundedHeaderContext from '@components/rounded_header_context';
|
||||
@@ -23,6 +25,7 @@ import type PostModel from '@typings/database/models/servers/post';
|
||||
type ThreadProps = {
|
||||
componentId: string;
|
||||
rootPost?: PostModel;
|
||||
isInACall: boolean;
|
||||
};
|
||||
|
||||
const edges: Edge[] = ['left', 'right'];
|
||||
@@ -31,7 +34,7 @@ const styles = StyleSheet.create({
|
||||
flex: {flex: 1},
|
||||
});
|
||||
|
||||
const Thread = ({componentId, rootPost}: ThreadProps) => {
|
||||
const Thread = ({componentId, rootPost, isInACall}: ThreadProps) => {
|
||||
const appState = useAppState();
|
||||
const postDraftRef = useRef<KeyboardTrackingViewRef>(null);
|
||||
const [containerHeight, setContainerHeight] = useState(0);
|
||||
@@ -96,6 +99,11 @@ const Thread = ({componentId, rootPost}: ThreadProps) => {
|
||||
/>
|
||||
</>
|
||||
}
|
||||
{isInACall &&
|
||||
<FloatingCallContainer threadScreen={true}>
|
||||
<CurrentCallBar threadScreen={true}/>
|
||||
</FloatingCallContainer>
|
||||
}
|
||||
</SafeAreaView>
|
||||
</FreezeScreen>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user