import 'dart:math' as math; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'shortcut_tile.dart'; class ShortcutSpec { const ShortcutSpec({ required this.title, required this.subtitle, required this.iconAsset, required this.assigned, required this.onTap, this.onLongPress, this.longPressHint, this.iconBytes, this.showEqualizer = false, }); final String title; final String? subtitle; final String iconAsset; final bool assigned; final VoidCallback onTap; final VoidCallback? onLongPress; final String? longPressHint; final Uint8List? iconBytes; final bool showEqualizer; } /// Fits up to 16 home shortcuts. Columns and tile size are chosen together so /// the whole set stays visible and grows denser as apps are added. class ShortcutGrid extends StatelessWidget { const ShortcutGrid({ super.key, required this.shortcuts, required this.compact, }); final List shortcuts; final bool compact; @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { if (!constraints.hasBoundedWidth || !constraints.hasBoundedHeight) { return const SizedBox.shrink(); } if (shortcuts.isEmpty) return const SizedBox.shrink(); final dense = shortcuts.length > 8; final horizontalGap = dense ? (compact ? 10.0 : 14.0) : (compact ? 18.0 : 24.0); final rowGap = dense ? (compact ? 12.0 : 16.0) : (compact ? 18.0 : 26.0); final labelAllowance = compact ? 46.0 : 50.0; final maxTileSize = compact ? 168.0 : 196.0; var bestSize = 0.0; for (var columns = 2; columns <= 6; columns++) { if (columns > shortcuts.length) break; final rows = (shortcuts.length / columns).ceil(); final widthLimited = (constraints.maxWidth - horizontalGap * (columns - 1)) / columns; final heightLimited = (constraints.maxHeight - rowGap * (rows - 1)) / rows - labelAllowance; final candidate = math .min(widthLimited, heightLimited) .clamp(0.0, maxTileSize); if (candidate > bestSize) bestSize = candidate; } final size = bestSize.clamp(64.0, maxTileSize); return Center( child: Wrap( alignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.start, spacing: horizontalGap, runSpacing: rowGap, children: [ for (final shortcut in shortcuts) ShortcutTile( title: shortcut.title, subtitle: shortcut.subtitle, iconAsset: shortcut.iconAsset, size: size, assigned: shortcut.assigned, onTap: shortcut.onTap, onLongPress: shortcut.onLongPress, longPressHint: shortcut.longPressHint, iconBytes: shortcut.iconBytes, showEqualizer: shortcut.showEqualizer, ), ], ), ); }, ); } }