Improved screen changing performances and removed tab screen animations

This commit is contained in:
Arnaud Vergnet 2020-04-20 19:27:23 +02:00
parent da92856478
commit 01e3195be7
10 changed files with 79 additions and 151 deletions

15
App.js
View file

@ -9,7 +9,6 @@ import {AppLoading} from 'expo';
import type {CustomTheme} from "./src/managers/ThemeManager"; import type {CustomTheme} from "./src/managers/ThemeManager";
import ThemeManager from './src/managers/ThemeManager'; import ThemeManager from './src/managers/ThemeManager';
import {NavigationContainer} from '@react-navigation/native'; import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
import DrawerNavigator from './src/navigation/DrawerNavigator'; import DrawerNavigator from './src/navigation/DrawerNavigator';
import {initExpoToken} from "./src/utils/Notifications"; import {initExpoToken} from "./src/utils/Notifications";
import {Provider as PaperProvider} from 'react-native-paper'; import {Provider as PaperProvider} from 'react-native-paper';
@ -18,6 +17,11 @@ import Update from "./src/constants/Update";
import ConnectionManager from "./src/managers/ConnectionManager"; import ConnectionManager from "./src/managers/ConnectionManager";
import URLHandler from "./src/utils/URLHandler"; import URLHandler from "./src/utils/URLHandler";
import {setSafeBounceHeight} from "react-navigation-collapsible"; import {setSafeBounceHeight} from "react-navigation-collapsible";
import {enableScreens} from 'react-native-screens';
// Native optimizations https://reactnavigation.org/docs/react-native-screens
enableScreens();
YellowBox.ignoreWarnings([ // collapsible headers cause this warning, just ignore as it is not an issue YellowBox.ignoreWarnings([ // collapsible headers cause this warning, just ignore as it is not an issue
'Non-serializable values were found in the navigation state', 'Non-serializable values were found in the navigation state',
@ -33,8 +37,6 @@ type State = {
currentTheme: CustomTheme | null, currentTheme: CustomTheme | null,
}; };
const Stack = createStackNavigator();
export default class App extends React.Component<Props, State> { export default class App extends React.Component<Props, State> {
state = { state = {
@ -190,9 +192,10 @@ export default class App extends React.Component<Props, State> {
return ( return (
<PaperProvider theme={this.state.currentTheme}> <PaperProvider theme={this.state.currentTheme}>
<NavigationContainer theme={this.state.currentTheme} ref={this.navigatorRef}> <NavigationContainer theme={this.state.currentTheme} ref={this.navigatorRef}>
<Stack.Navigator headerMode="none"> <DrawerNavigator
<Stack.Screen name="Root" component={this.createDrawerNavigator}/> defaultHomeRoute={this.defaultHomeRoute}
</Stack.Navigator> defaultHomeData={this.defaultHomeData}
/>
</NavigationContainer> </NavigationContainer>
</PaperProvider> </PaperProvider>
); );

View file

@ -1,55 +0,0 @@
// @flow
import * as React from 'react';
import * as Animatable from "react-native-animatable";
import {CommonActions} from "@react-navigation/native";
import {StackNavigationProp} from "@react-navigation/stack";
type Props = {
navigation: StackNavigationProp,
route: { params?: any, ... },
children: React.Node
}
export default class AnimatedFocusView extends React.Component<Props> {
ref: { current: null | Animatable.View };
constructor() {
super();
this.ref = React.createRef();
}
componentDidMount() {
this.props.navigation.addListener('focus', this.onScreenFocus);
}
onScreenFocus = () => {
if (this.props.route.params != null) {
if (this.props.route.params.animationDir && this.ref.current) {
if (this.props.route.params.animationDir === "right")
this.ref.current.fadeInRight(300);
else
this.ref.current.fadeInLeft(300);
// reset params to prevent infinite loop
this.props.navigation.dispatch(CommonActions.setParams({animationDir: null}));
}
}
};
render() {
return (
<Animatable.View
ref={this.ref}
style={{
width: "100%",
height: "100%",
}}
useNativeDriver
>
{this.props.children}
</Animatable.View>
);
}
}

View file

@ -7,18 +7,19 @@ import {TouchableRipple} from "react-native-paper";
import ConnectionManager from "../../managers/ConnectionManager"; import ConnectionManager from "../../managers/ConnectionManager";
import LogoutDialog from "../Amicale/LogoutDialog"; import LogoutDialog from "../Amicale/LogoutDialog";
import SideBarSection from "./SideBarSection"; import SideBarSection from "./SideBarSection";
import {DrawerNavigationProp} from "@react-navigation/drawer";
const deviceWidth = Dimensions.get("window").width; const deviceWidth = Dimensions.get("window").width;
type Props = { type Props = {
navigation: Object, navigation: DrawerNavigationProp,
state: {[key: string] : any},
theme?: Object, theme?: Object,
}; };
type State = { type State = {
isLoggedIn: boolean, isLoggedIn: boolean,
dialogVisible: boolean, dialogVisible: boolean,
activeRoute: string;
}; };
/** /**
@ -27,7 +28,7 @@ type State = {
class SideBar extends React.Component<Props, State> { class SideBar extends React.Component<Props, State> {
dataSet: Array<Object>; dataSet: Array<Object>;
activeRoute: string;
/** /**
* Generate the dataset * Generate the dataset
* *
@ -35,6 +36,7 @@ class SideBar extends React.Component<Props, State> {
*/ */
constructor(props: Props) { constructor(props: Props) {
super(props); super(props);
this.activeRoute = 'main';
// Dataset used to render the drawer // Dataset used to render the drawer
const mainData = [ const mainData = [
{ {
@ -179,27 +181,23 @@ class SideBar extends React.Component<Props, State> {
}, },
]; ];
ConnectionManager.getInstance().addLoginStateListener(this.onLoginStateChange); ConnectionManager.getInstance().addLoginStateListener(this.onLoginStateChange);
this.props.navigation.addListener('state', this.onRouteChange);
this.state = { this.state = {
isLoggedIn: ConnectionManager.getInstance().isLoggedIn(), isLoggedIn: ConnectionManager.getInstance().isLoggedIn(),
dialogVisible: false, dialogVisible: false,
activeRoute: 'Main',
}; };
} }
onRouteChange = (event: Object) => { shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
try { const nextNavigationState = nextProps.state;
const state = event.data.state.routes[0].state; // Get the Drawer's state if it exists const nextRoute = nextNavigationState.routes[nextNavigationState.index].name;
// Get the current route name. This will only show Drawer routes.
// Tabbar routes will be shown as 'Main'
const routeName = state.routeNames[state.index];
if (this.state.activeRoute !== routeName)
this.setState({activeRoute: routeName});
} catch (e) {
this.setState({activeRoute: 'Main'});
}
}; const currentNavigationState = this.props.state;
const currentRoute = currentNavigationState.routes[currentNavigationState.index].name;
this.activeRoute = nextRoute;
return (nextState !== this.state)
|| (nextRoute !== currentRoute);
}
showDisconnectDialog = () => this.setState({dialogVisible: true}); showDisconnectDialog = () => this.setState({dialogVisible: true});
@ -217,7 +215,7 @@ class SideBar extends React.Component<Props, State> {
return <SideBarSection return <SideBarSection
{...this.props} {...this.props}
listKey={item.key} listKey={item.key}
activeRoute={this.state.activeRoute} activeRoute={this.activeRoute}
isLoggedIn={this.state.isLoggedIn} isLoggedIn={this.state.isLoggedIn}
sectionName={item.name} sectionName={item.name}
startOpen={item.startOpen} startOpen={item.startOpen}
@ -239,7 +237,7 @@ class SideBar extends React.Component<Props, State> {
{/*$FlowFixMe*/} {/*$FlowFixMe*/}
<FlatList <FlatList
data={this.dataSet} data={this.dataSet}
extraData={this.state.isLoggedIn.toString() + this.state.activeRoute} extraData={this.state.isLoggedIn.toString() + this.activeRoute}
renderItem={this.getRenderItem} renderItem={this.getRenderItem}
/> />
<LogoutDialog <LogoutDialog

View file

@ -61,10 +61,7 @@ class CustomTabBar extends React.Component<Props, State> {
}); });
if (currentIndex !== destIndex && !event.defaultPrevented) { if (currentIndex !== destIndex && !event.defaultPrevented) {
this.state.translateY = new Animated.Value(0); this.state.translateY = new Animated.Value(0);
this.props.navigation.navigate(route.name, { this.props.navigation.navigate(route.name);
screen: 'index',
params: {animationDir: currentIndex < destIndex ? "right" : "left"}
});
} }
} }

View file

@ -541,7 +541,10 @@ export default class DrawerNavigator extends React.Component<Props> {
this.createTabNavigator = () => <TabNavigator {...props}/> this.createTabNavigator = () => <TabNavigator {...props}/>
} }
getDrawerContent = (props: { navigation: DrawerNavigationProp }) => <Sidebar {...props}/> getDrawerContent = (props: {
navigation: DrawerNavigationProp,
state: {[key: string] : any}
}) => <Sidebar {...props}/>
render() { render() {
return ( return (

View file

@ -15,9 +15,9 @@ import ConnectionManager from "../../managers/ConnectionManager";
import {CommonActions} from '@react-navigation/native'; import {CommonActions} from '@react-navigation/native';
import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton"; import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
import AnimatedFAB from "../../components/Animations/AnimatedFAB"; import AnimatedFAB from "../../components/Animations/AnimatedFAB";
import AnimatedFocusView from "../../components/Animations/AnimatedFocusView";
import {StackNavigationProp} from "@react-navigation/stack"; import {StackNavigationProp} from "@react-navigation/stack";
import type {CustomTheme} from "../../managers/ThemeManager"; import type {CustomTheme} from "../../managers/ThemeManager";
import {View} from "react-native-animatable";
// import DATA from "../dashboard_data.json"; // import DATA from "../dashboard_data.json";
@ -166,17 +166,11 @@ class HomeScreen extends React.Component<Props> {
}; };
onProxiwashClick = () => { onProxiwashClick = () => {
this.props.navigation.navigate("proxiwash", { this.props.navigation.navigate("proxiwash");
screen: 'index',
params: {animationDir: "right"} // Play tab animation
});
}; };
onProximoClick = () => { onProximoClick = () => {
this.props.navigation.navigate("proximo", { this.props.navigation.navigate("proximo");
screen: 'index',
params: {animationDir: "left"} // Play tab animation
});
}; };
onTutorInsaClick = () => this.props.navigation.navigate('tutorinsa'); onTutorInsaClick = () => this.props.navigation.navigate('tutorinsa');
@ -513,8 +507,8 @@ class HomeScreen extends React.Component<Props> {
render() { render() {
return ( return (
<AnimatedFocusView <View
{...this.props} style={{flex: 1}}
> >
<WebSectionList <WebSectionList
{...this.props} {...this.props}
@ -532,7 +526,7 @@ class HomeScreen extends React.Component<Props> {
icon="qrcode-scan" icon="qrcode-scan"
onPress={this.openScanner} onPress={this.openScanner}
/> />
</AnimatedFocusView> </View>
); );
} }
} }

View file

@ -14,7 +14,6 @@ import DateManager from "../../managers/DateManager";
import AnimatedBottomBar from "../../components/Animations/AnimatedBottomBar"; import AnimatedBottomBar from "../../components/Animations/AnimatedBottomBar";
import {CommonActions} from "@react-navigation/native"; import {CommonActions} from "@react-navigation/native";
import ErrorView from "../../components/Screens/ErrorView"; import ErrorView from "../../components/Screens/ErrorView";
import AnimatedFocusView from "../../components/Animations/AnimatedFocusView";
type Props = { type Props = {
navigation: Object, navigation: Object,
@ -300,8 +299,8 @@ class PlanexScreen extends React.Component<Props, State> {
render() { render() {
const {containerPaddingTop} = this.props.collapsibleStack; const {containerPaddingTop} = this.props.collapsibleStack;
return ( return (
<AnimatedFocusView <View
{...this.props} style={{flex: 1}}
> >
<Banner <Banner
style={{ style={{
@ -340,7 +339,7 @@ class PlanexScreen extends React.Component<Props, State> {
onPress={this.sendMessage} onPress={this.sendMessage}
seekAttention={this.state.currentGroup.id === -1} seekAttention={this.state.currentGroup.id === -1}
/> />
</AnimatedFocusView> </View>
); );
} }
} }

View file

@ -14,7 +14,6 @@ import {
} from '../../utils/Planning'; } from '../../utils/Planning';
import {Avatar, Divider, List} from 'react-native-paper'; import {Avatar, Divider, List} from 'react-native-paper';
import CustomAgenda from "../../components/Overrides/CustomAgenda"; import CustomAgenda from "../../components/Overrides/CustomAgenda";
import AnimatedFocusView from "../../components/Animations/AnimatedFocusView";
LocaleConfig.locales['fr'] = { LocaleConfig.locales['fr'] = {
monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'], monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
@ -231,9 +230,6 @@ class PlanningScreen extends React.Component<Props, State> {
render() { render() {
// console.log("rendering PlanningScreen"); // console.log("rendering PlanningScreen");
return ( return (
<AnimatedFocusView
{...this.props}
>
<CustomAgenda <CustomAgenda
{...this.props} {...this.props}
// the list of items that have to be displayed in agenda. If you want to render item as empty date // the list of items that have to be displayed in agenda. If you want to render item as empty date
@ -262,7 +258,6 @@ class PlanningScreen extends React.Component<Props, State> {
// ref to this agenda in order to handle back button event // ref to this agenda in order to handle back button event
onRef={this.onAgendaRef} onRef={this.onAgendaRef}
/> />
</AnimatedFocusView>
); );
} }
} }

View file

@ -6,7 +6,6 @@ import i18n from "i18n-js";
import WebSectionList from "../../components/Screens/WebSectionList"; import WebSectionList from "../../components/Screens/WebSectionList";
import {List, withTheme} from 'react-native-paper'; import {List, withTheme} from 'react-native-paper';
import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton"; import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
import AnimatedFocusView from "../../components/Animations/AnimatedFocusView";
const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json"; const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
const LIST_ITEM_HEIGHT = 84; const LIST_ITEM_HEIGHT = 84;
@ -234,9 +233,6 @@ class ProximoMainScreen extends React.Component<Props, State> {
render() { render() {
const nav = this.props.navigation; const nav = this.props.navigation;
return ( return (
<AnimatedFocusView
{...this.props}
>
<WebSectionList <WebSectionList
createDataset={this.createDataset} createDataset={this.createDataset}
navigation={nav} navigation={nav}
@ -244,7 +240,6 @@ class ProximoMainScreen extends React.Component<Props, State> {
refreshOnFocus={false} refreshOnFocus={false}
fetchUrl={DATA_URL} fetchUrl={DATA_URL}
renderItem={this.getRenderItem}/> renderItem={this.getRenderItem}/>
</AnimatedFocusView>
); );
} }
} }

View file

@ -15,7 +15,6 @@ import AprilFoolsManager from "../../managers/AprilFoolsManager";
import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton"; import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
import ProxiwashSectionHeader from "../../components/Lists/Proxiwash/ProxiwashSectionHeader"; import ProxiwashSectionHeader from "../../components/Lists/Proxiwash/ProxiwashSectionHeader";
import {withCollapsible} from "../../utils/withCollapsible"; import {withCollapsible} from "../../utils/withCollapsible";
import AnimatedFocusView from "../../components/Animations/AnimatedFocusView";
const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json"; const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
@ -422,8 +421,8 @@ class ProxiwashScreen extends React.Component<Props, State> {
const nav = this.props.navigation; const nav = this.props.navigation;
const {containerPaddingTop} = this.props.collapsibleStack; const {containerPaddingTop} = this.props.collapsibleStack;
return ( return (
<AnimatedFocusView <View
{...this.props} style={{flex: 1}}
> >
<Banner <Banner
style={{ style={{
@ -455,7 +454,7 @@ class ProxiwashScreen extends React.Component<Props, State> {
autoRefreshTime={REFRESH_TIME} autoRefreshTime={REFRESH_TIME}
refreshOnFocus={true} refreshOnFocus={true}
updateData={this.state.machinesWatched.length}/> updateData={this.state.machinesWatched.length}/>
</AnimatedFocusView> </View>
); );
} }
} }