Skip to content

Commit

Permalink
Animate splash screen in JS
Browse files Browse the repository at this point in the history
  • Loading branch information
zoontek committed May 15, 2023
1 parent e5341e7 commit cd83444
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 5 deletions.
1 change: 1 addition & 0 deletions __mocks__/react-native.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jest.doMock('react-native', () => {
BootSplash: {
getVisibilityStatus: jest.fn(),
hide: jest.fn(),
navigationBarHeight: 0,
},
StartupTimer: {stop: jest.fn()},
},
Expand Down
1 change: 1 addition & 0 deletions android/app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<resources>
<color name="bootsplash_background">#03D47C</color>
<color name="status_bar_background">#061B09</color>
<color name="white">#FFFFFF</color>
<color name="accent">#03D47C</color>
<color name="dark">#0b1b34</color>
Expand Down
3 changes: 1 addition & 2 deletions android/app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@
</style>

<style name="BootTheme" parent="Theme.SplashScreen">
<item name="android:navigationBarColor">@color/bootsplash_background</item>
<item name="android:statusBarColor">@color/bootsplash_background</item>
<item name="android:statusBarColor">@color/status_bar_background</item>
<item name="windowSplashScreenAnimatedIcon">@mipmap/bootsplash_logo</item>
<item name="windowSplashScreenBackground">@color/bootsplash_background</item>
</style>
Expand Down
1 change: 1 addition & 0 deletions assets/images/new-expensify-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/Expensify.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import Navigation from './libs/Navigation/Navigation';
import DeeplinkWrapper from './components/DeeplinkWrapper';
import PopoverReportActionContextMenu from './pages/home/report/ContextMenu/PopoverReportActionContextMenu';
import * as ReportActionContextMenu from './pages/home/report/ContextMenu/ReportActionContextMenu';
import AnimatedSplashScreen from './components/AnimatedSplashScreen';
import KeyboardShortcutsModal from './components/KeyboardShortcutsModal';

// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
Expand Down Expand Up @@ -202,6 +203,8 @@ function Expensify(props) {
onReady={setNavigationReady}
authenticated={isAuthenticated}
/>

<AnimatedSplashScreen isReady={!isSplashShown} />
</DeeplinkWrapper>
);
}
Expand Down
85 changes: 85 additions & 0 deletions src/components/AnimatedSplashScreen/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import PropTypes from 'prop-types';
import {useEffect, useState} from 'react';
import {Animated, StatusBar, StyleSheet} from 'react-native';
import BootSplash from '../../libs/BootSplash';
import Logo from '../../../assets/images/new-expensify-dark.svg';
import colors from '../../styles/colors';

const SCALE_RATIO = 10;

const propTypes = {
/** Screen is ready to be animated */
isReady: PropTypes.bool,
};

const defaultProps = {
isReady: false,
};

const AnimatedSplashScreen = (props) => {
const [isVisible, setIsVisible] = useState(true);
const [scale] = useState(() => new Animated.Value(1 / SCALE_RATIO));
const [opacity] = useState(() => new Animated.Value(1));

useEffect(() => {
if (!props.isReady || !isVisible) {
return;
}

Animated.stagger(220, [
Animated.spring(scale, {
toValue: 1 / (SCALE_RATIO * 2),
useNativeDriver: true,
}),
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
}),
]).start();

Animated.timing(opacity, {
delay: 220,
duration: 220,
toValue: 0,
useNativeDriver: true,
}).start(() => {
setIsVisible(false);
});
}, [props.isReady, isVisible, opacity, scale]);

if (!isVisible) {
return null;
}

return (
<Animated.View
style={{
...StyleSheet.absoluteFillObject,
backgroundColor: colors.green400,
alignItems: 'center',
justifyContent: 'center',
opacity,
marginTop: -StatusBar.currentHeight,
marginBottom: -BootSplash.navigationBarHeight,
}}
>
<Animated.View
style={{
transform: [{scale}],
}}
>
<Logo
viewBox="0 0 100 100"
width={100 * SCALE_RATIO}
height={100 * SCALE_RATIO}
/>
</Animated.View>
</Animated.View>
);
};

AnimatedSplashScreen.displayName = 'AnimatedSplashScreen';
AnimatedSplashScreen.propTypes = propTypes;
AnimatedSplashScreen.defaultProps = defaultProps;

export default AnimatedSplashScreen;
1 change: 1 addition & 0 deletions src/components/AnimatedSplashScreen/index.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => null;
1 change: 1 addition & 0 deletions src/libs/BootSplash/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
hide: () => Promise.resolve(),
getVisibilityStatus: () => Promise.resolve('hidden'),
navigationBarHeight: 0,
};
1 change: 1 addition & 0 deletions src/libs/BootSplash/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ function hide() {
export default {
hide,
getVisibilityStatus: BootSplash.getVisibilityStatus,
navigationBarHeight: BootSplash.navigationBarHeight || 0,
};
3 changes: 0 additions & 3 deletions src/libs/Navigation/NavigationRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import {useFlipper} from '@react-navigation/devtools';
import Navigation, {navigationRef} from './Navigation';
import linkingConfig from './linkingConfig';
import AppNavigator from './AppNavigator';
import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
import themeColors from '../../styles/themes/default';
import styles from '../../styles/styles';
import Log from '../Log';

// https://reactnavigation.org/docs/themes
Expand Down Expand Up @@ -52,7 +50,6 @@ const NavigationRoot = (props) => {
useFlipper(navigationRef);
return (
<NavigationContainer
fallback={<FullScreenLoadingIndicator style={styles.navigatorFullScreenLoading} />}
onStateChange={parseAndLogRoute}
onReady={props.onReady}
theme={navigationTheme}
Expand Down

0 comments on commit cd83444

Please sign in to comment.