summaryrefslogtreecommitdiff
path: root/app/navigators/navigation-utilities.tsx
diff options
context:
space:
mode:
authorThomas F. K. Jorna <[email protected]>2021-07-14 15:10:31 +0200
committerThomas F. K. Jorna <[email protected]>2021-07-14 15:10:31 +0200
commite5021187e96b78b53203bd95d08d6818aea47d17 (patch)
tree37ec45d00eb963db53cd4bb4f04a770414b351cc /app/navigators/navigation-utilities.tsx
New Ignite 7.0.6 app
Diffstat (limited to 'app/navigators/navigation-utilities.tsx')
-rw-r--r--app/navigators/navigation-utilities.tsx127
1 files changed, 127 insertions, 0 deletions
diff --git a/app/navigators/navigation-utilities.tsx b/app/navigators/navigation-utilities.tsx
new file mode 100644
index 0000000..de1ea05
--- /dev/null
+++ b/app/navigators/navigation-utilities.tsx
@@ -0,0 +1,127 @@
+import React, { useState, useEffect, useRef } from "react"
+import { BackHandler } from "react-native"
+import { PartialState, NavigationState, NavigationContainerRef } from "@react-navigation/native"
+
+export const RootNavigation = {
+ navigate(name: string) {
+ name // eslint-disable-line no-unused-expressions
+ },
+ goBack() {}, // eslint-disable-line @typescript-eslint/no-empty-function
+ resetRoot(state?: PartialState<NavigationState> | NavigationState) {}, // eslint-disable-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
+ getRootState(): NavigationState {
+ return {} as any
+ },
+}
+
+export const setRootNavigation = (ref: React.RefObject<NavigationContainerRef>) => {
+ for (const method in RootNavigation) {
+ RootNavigation[method] = (...args: any) => {
+ if (ref.current) {
+ return ref.current[method](...args)
+ }
+ }
+ }
+}
+
+/**
+ * Gets the current screen from any navigation state.
+ */
+export function getActiveRouteName(state: NavigationState | PartialState<NavigationState>) {
+ const route = state.routes[state.index]
+
+ // Found the active route -- return the name
+ if (!route.state) return route.name
+
+ // Recursive call to deal with nested routers
+ return getActiveRouteName(route.state)
+}
+
+/**
+ * Hook that handles Android back button presses and forwards those on to
+ * the navigation or allows exiting the app.
+ */
+export function useBackButtonHandler(
+ ref: React.RefObject<NavigationContainerRef>,
+ canExit: (routeName: string) => boolean,
+) {
+ const canExitRef = useRef(canExit)
+
+ useEffect(() => {
+ canExitRef.current = canExit
+ }, [canExit])
+
+ useEffect(() => {
+ // We'll fire this when the back button is pressed on Android.
+ const onBackPress = () => {
+ const navigation = ref.current
+
+ if (navigation == null) {
+ return false
+ }
+
+ // grab the current route
+ const routeName = getActiveRouteName(navigation.getRootState())
+
+ // are we allowed to exit?
+ if (canExitRef.current(routeName)) {
+ // let the system know we've not handled this event
+ return false
+ }
+
+ // we can't exit, so let's turn this into a back action
+ if (navigation.canGoBack()) {
+ navigation.goBack()
+
+ return true
+ }
+
+ return false
+ }
+
+ // Subscribe when we come to life
+ BackHandler.addEventListener("hardwareBackPress", onBackPress)
+
+ // Unsubscribe when we're done
+ return () => BackHandler.removeEventListener("hardwareBackPress", onBackPress)
+ }, [ref])
+}
+
+/**
+ * Custom hook for persisting navigation state.
+ */
+export function useNavigationPersistence(storage: any, persistenceKey: string) {
+ const [initialNavigationState, setInitialNavigationState] = useState()
+ const [isRestoringNavigationState, setIsRestoringNavigationState] = useState(true)
+
+ const routeNameRef = useRef()
+ const onNavigationStateChange = (state) => {
+ const previousRouteName = routeNameRef.current
+ const currentRouteName = getActiveRouteName(state)
+
+ if (previousRouteName !== currentRouteName) {
+ // track screens.
+ __DEV__ && console.tron.log(currentRouteName)
+ }
+
+ // Save the current route name for later comparision
+ routeNameRef.current = currentRouteName
+
+ // Persist state to storage
+ storage.save(persistenceKey, state)
+ }
+
+ const restoreState = async () => {
+ try {
+ const state = await storage.load(persistenceKey)
+ if (state) setInitialNavigationState(state)
+ } finally {
+ setIsRestoringNavigationState(false)
+ }
+ }
+
+ useEffect(() => {
+ if (isRestoringNavigationState) restoreState()
+ }, [isRestoringNavigationState])
+
+ return { onNavigationStateChange, restoreState, initialNavigationState }
+}