@@ -24,7 +24,7 @@ import { countOccurrences, type FileTreeNodeData, makeFileTree, type LazyPromise
2424import { onDestroy , tick } from "svelte" ;
2525import { type TreeNode , TreeState } from "$lib/components/tree/index.svelte" ;
2626import { VList } from "virtua/svelte" ;
27- import { Context , Debounced } from "runed" ;
27+ import { Context , Debounced , watch } from "runed" ;
2828import { MediaQuery } from "svelte/reactivity" ;
2929import { ProgressBarState } from "$lib/components/progress-bar/index.svelte" ;
3030
@@ -338,8 +338,7 @@ export class MultiFileDiffViewerState {
338338 activeSearchResult : ActiveSearchResult | null = $state ( null ) ;
339339 sidebarCollapsed = $state ( false ) ;
340340 diffMetadata : DiffMetadata | null = $state ( null ) ;
341- loading : boolean = $state ( false ) ;
342- readonly progressBar = $state ( new ProgressBarState ( null , 100 ) ) ;
341+ readonly loadingState : LoadingState = $state ( new LoadingState ( ) ) ;
343342
344343 readonly fileTreeFilterDebounced = new Debounced ( ( ) => this . fileTreeFilter , 500 ) ;
345344 readonly searchQueryDebounced = new Debounced ( ( ) => this . searchQuery , 500 ) ;
@@ -479,13 +478,12 @@ export class MultiFileDiffViewerState {
479478 }
480479
481480 async loadPatches ( meta : ( ) => Promise < DiffMetadata > , patches : ( ) => Promise < AsyncGenerator < FileDetails , void > > ) {
482- if ( this . loading ) {
481+ if ( this . loadingState . loading ) {
483482 alert ( "Already loading patches, please wait." ) ;
484483 return false ;
485484 }
486485 try {
487- this . progressBar . setSpinning ( ) ;
488- this . loading = true ;
486+ this . loadingState . start ( ) ;
489487 await tick ( ) ;
490488 await animationFramePromise ( ) ;
491489
@@ -501,8 +499,14 @@ export class MultiFileDiffViewerState {
501499
502500 const tempDetails : FileDetails [ ] = [ ] ;
503501 for await ( const details of generator ) {
502+ this . loadingState . loadedCount ++ ;
503+
504504 // Pushing directly to the main array causes too many signals to update (lag)
505505 tempDetails . push ( details ) ;
506+
507+ // TODO this makes it load one patch per frame
508+ await tick ( ) ;
509+ await animationFramePromise ( ) ;
506510 }
507511 if ( tempDetails . length === 0 ) {
508512 throw new Error ( "No valid patches found in the provided data." ) ;
@@ -516,7 +520,7 @@ export class MultiFileDiffViewerState {
516520 alert ( "Failed to load patches: " + e ) ;
517521 return false ;
518522 } finally {
519- this . loading = false ;
523+ this . loadingState . done ( ) ;
520524 }
521525 }
522526
@@ -527,7 +531,7 @@ export class MultiFileDiffViewerState {
527531 } ,
528532 async ( ) => {
529533 const result = await resultPromise ;
530- return parseMultiFilePatchGithub ( result . info , await result . response ) ;
534+ return parseMultiFilePatchGithub ( result . info , await result . response , this . loadingState ) ;
531535 } ,
532536 ) ;
533537 }
@@ -661,6 +665,34 @@ export class MultiFileDiffViewerState {
661665 }
662666}
663667
668+ export class LoadingState {
669+ loading : boolean = $state ( false ) ;
670+ loadedCount : number = $state ( 0 ) ;
671+ totalCount : number | null = $state ( 0 ) ;
672+ readonly progressBar = $state ( new ProgressBarState ( null , 100 ) ) ;
673+
674+ constructor ( ) {
675+ watch ( [ ( ) => this . loadedCount , ( ) => this . totalCount ] , ( [ loadedCount , totalCount ] ) => {
676+ if ( totalCount === null || totalCount <= 0 ) {
677+ this . progressBar . setSpinning ( ) ;
678+ } else {
679+ this . progressBar . setProgress ( loadedCount , totalCount ) ;
680+ }
681+ } ) ;
682+ }
683+
684+ start ( ) {
685+ this . loadedCount = 0 ;
686+ this . totalCount = null ;
687+ this . progressBar . setSpinning ( ) ;
688+ this . loading = true ;
689+ }
690+
691+ done ( ) {
692+ this . loading = false ;
693+ }
694+ }
695+
664696export type ActiveSearchResult = {
665697 file : FileDetails ;
666698 idx : number ;
0 commit comments