From 1089e905116714accaf9db97c36134a7108da7af Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 21 Dec 2024 15:21:13 +0600 Subject: [PATCH] refactor: use shadcn CardImage for playbutton card --- .../horizontal_playbutton_card_view.dart | 2 + lib/components/playbutton_card.dart | 237 +++++------------- 2 files changed, 65 insertions(+), 174 deletions(-) diff --git a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 16204952..1093fff0 100644 --- a/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -2,6 +2,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; @@ -90,6 +91,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { ), isLoading: isLoadingNextPage, hasReachedMax: !hasNextPage, + separatorBuilder: (context, index) => const Gap(8.0), itemBuilder: (context, index) { final item = items[index]; diff --git a/lib/components/playbutton_card.dart b/lib/components/playbutton_card.dart index ae9050d8..0b942564 100644 --- a/lib/components/playbutton_card.dart +++ b/lib/components/playbutton_card.dart @@ -1,16 +1,9 @@ -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:gap/gap.dart'; -import 'package:skeletonizer/skeletonizer.dart'; + +import 'package:shadcn_flutter/shadcn_flutter.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/hover_builder.dart'; import 'package:spotube/components/image/universal_image.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/string.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; -import 'package:spotube/hooks/utils/use_brightness_value.dart'; class PlaybuttonCard extends HookWidget { final void Function()? onTap; @@ -40,180 +33,76 @@ class PlaybuttonCard extends HookWidget { @override Widget build(BuildContext context) { - final textsKey = useMemoized(() => GlobalKey(), []); - final theme = Theme.of(context); - final mediaQuery = MediaQuery.of(context); - final radius = BorderRadius.circular(15); - - final double size = useBreakpointValue( - xs: 130, - sm: 130, - md: 150, - others: 170, - ); - - final end = useBreakpointValue( - xs: 7, - sm: 7, - others: 15, - ); - final unescapeHtml = description?.unescapeHtml().cleanHtml(); + return Container( - constraints: BoxConstraints(maxWidth: size), - margin: margin, - child: Material( - color: Color.lerp( - theme.colorScheme.surfaceContainerHighest, - theme.colorScheme.surface, - useBrightnessValue(.9, .7), - ), - borderRadius: radius, - shadowColor: theme.colorScheme.surface, - elevation: 3, - child: InkWell( - mouseCursor: SystemMouseCursors.click, - onTap: onTap, - borderRadius: radius, - splashFactory: theme.splashFactory, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - Container( - margin: const EdgeInsets.fromLTRB(8, 8, 8, 0), - padding: const EdgeInsets.only( - left: 8, - right: 8, - top: 8, - ), - height: mediaQuery.smAndDown - ? 120 - : mediaQuery.mdAndDown - ? 130 - : 150, - decoration: BoxDecoration( - borderRadius: radius, - image: DecorationImage( - image: UniversalImage.imageProvider(imageUrl), - fit: BoxFit.cover, + width: 150, + child: CardImage( + image: Stack( + children: [ + UniversalImage( + path: imageUrl, + fit: BoxFit.cover, + ), + StatedWidget.builder( + builder: (context, states) { + return Positioned( + right: 8, + bottom: 8, + child: Column( + children: [ + AnimatedScale( + curve: Curves.easeOutBack, + duration: const Duration(milliseconds: 300), + scale: states.contains(WidgetState.hovered) ? 1 : 0.7, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: states.contains(WidgetState.hovered) ? 1 : 0, + child: IconButton.secondary( + icon: const Icon(SpotubeIcons.queueAdd), + onPressed: onAddToQueuePressed, + size: ButtonSize.small, + ), + ), ), - ), - ), - if (isOwner) - Positioned( - top: 15, - left: 15, - child: AnimatedSize( + const Gap(5), + AnimatedScale( + curve: Curves.easeOutBack, 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( - context.l10n.owned_by_you, - style: theme.textTheme.bodySmall?.copyWith( - color: Colors.white, - ), - ), - ], - ), - ); - }), - ), - ), - Positioned( - right: end, - bottom: -15, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (!isPlaying) - Skeleton.keep( - child: IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.surface, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), - ), - icon: const Icon(SpotubeIcons.queueAdd), - onPressed: isLoading ? null : onAddToQueuePressed, - ), + scale: states.contains(WidgetState.hovered) ? 1 : 0.7, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 150), + opacity: states.contains(WidgetState.hovered) ? 1 : 0, + child: IconButton.secondary( + icon: const Icon(SpotubeIcons.play), + onPressed: onPlaybuttonPressed, + size: ButtonSize.small, ), - const Gap(5), - IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.primaryContainer, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), - ), - icon: Skeleton.keep( - child: 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 (description != null) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: AutoSizeText( - unescapeHtml!, - maxLines: 2, - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurface.withOpacity(.5), - ), - overflow: TextOverflow.ellipsis, ), - ), - const SizedBox(height: 10), - ], - ), - ], + ], + ), + ); + }, + ) + ], + ), + title: Tooltip( + tooltip: Text(title), + child: Text( + title, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ), + subtitle: unescapeHtml == null + ? null + : Text( + unescapeHtml, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + onPressed: onTap, ), ); }