startAsyncUpdateHandler manages UI updates during async loading
(updateChan <-chan bool, doneChan <-chan error)
| 40 | |
| 41 | // startAsyncUpdateHandler manages UI updates during async loading |
| 42 | func startAsyncUpdateHandler(updateChan <-chan bool, doneChan <-chan error) { |
| 43 | go func() { |
| 44 | ticker := time.NewTicker(20 * time.Millisecond) |
| 45 | defer ticker.Stop() |
| 46 | |
| 47 | loadComplete := false |
| 48 | for !loadComplete { |
| 49 | select { |
| 50 | case <-updateChan: |
| 51 | // Update available - will be handled by ticker |
| 52 | case err := <-doneChan: |
| 53 | loadComplete = true |
| 54 | if err != nil { |
| 55 | fatalError(err) |
| 56 | } |
| 57 | // Final update |
| 58 | app.QueueUpdateDraw(func() { |
| 59 | drawBuffer(b, bufferTable) |
| 60 | updateFooterWithStatus("Loaded " + strconv.Itoa(b.rowLen) + " rows") |
| 61 | }) |
| 62 | case <-ticker.C: |
| 63 | // Periodic UI update |
| 64 | app.QueueUpdateDraw(func() { |
| 65 | drawBuffer(b, bufferTable) |
| 66 | |
| 67 | // Keep cursor on first row if user hasn't moved it |
| 68 | if !userMovedCursor { |
| 69 | row, col := bufferTable.GetSelection() |
| 70 | if row != 0 { |
| 71 | bufferTable.Select(0, col) |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | if loadProgress.TotalBytes > 0 { |
| 76 | // Show progress bar for files |
| 77 | percent := loadProgress.GetPercentage() |
| 78 | progressBar := makeProgressBar(percent, 15) |
| 79 | updateFooterWithStatus(fmt.Sprintf("Loading... %s", progressBar)) |
| 80 | } else { |
| 81 | // Show row count for pipes (no file size) |
| 82 | updateFooterWithStatus("Loading... " + strconv.Itoa(b.rowLen) + " rows") |
| 83 | } |
| 84 | }) |
| 85 | } |
| 86 | } |
| 87 | }() |
| 88 | } |
| 89 | |
| 90 | // loadDataAsync starts async loading and waits for initial data |
| 91 | func loadDataAsync(loader func(*Buffer, chan<- bool, chan<- error), b *Buffer) (chan bool, chan error, error) { |
no test coverage detected