suggest static method
Generate fix suggestions for a layout decision.
Implementation
static List<FixSuggestion> suggest(LayoutDecision decision) {
if (!decision.overflowed) return const [];
final suggestions = <FixSuggestion>[];
final widgetType = decision.widgetType.toLowerCase();
final constraints = decision.constraintsReceived;
final size = decision.sizeReported;
final widthOverflow = size.width > constraints.maxWidth;
final heightOverflow = size.height > constraints.maxHeight;
// ── Row/Flex horizontal overflow ──────────────────────────────────────
if (widthOverflow && _isHorizontalFlex(widgetType)) {
suggestions.add(const FixSuggestion(
description: 'Wrap overflowing children in Expanded or Flexible',
codeHint: 'Row(children: [Expanded(child: Text(...)), ...])',
confidence: 0.92,
priority: 0,
category: FixCategory.addWrapper,
));
suggestions.add(const FixSuggestion(
description: 'Make the Row horizontally scrollable',
codeHint:
'SingleChildScrollView(scrollDirection: Axis.horizontal, child: Row(...))',
confidence: 0.75,
priority: 1,
category: FixCategory.addScrollable,
));
}
// ── Column/Flex vertical overflow ─────────────────────────────────────
if (heightOverflow && _isVerticalFlex(widgetType)) {
suggestions.add(const FixSuggestion(
description: 'Wrap overflowing children in Expanded or Flexible',
codeHint: 'Column(children: [Expanded(child: ListView(...)), ...])',
confidence: 0.92,
priority: 0,
category: FixCategory.addWrapper,
));
suggestions.add(const FixSuggestion(
description: 'Wrap the Column in SingleChildScrollView',
codeHint: 'SingleChildScrollView(child: Column(...))',
confidence: 0.75,
priority: 1,
category: FixCategory.addScrollable,
));
}
// ── Text overflow ─────────────────────────────────────────────────────
if (widthOverflow && _isTextWidget(widgetType)) {
suggestions.add(const FixSuggestion(
description: 'Add TextOverflow.ellipsis to truncate text',
codeHint: "Text('...', overflow: TextOverflow.ellipsis)",
confidence: 0.88,
priority: 0,
category: FixCategory.changeProperty,
));
suggestions.add(const FixSuggestion(
description: 'Wrap the Text in Flexible inside a Row or Column',
codeHint: 'Flexible(child: Text(...))',
confidence: 0.82,
priority: 1,
category: FixCategory.addWrapper,
));
suggestions.add(const FixSuggestion(
description: 'Set maxLines to limit the number of text lines',
codeHint: "Text('...', maxLines: 2, overflow: TextOverflow.ellipsis)",
confidence: 0.7,
priority: 2,
category: FixCategory.changeProperty,
));
}
// ── Image overflow ────────────────────────────────────────────────────
if (_isImageWidget(widgetType)) {
suggestions.add(const FixSuggestion(
description: 'Set BoxFit.contain or BoxFit.cover on the Image',
codeHint: 'Image.network(url, fit: BoxFit.cover)',
confidence: 0.85,
priority: 0,
category: FixCategory.changeProperty,
));
suggestions.add(const FixSuggestion(
description: 'Constrain the Image with SizedBox or AspectRatio',
codeHint: 'SizedBox(width: 200, height: 200, child: Image(...))',
confidence: 0.8,
priority: 1,
category: FixCategory.constrainDimensions,
));
}
// ── ListView inside Column (unbounded height) ────────────────────────
if (heightOverflow && _isScrollableWidget(widgetType)) {
suggestions.add(const FixSuggestion(
description: 'Wrap ListView in Expanded when inside a Column',
codeHint: 'Column(children: [Expanded(child: ListView(...))])',
confidence: 0.95,
priority: 0,
category: FixCategory.addWrapper,
));
suggestions.add(const FixSuggestion(
description: 'Set shrinkWrap: true on the ListView',
codeHint:
'ListView(shrinkWrap: true, physics: NeverScrollableScrollPhysics())',
confidence: 0.6,
priority: 2,
category: FixCategory.changeProperty,
));
}
// ── Unbounded constraints ─────────────────────────────────────────────
// When maxWidth/maxHeight is infinity, size can never exceed it numerically,
// but an unbounded constraint IS the problem — flag it when overflowed.
if (constraints.maxWidth == double.infinity) {
suggestions.add(const FixSuggestion(
description:
'The widget received unbounded width — add a width constraint',
codeHint:
'ConstrainedBox(constraints: BoxConstraints(maxWidth: 400), child: ...)',
confidence: 0.7,
priority: 1,
category: FixCategory.constrainDimensions,
));
}
if (constraints.maxHeight == double.infinity) {
suggestions.add(const FixSuggestion(
description:
'The widget received unbounded height — add a height constraint',
codeHint:
'ConstrainedBox(constraints: BoxConstraints(maxHeight: 600), child: ...)',
confidence: 0.7,
priority: 1,
category: FixCategory.constrainDimensions,
));
}
// ── Fallback generic suggestion ───────────────────────────────────────
if (suggestions.isEmpty) {
if (widthOverflow) {
suggestions.add(const FixSuggestion(
description:
'Constrain the widget width with SizedBox or ConstrainedBox',
codeHint:
'ConstrainedBox(constraints: BoxConstraints(maxWidth: 300), child: ...)',
confidence: 0.4,
priority: 3,
category: FixCategory.constrainDimensions,
));
}
if (heightOverflow) {
suggestions.add(const FixSuggestion(
description: 'Constrain the widget height or wrap in a scrollable',
codeHint:
'ConstrainedBox(constraints: BoxConstraints(maxHeight: 400), child: ...)',
confidence: 0.4,
priority: 3,
category: FixCategory.constrainDimensions,
));
}
}
// Sort by priority
suggestions.sort((a, b) => a.priority.compareTo(b.priority));
return suggestions;
}