94 lines
3.1 KiB
TypeScript
94 lines
3.1 KiB
TypeScript
import { InteractionManager } from 'react-native';
|
|
import { router } from 'expo-router';
|
|
import { showGlobalLoader, hideGlobalLoader } from '../stores/uiStore';
|
|
|
|
let loaderEnhancementEnabled = false;
|
|
|
|
// Performance monitoring (only in dev)
|
|
const isDev = process.env.NODE_ENV !== 'production';
|
|
const perfLogs: Record<string, number[]> = {};
|
|
|
|
const logPerformance = (methodName: string, duration: number) => {
|
|
if (!isDev) return;
|
|
|
|
if (!perfLogs[methodName]) {
|
|
perfLogs[methodName] = [];
|
|
}
|
|
perfLogs[methodName].push(duration);
|
|
|
|
// Log average every 5 calls
|
|
if (perfLogs[methodName].length % 5 === 0) {
|
|
const avg = perfLogs[methodName].reduce((a, b) => a + b, 0) / perfLogs[methodName].length;
|
|
console.log(`[nav-perf] ${methodName}: avg ${avg.toFixed(2)}ms (${perfLogs[methodName].length} calls)`);
|
|
}
|
|
};
|
|
|
|
const scheduleHide = () => {
|
|
// Use requestIdleCallback if available, otherwise InteractionManager
|
|
if (typeof requestIdleCallback !== 'undefined') {
|
|
requestIdleCallback(() => {
|
|
hideGlobalLoader();
|
|
}, { timeout: 100 });
|
|
} else {
|
|
InteractionManager.runAfterInteractions(() => {
|
|
hideGlobalLoader();
|
|
});
|
|
}
|
|
};
|
|
|
|
const wrapNavigationMethod = <T extends (...args: any[]) => any>(
|
|
methodName: string,
|
|
originalMethod: T
|
|
): T => {
|
|
const wrapped = ((...args: Parameters<T>) => {
|
|
const startTime = isDev && typeof performance !== 'undefined' ? performance.now() : 0;
|
|
console.log(`[router-loader] ${methodName} invoked`);
|
|
|
|
// Show loader after a small delay to avoid flicker on fast navigations
|
|
const loaderTimeout = setTimeout(() => {
|
|
showGlobalLoader();
|
|
}, 100);
|
|
|
|
try {
|
|
const result = originalMethod(...args);
|
|
|
|
// Clear loader timeout and schedule hide
|
|
clearTimeout(loaderTimeout);
|
|
scheduleHide();
|
|
|
|
if (isDev && typeof performance !== 'undefined') {
|
|
const duration = performance.now() - startTime;
|
|
logPerformance(methodName, duration);
|
|
if (duration > 300) {
|
|
console.warn(`[nav-perf] Slow navigation: ${methodName} took ${duration.toFixed(2)}ms`);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
clearTimeout(loaderTimeout);
|
|
hideGlobalLoader();
|
|
throw error;
|
|
}
|
|
}) as T;
|
|
|
|
return wrapped;
|
|
};
|
|
|
|
export const enableRouterLoader = () => {
|
|
if (loaderEnhancementEnabled) {
|
|
return;
|
|
}
|
|
loaderEnhancementEnabled = true;
|
|
|
|
const originalPush = router.push.bind(router);
|
|
const originalReplace = router.replace.bind(router);
|
|
const originalNavigate = router.navigate.bind(router);
|
|
const originalBack = router.back.bind(router);
|
|
|
|
(router as any).push = wrapNavigationMethod('push', originalPush);
|
|
(router as any).replace = wrapNavigationMethod('replace', originalReplace);
|
|
(router as any).navigate = wrapNavigationMethod('navigate', originalNavigate);
|
|
(router as any).back = wrapNavigationMethod('back', originalBack);
|
|
};
|