Skip to content
This repository has been archived by the owner on May 16, 2024. It is now read-only.

[MV-405] Fix deeplinking when app is in background #93

Merged
merged 2 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions example/patches/@react-navigation+stack+6.3.16.patch
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ index 77f48cd..593a3d3 100644
* Function which returns a React Element to display custom image in header's back button.
* It receives the `tintColor` in in the options object as an argument. object.
diff --git a/node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx b/node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx
index 4d4848f..beab2df 100755
index 4d4848f..c19026a 100755
--- a/node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx
+++ b/node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx
@@ -18,6 +18,8 @@ import {
Expand Down Expand Up @@ -41,7 +41,19 @@ index 4d4848f..beab2df 100755
optionsForTransitionConfig.presentation === 'modal'
? ModalTransition
: optionsForTransitionConfig.presentation === 'transparentModal'
@@ -499,12 +499,18 @@ export default class CardStack extends React.Component<Props, State> {
@@ -470,6 +470,11 @@ export default class CardStack extends React.Component<Props, State> {
return undefined;
};

+ private lastActivityStateForIndex: Record<
+ number,
+ number | Animated.AnimatedInterpolation<number>
+ > = {};
+
render() {
const {
insets,
@@ -499,12 +504,18 @@ export default class CardStack extends React.Component<Props, State> {

const isFloatHeaderAbsolute = this.state.scenes.slice(-2).some((scene) => {
const options = scene.descriptor.options ?? {};
Expand All @@ -62,3 +74,38 @@ index 4d4848f..beab2df 100755
) {
return true;
}
@@ -585,15 +596,23 @@ export default class CardStack extends React.Component<Props, State> {
// For the old implementation, it stays the same it was
let isScreenActive: Animated.AnimatedInterpolation | 2 | 1 | 0 = 1;

- if (index < self.length - activeScreensLimit - 1) {
+ const activeAfterTransition =
+ index >= self.length - activeScreensLimit;
+
+ if (
+ index < self.length - activeScreensLimit - 1 ||
+ (this.lastActivityStateForIndex[index] === STATE_INACTIVE &&
+ !activeAfterTransition)
+ ) {
// screen should be inactive because it is too deep in the stack
+ // or it was inactive before and it will still be inactive after the transition.
isScreenActive = STATE_INACTIVE;
} else {
const sceneForActivity = scenes[self.length - 1];
const outputValue =
index === self.length - 1
? STATE_ON_TOP // the screen is on top after the transition
- : index >= self.length - activeScreensLimit
+ : activeAfterTransition
? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
: STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
isScreenActive = sceneForActivity
@@ -605,6 +624,8 @@ export default class CardStack extends React.Component<Props, State> {
: STATE_TRANSITIONING_OR_BELOW_TOP;
}

+ this.lastActivityStateForIndex[index] = isScreenActive;
+
const {
headerShown = true,
headerTransparent,
88 changes: 42 additions & 46 deletions example/src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import { Preview } from '@screens/Preview';
import { Room } from '@screens/Room';
import React from 'react';

import { useVideoroomState } from './VideoroomContext';

const linking = {
prefixes: [VIDEOROOM_URL],
config: {
initialRouteName: 'InitialScreen' as const,
screens: {
InitialScreen: {},
JoinRoom: {
path: ':roomName',
parse: {
Expand All @@ -24,6 +24,10 @@ const linking = {
},
},
},
// a hack - reset the stack instead of navigating
getActionFromState: () => {
return undefined;
},
};

const navTheme = {
Expand All @@ -37,7 +41,6 @@ const navTheme = {
const Stack = createStackNavigator<RootStack>();

export const Navigation = () => {
const { videoroomState } = useVideoroomState();
return (
<NavigationContainer linking={linking} theme={navTheme}>
<Stack.Navigator
Expand All @@ -50,49 +53,42 @@ export const Navigation = () => {
cardStyle: { backgroundColor: 'transparent' },
}}
>
{videoroomState === 'InMeeting' || videoroomState === 'AfterMeeting' ? (
<>
<Stack.Screen
name="Room"
component={Room}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="LeaveRoom"
component={LeaveRoomScreen}
options={{
headerShown: false,
}}
/>
</>
) : (
<>
<Stack.Screen
name="InitialScreen"
component={InitialScreen}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="CreateRoom"
component={CreateRoom}
options={{
title: 'New meeting',
}}
/>
<Stack.Screen
name="JoinRoom"
component={JoinRoom}
options={{
title: 'Join meeting',
}}
/>
<Stack.Screen name="Preview" component={Preview} />
</>
)}
<Stack.Screen
name="Room"
component={Room}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="LeaveRoom"
component={LeaveRoomScreen}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="InitialScreen"
component={InitialScreen}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="CreateRoom"
component={CreateRoom}
options={{
title: 'New meeting',
}}
/>
<Stack.Screen
name="JoinRoom"
component={JoinRoom}
options={{
title: 'Join meeting',
}}
/>
<Stack.Screen name="Preview" component={Preview} />
</Stack.Navigator>
</NavigationContainer>
);
Expand Down
21 changes: 12 additions & 9 deletions example/src/components/DiscardModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,19 @@ type DiscardModalProps = {
headline: string;
body: string;
buttonText: string;
handleBeforeRemoveEvent: (
e: GoBackAction,
setIsModalVisible: (isVisible: boolean) => void
) => void;
onDiscard?: () => void;
};

export const DiscardModal = ({
headline,
body,
buttonText,
handleBeforeRemoveEvent,
onDiscard = () => {},
}: DiscardModalProps) => {
const navigation = useNavigation();
const { roomName, setRoomName, username, setUsername } = useVideoroomState();
Expand All @@ -29,20 +36,15 @@ export const DiscardModal = ({

useFocusEffect(
useCallback(() => {
const handleBeforeRemoveEvent = (e) => {
if (!roomName && !username) {
// If we don't have unsaved changes, then we don't need to do anything
return;
}
e.preventDefault();
const _handleBeforeRemoveEvent = (e) => {
handleBeforeRemoveEvent(e, setIsModalVisible);
modalAction.current = e.data.action;
setIsModalVisible(true);
};

navigation.addListener('beforeRemove', handleBeforeRemoveEvent);
navigation.addListener('beforeRemove', _handleBeforeRemoveEvent);

return () =>
navigation.removeListener('beforeRemove', handleBeforeRemoveEvent);
navigation.removeListener('beforeRemove', _handleBeforeRemoveEvent);
}, [navigation, roomName, username])
);

Expand All @@ -60,6 +62,7 @@ export const DiscardModal = ({
setRoomName('');
setUsername('');
navigation.dispatch(modalAction.current!);
onDiscard();
}}
>
{buttonText}
Expand Down
10 changes: 10 additions & 0 deletions example/src/screens/CreateRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ export const CreateRoom = ({ navigation, route }: Props) => {
navigation.push('Preview', { title: 'New meeting' });
};

const handleBeforeRemoveEvent = (e, setIsModalVisible) => {
if (!roomName && !username) {
// If we don't have unsaved changes, then we don't need to do anything
return;
}
e.preventDefault();
setIsModalVisible(true);
};

return (
<BackgroundAnimation>
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
Expand All @@ -69,6 +78,7 @@ export const CreateRoom = ({ navigation, route }: Props) => {
headline="Discard meeting"
body="Are you sure you want to discard creation of this meeting?"
buttonText="Yes, discard meeting"
handleBeforeRemoveEvent={handleBeforeRemoveEvent}
/>
<View style={styles.inner}>
<View>
Expand Down
10 changes: 10 additions & 0 deletions example/src/screens/JoinRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ export const JoinRoom = ({ navigation, route }: Props) => {
navigation.push('Preview', { title: 'Join meeting' });
};

const handleBeforeRemoveEvent = (e, setIsModalVisible) => {
if (!roomName && !username) {
// If we don't have unsaved changes, then we don't need to do anything
return;
}
e.preventDefault();
setIsModalVisible(true);
};

return (
<BackgroundAnimation>
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
Expand All @@ -84,6 +93,7 @@ export const JoinRoom = ({ navigation, route }: Props) => {
headline="Cancel joining meeting"
body="Are you sure you want to cancel joining to this meeting?"
buttonText="Yes, don't join"
handleBeforeRemoveEvent={handleBeforeRemoveEvent}
/>
<View style={styles.inner}>
<View>
Expand Down
7 changes: 6 additions & 1 deletion example/src/screens/LeaveRoomScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export const LeaveRoomScreen = ({ navigation }: Props) => {
}
}, [connectAndJoinRoom]);

const onMainScreenPress = useCallback(() => {
navigation.navigate('InitialScreen');
goToMainScreen();
}, []);

return (
<BackgroundAnimation>
<View style={styles.content}>
Expand All @@ -40,7 +45,7 @@ export const LeaveRoomScreen = ({ navigation }: Props) => {
</Typo>

<View style={styles.mainButton}>
<StandardButton onPress={goToMainScreen}>Main page</StandardButton>
<StandardButton onPress={onMainScreenPress}>Main page</StandardButton>
</View>
<View style={styles.rejoinButton}>
<StandardButton type="secondary" onPress={rejoinMeeting}>
Expand Down
1 change: 1 addition & 0 deletions example/src/screens/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const Preview = ({ navigation, route }: Props) => {
const onConnectPress = useCallback(async () => {
try {
await connectAndJoinRoom();
navigation.navigate('Room');
} catch (err) {
showNotification('Error connecting to server', 'error');
Sentry.captureException(err);
Expand Down
24 changes: 22 additions & 2 deletions example/src/screens/Room.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BrandColors } from '@colors';
import { BackgroundAnimation } from '@components/BackgroundAnimation';
import { DiscardModal } from '@components/DiscardModal';
import { FocusedParticipant } from '@components/FocusedParticipant';
import { Icon } from '@components/Icon';
import {
Expand All @@ -9,7 +10,9 @@ import {
import { Participants } from '@components/Participants';
import { Typo } from '@components/Typo';
import * as Membrane from '@jellyfish-dev/react-native-membrane-webrtc';
import { RootStack } from '@model/NavigationTypes';
import { useFocusEffect } from '@react-navigation/native';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import React, { useCallback, useEffect, useState } from 'react';
import { StyleSheet, View, InteractionManager } from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
Expand All @@ -19,8 +22,10 @@ import { useVideoroomState } from 'src/VideoroomContext';

import { CallControls } from '../components/CallControls';

export const Room = () => {
const { roomName } = useVideoroomState();
type Props = NativeStackScreenProps<RootStack, 'Room'>;

export const Room = ({ navigation }: Props) => {
const { roomName, disconnect } = useVideoroomState();

const participants = Membrane.useRoomParticipants();
const [focusedParticipantData, setFocusedParticipantData] =
Expand Down Expand Up @@ -111,8 +116,23 @@ export const Room = () => {
Membrane.flipCamera();
}, []);

const handleBeforeRemoveEvent = (e, setIsModalVisible) => {
e.preventDefault();
// reset action comes from deeplink
if (e.data.action.type === 'RESET') {
setIsModalVisible(true);
}
};

return (
<BackgroundAnimation>
<DiscardModal
headline="Leave room"
body="Are you sure you want to leave this room?"
buttonText="Yes, leave room"
handleBeforeRemoveEvent={handleBeforeRemoveEvent}
onDiscard={disconnect}
/>
<View style={styles.container}>
<SafeAreaView style={{ flex: 1 }} edges={['bottom']}>
<View style={styles.header}>
Expand Down