Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions lib/features/workspace/grid/grid_column_sizer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,24 @@ class ResultGridColumnWindow {
}

/// Computes fixed column widths from headers and a sample of [rows].
///
/// When provided, [outMaxRowChars] is populated with the maximum content
/// character length for each column across the sampled rows, which can be
/// passed to [distributeResultGridSpareWidth] to eliminate redundant row
/// sampling (#1349).
List<double> computeResultGridColumnWidths({
required List<String> columns,
required List<List<String>> rows,
double minWidth = ResultGridMetrics.minColumnWidth,
double maxWidth = ResultGridMetrics.maxColumnWidth,
int sampleRowCount = ResultGridMetrics.columnWidthSampleRows,
List<int>? outMaxRowChars,
}) {
if (columns.isEmpty) return const [];

final widths = List<double>.filled(columns.length, minWidth);
final sample = rows.length < sampleRowCount ? rows.length : sampleRowCount;
outMaxRowChars?.clear();

for (var c = 0; c < columns.length; c++) {
final headerWidth = columns[c].length * 7.5 + 38.0;
Expand All @@ -101,6 +108,7 @@ List<double> computeResultGridColumnWidths({
maxRowChars = rows[r][c].length;
}
}
outMaxRowChars?.add(maxRowChars);
final contentWidth = maxRowChars * 7.5 + 24.0;
final naturalWidth = math.max(headerWidth, contentWidth);
widths[c] = naturalWidth.clamp(minWidth, maxWidth);
Expand All @@ -114,13 +122,17 @@ int gridCellContextMenuItemsBuiltCount = 0;

/// Distributes spare viewport width adaptively to columns that benefit from expansion,
/// avoiding artificial stretching of compact columns.
///
/// If [maxRowChars] is provided (e.g. from [computeResultGridColumnWidths]),
/// it is reused directly to avoid redundant row sampling passes (#1349).
List<double> distributeResultGridSpareWidth({
required List<double> columnWidths,
required List<String> columns,
required List<List<String>> rows,
required double availableWidth,
double maxColumnWidth = ResultGridMetrics.maxColumnWidth,
int sampleRowCount = ResultGridMetrics.columnWidthSampleRows,
List<int>? maxRowChars,
}) {
if (columnWidths.isEmpty || columns.isEmpty) return columnWidths;

Expand All @@ -130,16 +142,22 @@ List<double> distributeResultGridSpareWidth({

final sample = rows.length < sampleRowCount ? rows.length : sampleRowCount;
final desiredWidths = List<double>.filled(columns.length, 0);
final hasPrecomputedChars =
maxRowChars != null && maxRowChars.length == columns.length;

for (var c = 0; c < columns.length; c++) {
final headerWidth = columns[c].length * 7.5 + 38.0;
var maxRowChars = 0;
for (var r = 0; r < sample; r++) {
if (c < rows[r].length && rows[r][c].length > maxRowChars) {
maxRowChars = rows[r][c].length;
var rowChars = 0;
if (hasPrecomputedChars) {
rowChars = maxRowChars[c];
} else {
for (var r = 0; r < sample; r++) {
if (c < rows[r].length && rows[r][c].length > rowChars) {
rowChars = rows[r][c].length;
}
}
}
final contentWidth = maxRowChars * 7.5 + 24.0;
final contentWidth = rowChars * 7.5 + 24.0;
desiredWidths[c] = math.max(headerWidth, contentWidth);
}

Expand Down
1 change: 1 addition & 0 deletions lib/features/workspace/grid/grid_view_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ extension _GridViewBuilder on _VirtualResultGridState {
availableWidth: availableWidth,
maxColumnWidth:
context.scaled(ResultGridMetrics.maxColumnWidth),
maxRowChars: _columnSampleMaxRowChars,
);
_distributedWidths = displayWidths;
_distributedForColumnWidths = _columnWidths;
Expand Down
1 change: 1 addition & 0 deletions lib/features/workspace/grid/grid_view_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ extension _GridViewLayout on _VirtualResultGridState {
rows: _baseRows,
minWidth: context.scaled(ResultGridMetrics.minColumnWidth),
maxWidth: context.scaled(ResultGridMetrics.maxColumnWidth),
outMaxRowChars: _columnSampleMaxRowChars,
);
}

Expand Down
1 change: 1 addition & 0 deletions lib/features/workspace/result_grid_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class _VirtualResultGridState extends material.State<VirtualResultGrid> {

List<double> _columnWidths = const [];
List<double> _columnOffsets = const [0];
final List<int> _columnSampleMaxRowChars = [];
bool _widthsNeedUpdate = true;
bool _userHasResized = false;
double _scrollOffset = 0;
Expand Down
31 changes: 31 additions & 0 deletions test/features/workspace/results_tab_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,37 @@ void main() {
);
expect(result, equals(initial));
});

test('reuses precomputed maxRowChars and yields identical distributed widths', () {
final columns = ['app_id', 'country', 'description'];
final rows = [
['292030', 'kz', 'x' * 100],
];
final maxRowChars = <int>[];
final initialWidths = computeResultGridColumnWidths(
columns: columns,
rows: rows,
outMaxRowChars: maxRowChars,
);
expect(maxRowChars, [6, 2, 100]);

final withoutPrecomputed = distributeResultGridSpareWidth(
columnWidths: initialWidths,
columns: columns,
rows: rows,
availableWidth: 1000.0,
);

final withPrecomputed = distributeResultGridSpareWidth(
columnWidths: initialWidths,
columns: columns,
rows: rows,
availableWidth: 1000.0,
maxRowChars: maxRowChars,
);

expect(withPrecomputed, equals(withoutPrecomputed));
});
});

group('sortResultGridRows', () {
Expand Down
Loading