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 @@ -142,6 +142,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) { @@ -179,6 +180,9 @@ }); } + const completedItems = Math.min(i + batchSize, items.length); + onProgress?.(completedItems, items.length); + // This should help with the app responsiveness await sleep(0); } @@ -362,7 +366,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(); @@ -444,7 +455,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); @@ -457,17 +475,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, @@ -478,6 +499,7 @@ batchedUpdates, ), dispatch, + (completed, total) => onProgress?.(completed, total, 'messages'), ); setFarcasterDCsLoaded(true); @@ -547,7 +569,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(); @@ -555,6 +584,21 @@ 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') => + setProgress({ + completed, + total, + phase, + }), + [], + ); React.useEffect(() => { if ( @@ -566,11 +610,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?.(); } })(); @@ -580,10 +629,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,29 @@ 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} ( + {progress.total + ? Math.round((progress.completed / progress.total) * 100) + : 0} + %) +

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

+ {progressComponent}