Skip to content

Commit

Permalink
Merge pull request #33200 from margelo/@chrispader/animated-status-ba…
Browse files Browse the repository at this point in the history
…r-transition

Add back animated status bar transition
  • Loading branch information
roryabraham authored Jan 3, 2024
2 parents 6e234b9 + 1642c5d commit a83eecc
Showing 1 changed file with 44 additions and 19 deletions.
63 changes: 44 additions & 19 deletions src/components/CustomStatusBarAndBackground/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {useCallback, useContext, useEffect, useRef, useState} from 'react';
import {interpolateColor, runOnJS, useAnimatedReaction, useSharedValue, withDelay, withTiming} from 'react-native-reanimated';
import useTheme from '@hooks/useTheme';
import {navigationRef} from '@libs/Navigation/Navigation';
import StatusBar from '@libs/StatusBar';
Expand Down Expand Up @@ -33,7 +34,27 @@ function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBack
};
}, [disableRootStatusBar, isNested]);

const prevStatusBarBackgroundColor = useRef(theme.appBG);
const statusBarBackgroundColor = useRef(theme.appBG);
const statusBarAnimation = useSharedValue(0);

useAnimatedReaction(
() => statusBarAnimation.value,
(current, previous) => {
// Do not run if either of the animated value is null
// or previous animated value is greater than or equal to the current one
if (previous === null || current === null || current <= previous) {
return;
}
const backgroundColor = interpolateColor(statusBarAnimation.value, [0, 1], [prevStatusBarBackgroundColor.current, statusBarBackgroundColor.current]);
runOnJS(updateStatusBarAppearance)({backgroundColor});
},
);

const listenerCount = useRef(0);

// Updates the status bar style and background color depending on the current route and theme
// This callback is triggered everytime the route changes or the theme changes
const updateStatusBarStyle = useCallback(
(listenerId?: number) => {
// Check if this function is either called through the current navigation listener or the general useEffect which listens for theme changes.
Expand All @@ -49,27 +70,40 @@ function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBack
currentRoute = navigationRef.getCurrentRoute();
}

let currentScreenBackgroundColor = theme.appBG;
let newStatusBarStyle = theme.statusBarStyle;
let currentScreenBackgroundColor = theme.appBG;
if (currentRoute && 'name' in currentRoute && currentRoute.name in theme.PAGE_THEMES) {
const screenTheme = theme.PAGE_THEMES[currentRoute.name];
currentScreenBackgroundColor = screenTheme.backgroundColor;
newStatusBarStyle = screenTheme.statusBarStyle;
const pageTheme = theme.PAGE_THEMES[currentRoute.name];

newStatusBarStyle = pageTheme.statusBarStyle;

const backgroundColorFromRoute =
currentRoute?.params && 'backgroundColor' in currentRoute.params && typeof currentRoute.params.backgroundColor === 'string' && currentRoute.params.backgroundColor;

// It's possible for backgroundColorFromRoute to be empty string, so we must use "||" to fallback to backgroundColorFallback.
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
currentScreenBackgroundColor = backgroundColorFromRoute || pageTheme.backgroundColor;
}

prevStatusBarBackgroundColor.current = statusBarBackgroundColor.current;
statusBarBackgroundColor.current = currentScreenBackgroundColor;

if (currentScreenBackgroundColor !== theme.appBG || prevStatusBarBackgroundColor.current !== theme.appBG) {
statusBarAnimation.value = 0;
statusBarAnimation.value = withDelay(300, withTiming(1));
}

// Don't update the status bar style if it's the same as the current one, to prevent flashing.
if (newStatusBarStyle === statusBarStyle) {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor});
} else {
updateStatusBarAppearance({backgroundColor: currentScreenBackgroundColor, statusBarStyle: newStatusBarStyle});
if (newStatusBarStyle !== statusBarStyle) {
updateStatusBarAppearance({statusBarStyle: newStatusBarStyle});
setStatusBarStyle(newStatusBarStyle);
}
},
[statusBarStyle, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle],
[statusBarAnimation, statusBarStyle, theme.PAGE_THEMES, theme.appBG, theme.statusBarStyle],
);

// Add navigation state listeners to update the status bar every time the route changes
// We have to pass a count as the listener id, because "react-navigation" somehow doesn't remove listeners properyl
// We have to pass a count as the listener id, because "react-navigation" somehow doesn't remove listeners properly
useEffect(() => {
if (isDisabled) {
return;
Expand All @@ -82,15 +116,6 @@ function CustomStatusBarAndBackground({isNested = false}: CustomStatusBarAndBack
return () => navigationRef.removeListener('state', listener);
}, [isDisabled, theme.appBG, updateStatusBarStyle]);

// Update the status bar style everytime the theme changes
useEffect(() => {
if (isDisabled) {
return;
}

updateStatusBarStyle();
}, [isDisabled, theme, updateStatusBarStyle]);

// Update the global background (on web) everytime the theme changes.
// The background of the html element needs to be updated, otherwise you will see a big contrast when resizing the window or when the keyboard is open on iOS web.
useEffect(() => {
Expand Down

0 comments on commit a83eecc

Please sign in to comment.