| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- 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: SizedBox(
- width: size,
- 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,
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
- }
|