| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- import 'package:flutter/material.dart';
- import '../../../core/theme/app_colors.dart';
- import '../../../core/widgets/app_icon.dart';
- import '../../../core/widgets/pressable.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,
- });
- final String title;
- final String? subtitle;
- final String iconAsset;
- final double size;
- final bool assigned;
- final VoidCallback onTap;
- final VoidCallback? onLongPress;
- @override
- Widget build(BuildContext context) {
- final colors = context.colors;
- final theme = Theme.of(context);
- final placeholder = !assigned;
- final iconSize = (size * 0.27).clamp(30.0, 46.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 change.');
- }
- 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: AppIcon(
- iconAsset,
- size: iconSize,
- color: placeholder ? colors.inkMuted : colors.ink,
- ),
- ),
- if (placeholder)
- Positioned(
- top: size * 0.09,
- right: size * 0.09,
- child: Container(
- width: 26,
- height: 26,
- decoration: BoxDecoration(
- color: colors.accent,
- shape: BoxShape.circle,
- ),
- alignment: Alignment.center,
- child: AppIcon(
- 'assets/icons/plus.svg',
- size: 14,
- color: colors.accentInk,
- ),
- ),
- ),
- ],
- ),
- ),
- const SizedBox(height: 12),
- Text(
- title,
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- textAlign: TextAlign.center,
- style: theme.textTheme.titleMedium?.copyWith(
- fontSize: size >= 160 ? 16 : 14,
- ),
- ),
- if (subtitle != null) ...[
- const SizedBox(height: 2),
- SizedBox(
- height: 17,
- child: 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: size >= 160 ? 12 : 11,
- ),
- ),
- ),
- ],
- ],
- ),
- );
- }
- }
|