shortcut_grid.dart 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import 'dart:math' as math;
  2. import 'package:flutter/material.dart';
  3. import 'shortcut_tile.dart';
  4. class ShortcutSpec {
  5. const ShortcutSpec({
  6. required this.title,
  7. required this.subtitle,
  8. required this.iconAsset,
  9. required this.assigned,
  10. required this.onTap,
  11. this.onLongPress,
  12. });
  13. final String title;
  14. final String? subtitle;
  15. final String iconAsset;
  16. final bool assigned;
  17. final VoidCallback onTap;
  18. final VoidCallback? onLongPress;
  19. }
  20. /// Arranges the five home shortcuts in a centered 3+2 block on the car
  21. /// display, falling back to two columns on narrow windows.
  22. class ShortcutGrid extends StatelessWidget {
  23. const ShortcutGrid({
  24. super.key,
  25. required this.shortcuts,
  26. required this.compact,
  27. });
  28. final List<ShortcutSpec> shortcuts;
  29. final bool compact;
  30. @override
  31. Widget build(BuildContext context) {
  32. return LayoutBuilder(
  33. builder: (context, constraints) {
  34. if (!constraints.hasBoundedWidth || !constraints.hasBoundedHeight) {
  35. return const SizedBox.shrink();
  36. }
  37. final columns = constraints.maxWidth >= 520 ? 3 : 2;
  38. final horizontalGap = compact ? 18.0 : 24.0;
  39. final rowGap = compact ? 18.0 : 26.0;
  40. final labelAllowance = compact ? 45.0 : 50.0;
  41. final rows = (shortcuts.length / columns).ceil();
  42. final widthLimited =
  43. (constraints.maxWidth - horizontalGap * (columns - 1)) / columns;
  44. final heightLimited =
  45. (constraints.maxHeight - rowGap * (rows - 1)) / rows -
  46. labelAllowance;
  47. final size = math
  48. .min(math.min(widthLimited, heightLimited), compact ? 168.0 : 188.0)
  49. .clamp(112.0, 196.0);
  50. return Center(
  51. child: Wrap(
  52. alignment: WrapAlignment.center,
  53. crossAxisAlignment: WrapCrossAlignment.start,
  54. spacing: horizontalGap,
  55. runSpacing: rowGap,
  56. children: [
  57. for (final shortcut in shortcuts)
  58. ShortcutTile(
  59. title: shortcut.title,
  60. subtitle: shortcut.subtitle,
  61. iconAsset: shortcut.iconAsset,
  62. size: size,
  63. assigned: shortcut.assigned,
  64. onTap: shortcut.onTap,
  65. onLongPress: shortcut.onLongPress,
  66. ),
  67. ],
  68. ),
  69. );
  70. },
  71. );
  72. }
  73. }