From 424df91f62c280c4e4d1d6b2a73450f134c1951e Mon Sep 17 00:00:00 2001 From: ZhuchkaTriplesix Date: Wed, 29 Jul 2026 10:09:55 +0300 Subject: [PATCH] perf(ui): use binary search for visible column window in VirtualResultGrid --- .../main_screen/result_grid_view.dart | 30 +++++++++++++++---- .../main_screen/results_tab_test.dart | 18 +++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/lib/features/main_screen/result_grid_view.dart b/lib/features/main_screen/result_grid_view.dart index 9fc2bec..f56c377 100644 --- a/lib/features/main_screen/result_grid_view.dart +++ b/lib/features/main_screen/result_grid_view.dart @@ -125,16 +125,34 @@ ResultGridColumnWindow computeVisibleColumnWindow({ final start = scrollOffset.clamp(0.0, total); final end = (scrollOffset + viewportWidth).clamp(0.0, total); - // First column with any pixel past [start]. + // First column with any pixel past [start]: smallest index where columnOffsets[first + 1] > start var first = 0; - while (first < n && columnOffsets[first + 1] <= start) { - first++; + var low = 0; + var high = n - 1; + while (low <= high) { + final mid = (low + high) ~/ 2; + if (columnOffsets[mid + 1] > start) { + first = mid; + high = mid - 1; + } else { + low = mid + 1; + } } - // Last column with any pixel before [end]. + + // Last column with any pixel before [end]: largest index where columnOffsets[last] < end var last = n - 1; - while (last > 0 && columnOffsets[last] >= end) { - last--; + low = 0; + high = n - 1; + while (low <= high) { + final mid = (low + high) ~/ 2; + if (columnOffsets[mid] < end) { + last = mid; + low = mid + 1; + } else { + high = mid - 1; + } } + if (first > last) { first = last.clamp(0, n - 1); } diff --git a/test/features/main_screen/results_tab_test.dart b/test/features/main_screen/results_tab_test.dart index e3bf96c..2ed4a56 100644 --- a/test/features/main_screen/results_tab_test.dart +++ b/test/features/main_screen/results_tab_test.dart @@ -106,6 +106,24 @@ void main() { expect(window.last, lessThan(30)); expect(window.leadingWidth, greaterThan(0)); }); + + test('handles large scale column sets (10000 columns) efficiently', () { + final widths = List.filled(10000, 100); + final offsets = computeResultGridColumnOffsets(widths); + final window = computeVisibleColumnWindow( + columnWidths: widths, + columnOffsets: offsets, + scrollOffset: 500000, + viewportWidth: 1000, + overscanColumns: 2, + ); + // scrollOffset 500000 = index 5000 (since width is 100) + // viewport 1000 = 10 columns (indices 5000..5009) + // with overscan 2 -> first: 4998, last: 5011 + expect(window.first, 4998); + expect(window.last, 5011); + expect(window.leadingWidth, 4998 * 100.0); + }); }); group('ResultsTab', () {