import 'dart:typed_data'; import 'package:flutter/material.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/widgets/app_icon.dart'; import '../../../core/widgets/app_icon_image.dart'; import '../../../core/widgets/pressable.dart'; import 'music_equalizer.dart'; /// One large, generic shortcut on the home screen. class ShortcutTile extends StatelessWidget { const ShortcutTile({ super.key, required this.title, required this.subtitle, required this.iconAsset, required this.size, 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 double size; final bool assigned; final VoidCallback onTap; final VoidCallback? onLongPress; final String? longPressHint; final Uint8List? iconBytes; final bool showEqualizer; @override Widget build(BuildContext context) { final colors = context.colors; final theme = Theme.of(context); final placeholder = !assigned; final iconSize = (size * 0.27).clamp(24.0, 46.0); final badgeSize = (size * 0.18).clamp(20.0, 26.0); final titleSize = size >= 160 ? 16.0 : (size >= 110 ? 14.0 : 12.0); final subtitleSize = size >= 160 ? 12.0 : (size >= 110 ? 11.0 : 10.0); final semantics = StringBuffer(title); if (subtitle != null && subtitle!.isNotEmpty) { semantics.write(', $subtitle'); } semantics.write('. Tap to open.'); if (onLongPress != null) { semantics.write(' Long press to ${longPressHint ?? 'change the app'}.'); } if (showEqualizer) semantics.write(' Music playing.'); return Pressable( onTap: onTap, onLongPress: onLongPress, semanticLabel: semantics.toString(), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: size, height: size, decoration: BoxDecoration( color: colors.surface, borderRadius: BorderRadius.circular(size * 0.17), border: Border.all( color: placeholder ? colors.accent.withValues(alpha: 0.16) : colors.border, ), boxShadow: [ BoxShadow( color: colors.shadow.withValues( alpha: Theme.of(context).brightness == Brightness.dark ? 0.2 : 0.04, ), blurRadius: 26, offset: const Offset(0, 10), ), ], ), child: Stack( children: [ Center( child: iconBytes != null ? AppIconImage( bytes: iconBytes, size: (size * 0.36).clamp(28.0, 54.0), ) : AppIcon( iconAsset, size: iconSize, color: placeholder ? colors.inkMuted : colors.ink, ), ), if (placeholder) Positioned( top: size * 0.09, right: size * 0.09, child: Container( width: badgeSize, height: badgeSize, decoration: BoxDecoration( color: colors.accent, shape: BoxShape.circle, ), alignment: Alignment.center, child: AppIcon( 'assets/icons/plus.svg', size: badgeSize * 0.54, color: colors.accentInk, ), ), ), if (showEqualizer) Positioned( left: 0, right: 0, bottom: size * 0.07, child: Center(child: MusicEqualizer(compact: size < 130)), ), ], ), ), const SizedBox(height: 12), Text( title, maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: theme.textTheme.titleMedium?.copyWith(fontSize: titleSize), ), const SizedBox(height: 2), SizedBox( height: 17, child: subtitle == null ? null : Text( subtitle!, maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: theme.textTheme.bodySmall?.copyWith( color: placeholder ? colors.accent : colors.inkMuted, fontWeight: placeholder ? FontWeight.w600 : FontWeight.w400, fontSize: subtitleSize, ), ), ), ], ), ); } }