import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/hover_builder.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/hooks/use_breakpoint_value.dart'; import 'package:spotube/hooks/use_brightness_value.dart'; final htmlTagRegexp = RegExp(r"<[^>]*>", caseSensitive: true); String? useDescription(String? description) { return useMemoized(() { if (description == null) return null; return description.replaceAll(htmlTagRegexp, ''); }, [description]); } class PlaybuttonCard extends HookWidget { final void Function()? onTap; final void Function()? onPlaybuttonPressed; final void Function()? onAddToQueuePressed; final String? description; final EdgeInsetsGeometry? margin; final String imageUrl; final bool isPlaying; final bool isLoading; final String title; final bool isOwner; const PlaybuttonCard({ required this.imageUrl, required this.isPlaying, required this.isLoading, required this.title, this.margin, this.description, this.onPlaybuttonPressed, this.onAddToQueuePressed, this.onTap, this.isOwner = false, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { final textsKey = useMemoized(() => GlobalKey(), []); final theme = Theme.of(context); final radius = BorderRadius.circular(15); final double size = useBreakpointValue( xs: 130, sm: 130, md: 150, others: 170, ); final end = useBreakpointValue( xs: 10, sm: 10, others: 15, ); final textsHeight = useState( (textsKey.currentContext?.findRenderObject() as RenderBox?) ?.size .height ?? 110.00, ); final cleanDescription = useDescription(description); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((_) { textsHeight.value = (textsKey.currentContext?.findRenderObject() as RenderBox?) ?.size .height ?? textsHeight.value; }); return null; }, [textsKey]); return Container( constraints: BoxConstraints(maxWidth: size), margin: margin, child: Material( color: Color.lerp( theme.colorScheme.surfaceVariant, theme.colorScheme.surface, useBrightnessValue(.9, .7), ), borderRadius: radius, shadowColor: theme.colorScheme.background, elevation: 3, child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: onTap, borderRadius: radius, splashFactory: theme.splashFactory, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Stack( clipBehavior: Clip.none, children: [ Padding( padding: const EdgeInsets.only( left: 8, right: 8, top: 8, ), child: ClipRRect( borderRadius: radius, child: UniversalImage( path: imageUrl, placeholder: Assets.albumPlaceholder.path, ), ), ), if (isOwner) Positioned( top: 15, left: 15, child: AnimatedSize( duration: const Duration(milliseconds: 150), alignment: Alignment.centerLeft, curve: Curves.easeInExpo, child: HoverBuilder(builder: (context, isHovered) { return Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: Colors.blueAccent, borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( SpotubeIcons.user, color: Colors.white, size: 16, ), if (isHovered) Text( "Owned by you", style: theme.textTheme.bodySmall?.copyWith( color: Colors.white, ), ), ], ), ); }), ), ), Positioned( right: end, bottom: -15, child: Column( mainAxisSize: MainAxisSize.min, children: [ if (!isPlaying) IconButton( style: IconButton.styleFrom( backgroundColor: theme.colorScheme.background, foregroundColor: theme.colorScheme.primary, minimumSize: const Size.square(10), ), icon: const Icon(SpotubeIcons.queueAdd), onPressed: isLoading ? null : onAddToQueuePressed, ), const SizedBox(height: 5), IconButton( style: IconButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, foregroundColor: theme.colorScheme.primary, minimumSize: const Size.square(10), ), icon: isLoading ? SizedBox.fromSize( size: const Size.square(15), child: const CircularProgressIndicator( strokeWidth: 2), ) : isPlaying ? const Icon(SpotubeIcons.pause) : const Icon(SpotubeIcons.play), onPressed: isLoading ? null : onPlaybuttonPressed, ), ], ), ), ], ), Column( key: textsKey, crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 15), Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), child: AutoSizeText( title, maxLines: 1, minFontSize: theme.textTheme.bodyMedium!.fontSize!, overflow: TextOverflow.ellipsis, ), ), if (cleanDescription != null) Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), child: AutoSizeText( cleanDescription, maxLines: 2, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurface.withOpacity(.5), ), overflow: TextOverflow.ellipsis, ), ), const SizedBox(height: 10), ], ), ], ), ), ), ); } }