diff --git a/lib/shared/farcaster/farcaster-hooks.js b/lib/shared/farcaster/farcaster-hooks.js --- a/lib/shared/farcaster/farcaster-hooks.js +++ b/lib/shared/farcaster/farcaster-hooks.js @@ -138,6 +138,7 @@ batchSize: number, processor: (item: T, batchedUpdates: BatchedUpdates) => Promise, dispatch: Dispatch, + onProgress?: (completed: number, total: number) => void, ): Promise> { const results: Array = []; for (let i = 0; i < items.length; i += batchSize) { @@ -175,6 +176,9 @@ }); } + const completedItems = Math.min(i + batchSize, items.length); + onProgress?.(completedItems, items.length); + // This should help with the app responsiveness await sleep(0); } @@ -358,7 +362,14 @@ ); } -function useFarcasterConversationsSync(): (limit: number) => Promise { +function useFarcasterConversationsSync(): ( + limit: number, + onProgress?: ( + completed: number, + total: number, + phase: 'conversations' | 'messages', + ) => void, +) => Promise { const fetchFarcasterInbox = useFetchFarcasterInbox(); const dispatch = useDispatch(); const fetchConversation = useFetchConversationWithBatching(); @@ -407,7 +418,14 @@ ); return React.useCallback( - async (limit: number) => { + async ( + limit: number, + onProgress?: ( + completed: number, + total: number, + phase: 'conversations' | 'messages', + ) => void, + ) => { try { const conversations = await fetchInboxes(null); @@ -418,17 +436,20 @@ const farcasterConversations: Array = []; + onProgress?.(0, conversations.length, 'conversations'); const conversationResults = await processInBatchesWithReduxBatching( conversations, FARCASTER_DATA_BATCH_SIZE, (conversationID, batchedUpdates) => fetchConversation(conversationID, batchedUpdates), dispatch, + (completed, total) => onProgress?.(completed, total, 'conversations'), ); const successfulConversations = conversationResults.filter(Boolean); farcasterConversations.push(...successfulConversations); + onProgress?.(0, conversations.length, 'messages'); await processInBatchesWithReduxBatching( farcasterConversations, FARCASTER_DATA_BATCH_SIZE, @@ -439,6 +460,7 @@ batchedUpdates, ), dispatch, + (completed, total) => onProgress?.(completed, total, 'messages'), ); setFarcasterDCsLoaded(true); @@ -507,7 +529,14 @@ ); } -function useFarcasterSync(onComplete?: () => void): { +inProgress: boolean } { +function useFarcasterSync(onComplete?: () => void): { + +inProgress: boolean, + +progress: ?{ + completed: number, + total: number, + phase: 'conversations' | 'messages', + }, +} { const syncFarcasterConversations = useFarcasterConversationsSync(); const currentUserSupportsDCs = useCurrentUserSupportsDCs(); const farcasterDCsLoaded = useFarcasterDCsLoaded(); @@ -515,6 +544,19 @@ const userDataReady = useIsUserDataReady(); const fullyLoggedIn = isUserLoggedIn && userDataReady; const [inProgress, setInProgress] = React.useState(false); + const [progress, setProgress] = React.useState(null); + + const handleProgress = React.useCallback( + (completed: number, total: number, phase: 'conversations' | 'messages') => { + const progressInfo = { completed, total, phase }; + setProgress(progressInfo); + }, + [], + ); React.useEffect(() => { if ( @@ -526,11 +568,16 @@ return; } setInProgress(true); + setProgress(null); void (async () => { try { - await syncFarcasterConversations(Number.POSITIVE_INFINITY); + await syncFarcasterConversations( + Number.POSITIVE_INFINITY, + handleProgress, + ); } finally { setInProgress(false); + setProgress(null); onComplete?.(); } })(); @@ -540,10 +587,11 @@ fullyLoggedIn, inProgress, onComplete, + handleProgress, syncFarcasterConversations, ]); - return { inProgress }; + return { inProgress, progress }; } export { diff --git a/native/farcaster/farcaster-sync-loading-screen.react.js b/native/farcaster/farcaster-sync-loading-screen.react.js --- a/native/farcaster/farcaster-sync-loading-screen.react.js +++ b/native/farcaster/farcaster-sync-loading-screen.react.js @@ -24,7 +24,22 @@ props.navigation.goBack(); }, [props.navigation]); - useFarcasterSync(handleComplete); + const { progress } = useFarcasterSync(handleComplete); + + const progressValue = progress + ? progress.completed / progress.total + : undefined; + + const phase = React.useMemo(() => { + if (!progress?.phase) { + return null; + } + const phaseText = + progress.phase === 'conversations' + ? 'Loading conversations...' + : 'Loading messages...'; + return {phaseText}; + }, [progress?.phase, styles.section]); return ( @@ -35,13 +50,24 @@ This could take a while depending on how many conversations you have. + {phase} - + {progress ? ( + + ) : ( + + )} ); diff --git a/web/farcaster/farcaster-sync-loading-screen.react.js b/web/farcaster/farcaster-sync-loading-screen.react.js --- a/web/farcaster/farcaster-sync-loading-screen.react.js +++ b/web/farcaster/farcaster-sync-loading-screen.react.js @@ -8,7 +8,26 @@ import LoadingIndicator from '../loading-indicator.react.js'; function FarcasterSyncLoadingScreen(): React.Node { - useFarcasterSync(); + const { progress } = useFarcasterSync(); + + const progressComponent = React.useMemo(() => { + if (!progress) { + return null; + } + return ( + <> +

+ {progress.phase === 'conversations' + ? 'Loading conversations...' + : 'Loading messages...'} +

+

+ {progress.completed} of {progress.total} ( + {Math.round((progress.completed / progress.total) * 100)}%) +

+ + ); + }, [progress]); return (
@@ -24,6 +43,7 @@ This could take a while depending on how many conversations you have.

+ {progressComponent}