fix(mobile): apply the banner status bar only while its screen is on top

The settings tab stays focused while another screen is pushed over it,
so the light status bar for the banner also applied to screens such as
Data Control, leaving white text on a light header. The banner status
bar now also requires that no screen is pushed or presented over its
own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DIYgod
2026-10-12 07:02:03 +08:00
parent 7d1fc7b494
commit 713f63a211
@@ -1,8 +1,30 @@
import { StatusBar } from "expo-status-bar"
import { useState } from "react"
import { useAtomValue } from "jotai"
import { selectAtom } from "jotai/utils"
import { use, useMemo, useState } from "react"
import type { SharedValue } from "react-native-reanimated"
import { runOnJS, useAnimatedReaction } from "react-native-reanimated"
import { Navigation } from "@/src/lib/navigation/Navigation"
import { ScreenItemContext } from "@/src/lib/navigation/ScreenItemContext"
// Whether no other screen is pushed or presented over the screen this renders in
const useIsTopScreen = () => {
const { screenId } = use(ScreenItemContext)
return useAtomValue(
useMemo(
() =>
selectAtom(Navigation.rootNavigation.__dangerous_getCtxValue().routesAtom, (routes) =>
// The root and the tab screens are no routes; they are on top while nothing else is
routes.some((route) => route.id === screenId)
? routes.at(-1)?.id === screenId
: routes.length === 0,
),
[screenId],
),
)
}
/**
* The status bar sits on the user banner until the header fades in, so its text follows the
* banner colors, or it is dark on dark.
@@ -16,6 +38,7 @@ export const BannerStatusBar = ({
scrollY: SharedValue<number>
enabled?: boolean
}) => {
const isTopScreen = useIsTopScreen()
const [isOverBanner, setIsOverBanner] = useState(true)
useAnimatedReaction(
() => scrollY.value < 50,
@@ -23,6 +46,6 @@ export const BannerStatusBar = ({
if (current !== previous) runOnJS(setIsOverBanner)(current)
},
)
if (!enabled || !isOverBanner) return null
if (!enabled || !isTopScreen || !isOverBanner) return null
return <StatusBar animated style={gradientLight ? "dark" : "light"} />
}