Files
streamyfin/providers/SplashScreenProvider.tsx
Fredrik Burmester a71a646743 chore
2025-01-31 15:36:49 +01:00

104 lines
2.5 KiB
TypeScript

import {
createContext,
ReactNode,
useContext,
useEffect,
useState,
useRef,
} from "react";
import * as SplashScreen from "expo-splash-screen";
type SplashScreenContextValue = {
registerLoadingComponent: () => () => void;
splashScreenVisible: boolean;
};
const SplashScreenContext = createContext<SplashScreenContextValue | undefined>(
undefined
);
// Prevent splash screen from auto-hiding
void SplashScreen.preventAutoHideAsync();
export const SplashScreenProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
const [splashScreenVisible, setSplashScreenVisible] = useState(true);
const loadingComponentsCount = useRef(0);
const isHidingRef = useRef(false);
const hideScreenIfNoLoadingComponents = async () => {
if (loadingComponentsCount.current === 0 && !isHidingRef.current) {
try {
isHidingRef.current = true;
await SplashScreen.hideAsync();
setSplashScreenVisible(false);
} catch (error) {
console.warn("Failed to hide splash screen:", error);
} finally {
isHidingRef.current = false;
}
}
};
const registerLoadingComponent = () => {
loadingComponentsCount.current += 1;
return () => {
loadingComponentsCount.current -= 1;
void hideScreenIfNoLoadingComponents();
};
};
const contextValue: SplashScreenContextValue = {
registerLoadingComponent,
splashScreenVisible,
};
return (
<SplashScreenContext.Provider value={contextValue}>
{children}
</SplashScreenContext.Provider>
);
};
/**
* Show the Splash Screen until component is ready to be displayed.
*
* @param isLoading The loading state of the component
*
* ## Usage
* ```
* const isLoading = loadSomething()
* useSplashScreenLoading(isLoading) // splash screen visible until isLoading is false
* ```
*/
export function useSplashScreenLoading(isLoading: boolean) {
const context = useContext(SplashScreenContext);
if (!context) {
throw new Error(
"useSplashScreenLoading must be used within a SplashScreenProvider"
);
}
useEffect(() => {
if (isLoading) {
return context.registerLoadingComponent();
}
}, [isLoading]);
}
/**
* Get the visibility of the Splash Screen.
* @returns the visibility of the Splash Screen
*/
export function useSplashScreenVisible() {
const context = useContext(SplashScreenContext);
if (!context) {
throw new Error(
"useSplashScreenVisible must be used within a SplashScreenProvider"
);
}
return context.splashScreenVisible;
}