import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:dots_indicator/dots_indicator.dart'; import 'package:lba/gen/assets.gen.dart'; import 'package:lba/res/colors.dart'; import 'package:lba/widgets/remainingTime.dart'; import 'package:lba/widgets/search_bar.dart'; class Discover extends StatefulWidget { const Discover({super.key}); @override State createState() => _DiscoverState(); } class _DiscoverState extends State with TickerProviderStateMixin { final PageController _pageController = PageController(); double _currentPage = 0; late AnimationController _staggeredController; late List> _staggeredAnimations; final Map _filters = { 'Top 10 Offers': true, 'Flash Sale': true, 'special discount': false, 'Occasion Specials': true, 'First Purchase': false, }; final List categoryIcons = [ Assets.icons.stashStarsLight.path, Assets.icons.hugeiconsBabyBoyDress.path, Assets.icons.girlClothes.path, Assets.icons.gameIconsWinterGloves.path, Assets.icons.hugeiconsCheeseCake01.path, Assets.icons.ionFastFoodOutline.path, Assets.icons.healthiconsFruitsOutline.path, ]; @override void initState() { super.initState(); _pageController.addListener(() { if (_pageController.hasClients) { setState(() { _currentPage = _pageController.page!; }); } }); _staggeredController = AnimationController( vsync: this, duration: const Duration(milliseconds: 1500), ); final int itemCount = 8; _staggeredAnimations = List.generate(itemCount, (index) { return Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation( parent: _staggeredController, curve: Interval( (0.1 * index), (0.5 + 0.1 * index).clamp(0.0, 1.0), curve: Curves.easeOutCubic, ), ), ); }); _staggeredController.forward(); } @override void dispose() { _pageController.dispose(); _staggeredController.dispose(); super.dispose(); } Widget _buildAnimatedSection(Widget child, int index) { return FadeTransition( opacity: _staggeredAnimations[index], child: SlideTransition( position: Tween( begin: const Offset(0.0, 0.3), end: Offset.zero, ).animate(_staggeredAnimations[index]), child: child, ), ); } void _showFilterMenu() { showGeneralDialog( context: context, barrierDismissible: true, barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierColor: AppColors.textPrimary.withOpacity(0.1), transitionDuration: const Duration(milliseconds: 400), pageBuilder: (context, animation1, animation2) { return BackdropFilter( filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0), child: Align( alignment: Alignment.topRight, child: Container( width: 250, margin: const EdgeInsets.only(top: kToolbarHeight + 65, right: 16), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: AppColors.textPrimary.withOpacity(0.1), blurRadius: 10, spreadRadius: 5, ) ], ), child: StatefulBuilder( builder: (context, setDialogState) { return Column( mainAxisSize: MainAxisSize.min, children: _filters.keys.map((String filterName) { return Material( color: Colors.transparent, child: InkWell( onTap: () { setDialogState(() { setState(() { _filters[filterName] = !_filters[filterName]!; }); }); }, child: Padding( padding: const EdgeInsets.symmetric( horizontal: 18.0, vertical: 12.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( filterName, style: const TextStyle(fontSize: 16), ), _buildCustomCheckbox( _filters[filterName]!), ], ), ), ), ); }).toList(), ); }, ), ), ), ); }, transitionBuilder: (context, animation, secondaryAnimation, child) { final curvedAnimation = CurvedAnimation( parent: animation, curve: Curves.easeOutCubic, reverseCurve: Curves.easeInCubic, ); return ScaleTransition( scale: Tween(begin: 0.8, end: 1.0).animate(curvedAnimation), alignment: Alignment.topRight, child: FadeTransition( opacity: curvedAnimation, child: SlideTransition( position: Tween( begin: const Offset(0.2, -0.2), end: Offset.zero, ).animate(curvedAnimation), child: child, ), ), ); }, ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.surface, appBar: _buildAppBar(), body: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildAnimatedSection( Padding( padding: const EdgeInsets.only(right: 16.0), child: Row( children: [ const Expanded(child: SearchBarWidget()), const SizedBox(width: 10), _buildFilterButton(), ], ), ), 0, ), const SizedBox(height: 16), _buildAnimatedSection( _buildSectionTitle("what's on your mind?"), 1), const SizedBox(height: 12), _buildAnimatedSection(_buildCategoryIcons(), 2), const SizedBox(height: 24), _buildAnimatedSection( _buildSectionTitle("Top 10 Discount & Offers"), 3), const SizedBox(height: 12), _buildAnimatedSection(_buildTopOffersSection(), 4), const SizedBox(height: 24), _buildAnimatedSection( _buildSectionTitle("Flash Sale", showSeeAll: true, onSeeAllTap: () {}), 5), const SizedBox(height: 12), _buildAnimatedSection(_buildFlashSaleSection(), 6), const SizedBox(height: 24), _buildAnimatedSection( _buildSectionTitle("Special Discount"), 7), const SizedBox(height: 12), _buildAnimatedSection(_buildSpecialDiscountSection(), 1), const SizedBox(height: 24), _buildAnimatedSection( _buildSectionTitle("Seasonal Discount", showSeeAll: true, onSeeAllTap: () {}), 2), const SizedBox(height: 12), _buildAnimatedSection(_buildSeasonalDiscountSection(), 3), const SizedBox(height: 24), _buildAnimatedSection( _buildSectionTitle("Occasion Specials"), 4), const SizedBox(height: 12), _buildAnimatedSection(_buildCraftingSomethingSection(), 5), const SizedBox(height: 24), _buildAnimatedSection( _buildSectionTitle("First Purchase Discount", showSeeAll: true, onSeeAllTap: () {}), 6), const SizedBox(height: 12), _buildAnimatedSection(_buildFirstPurchaseSection(), 7), const SizedBox(height: 100), ], ), ), ); } PreferredSizeWidget _buildAppBar() { return AppBar( elevation: 0, backgroundColor: AppColors.scaffoldBackground, title: Row( children: [ SvgPicture.asset(Assets.icons.lBALogo.path, height: 32), const SizedBox(width: 8), Text( "Proxibuy", style: TextStyle( color: AppColors.hintTitle, fontWeight: FontWeight.normal, fontSize: 24, ), ), ], ), actions: [ IconButton( icon: SvgPicture.asset(Assets.icons.notificationBing.path, color: AppColors.isDarkMode ? AppColors.textPrimary : null), onPressed: () {}, ), const SizedBox(width: 8), ], ); } Widget _buildFilterButton() { return Container( width: 48, height: 48, decoration: BoxDecoration( color: AppColors.isDarkMode ? AppColors.primary : const Color.fromARGB(255, 14, 63, 102), borderRadius: BorderRadius.circular(12), ), child: IconButton( icon: SvgPicture.asset(Assets.icons.sort.path, color: AppColors.surface), onPressed: _showFilterMenu, ), ); } Widget _buildCustomCheckbox(bool isChecked) { return AnimatedContainer( duration: const Duration(milliseconds: 200), curve: Curves.easeInOut, width: 24, height: 24, decoration: BoxDecoration( color: isChecked ? AppColors.primary : Colors.transparent, border: isChecked ? null : Border.all( color: const Color.fromARGB(255, 89, 93, 98), width: 2), borderRadius: BorderRadius.circular(6), ), child: AnimatedSwitcher( duration: const Duration(milliseconds: 200), transitionBuilder: (child, animation) { return ScaleTransition( scale: animation, child: FadeTransition( opacity: animation, child: child, ), ); }, child: isChecked ? Icon( Icons.check, color: AppColors.surface, size: 18, key: ValueKey('checked'), ) : const SizedBox( key: ValueKey('unchecked'), ), ), ); } Widget _buildCategoryIcons() { return SizedBox( height: 50, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: categoryIcons.length, padding: const EdgeInsets.symmetric(horizontal: 16), itemBuilder: (context, index) { final isFirstIcon = index == 0; final backgroundColor = isFirstIcon ? (AppColors.isDarkMode ? AppColors.primary.withOpacity(0.3) : const Color.fromRGBO(186, 222, 251, 1)) : (AppColors.isDarkMode ? AppColors.cardBackground : const Color(0xFFF3F4F6)); final iconColor = isFirstIcon ? (AppColors.isDarkMode ? AppColors.primary : const Color.fromARGB(255, 14, 63, 102)) : AppColors.secondaryText; return Container( width: 50, height: 50, padding: const EdgeInsets.all(11), decoration: BoxDecoration( color: backgroundColor, borderRadius: BorderRadius.circular(12), ), child: SvgPicture.asset(categoryIcons[index], color: iconColor), ); }, separatorBuilder: (context, index) => const SizedBox(width: 12), ), ); } Widget _buildTopOffersSection() { return Column( children: [ SizedBox( height: 180, child: PageView( controller: _pageController, children: [ _buildOfferBanner(), _buildOfferBanner(), _buildOfferBanner(), ], ), ), const SizedBox(height: 12), DotsIndicator( dotsCount: 3, position: _currentPage, decorator: DotsDecorator( color: AppColors.divider, activeColor: AppColors.primary, size: const Size.square(8.0), activeSize: const Size(20.0, 8.0), activeShape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), ), ), ), ], ); } Widget _buildOfferBanner() { return Container( margin: const EdgeInsets.symmetric(horizontal: 16), child: Stack( children: [ ClipRRect( borderRadius: BorderRadius.circular(15), child: Image.asset( Assets.images.image.path, height: 180, width: double.infinity, fit: BoxFit.cover, ), ), Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ AppColors.shadowColor.withOpacity(0.6), AppColors.shadowColor.withOpacity(0.1), ], ), ), ), Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), decoration: BoxDecoration( color: AppColors.surface.withOpacity(0.8), borderRadius: BorderRadius.circular(8), ), child: Text( "65% OFF", style: TextStyle( color: AppColors.offerTimer, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 8), Text( "NEW COLLECTION", style: TextStyle( color: AppColors.surface, fontSize: 22, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Row( children: [ _buildTimeBox("12"), _buildTimeSeparator(), _buildTimeBox("25"), _buildTimeSeparator(), _buildTimeBox("14"), ], ), ], ), ), ], ), ); } Widget _buildTimeBox(String time) { return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(4), ), child: Text( time, style: TextStyle( color: AppColors.textPrimary, fontWeight: FontWeight.bold, ), ), ); } Widget _buildTimeSeparator() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), child: Text( ":", style: TextStyle( color: AppColors.surface, fontSize: 16, fontWeight: FontWeight.bold, ), ), ); } Widget _buildSectionTitle(String title, {bool showSeeAll = false, VoidCallback? onSeeAllTap}) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.normal, color: AppColors.textPrimary), ), const SizedBox(width: 8), Expanded( child: Divider(color: AppColors.divider, thickness: 1), ), if (showSeeAll) ...[ const SizedBox(width: 8), InkWell( onTap: onSeeAllTap, child: Row( children: [ Text( 'See all', style: TextStyle( color: AppColors.primary, fontSize: 14, fontWeight: FontWeight.w500, ), ), const SizedBox(width: 7), SvgPicture.asset( Assets.icons.arrowRight.path, color: AppColors.primary, ), ], ), ), ], ], ), ); } Widget _buildFlashSaleSection() { return SizedBox( height: 310, child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16), children: [ SizedBox( width: 250, child: FlashSaleCard( imagePath: Assets.images.media.path, title: "Amul Cheese Slices", location: "Fresno (750m away)", originalPrice: "70", discountedPrice: "53", discountPercent: "13", expiryTimeString: DateTime.now() .add(const Duration(hours: 8, minutes: 35)) .millisecondsSinceEpoch .toString(), categoryIconPath: Assets.icons.phCheese.path, ), ), const SizedBox(width: 16), SizedBox( width: 250, child: FlashSaleCard( imagePath: Assets.images.wp1929534FastFoodWallpapers1.path, title: "Tulip Luncheon Meat", location: "Fresno (2km away)", originalPrice: "370", discountedPrice: "194", discountPercent: "50", expiryTimeString: DateTime.now() .add(const Duration(hours: 12, minutes: 45)) .millisecondsSinceEpoch .toString(), categoryIconPath: Assets.icons.shop.path, ), ), ], ), ); } Widget _buildSpecialDiscountSection() { return Container( height: 180, margin: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), image: DecorationImage( image: AssetImage( Assets.images.wp1929534FastFoodWallpapers1.path), fit: BoxFit.cover, ), ), ); } Widget _buildSeasonalDiscountSection() { final List> seasonalItems = [ { "title": "Boots", "brand": "Columbia Sportswear", "discount": "22 - 35% off", "imagePath": Assets.images.image.path, }, { "title": "Hoodie", "brand": "The North Face", "discount": "22 - 35% off", "imagePath": Assets.images.topDealsAndStores.path, }, { "title": "Hats", "brand": "Patagonia", "discount": "10 - 15% off", "imagePath": Assets.images.image.path, }, { "title": "Jacket", "brand": "Arc'teryx", "discount": "20% off", "imagePath": Assets.images.topDealsAndStores.path, }, { "title": "Backpack", "brand": "Osprey", "discount": "15% off", "imagePath": Assets.images.image.path, }, { "title": "Gloves", "brand": "Nike", "discount": "Up to 40% off", "imagePath": Assets.images.topDealsAndStores.path, }, ]; final screenWidth = MediaQuery.of(context).size.width; final cardWidth = screenWidth * 0.8; final int itemCount = (seasonalItems.length / 2).ceil(); return SizedBox( height: 110 * 2 + 16, child: ListView.builder( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: itemCount, itemBuilder: (context, index) { final topIndex = index * 2; final bottomIndex = topIndex + 1; final topCard = SeasonalDiscountCard( title: seasonalItems[topIndex]['title']!, brand: seasonalItems[topIndex]['brand']!, discount: seasonalItems[topIndex]['discount']!, imagePath: seasonalItems[topIndex]['imagePath']!, width: cardWidth, ); Widget bottomCard; if (bottomIndex < seasonalItems.length) { bottomCard = SeasonalDiscountCard( title: seasonalItems[bottomIndex]['title']!, brand: seasonalItems[bottomIndex]['brand']!, discount: seasonalItems[bottomIndex]['discount']!, imagePath: seasonalItems[bottomIndex]['imagePath']!, width: cardWidth, ); } else { bottomCard = SizedBox(width: cardWidth); } return Padding( padding: const EdgeInsets.only(right: 16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ topCard, const SizedBox(height: 16), bottomCard, ], ), ); }, ), ); } Widget _buildCraftingSomethingSection() { return Container( height: 120, margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), image: DecorationImage( image: AssetImage(Assets.images.image.path), fit: BoxFit.cover, colorFilter: ColorFilter.mode( Colors.black.withOpacity(0.4), BlendMode.darken, ), ), ), child: const Center( child: Text( "Crafting something for you\nTell us your birthday and unlock special Dineout treats!", textAlign: TextAlign.center, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), ); } Widget _buildFirstPurchaseSection() { return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Container( margin: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.isDarkMode?DarkAppColors.cardBackground: Color(0xFFE3F2FD), borderRadius: BorderRadius.circular(15), ), child: Row( children: [ FirstPurchaseCard( title: "McDonald's", category: "Fast Food", discount: "Up to 25% Off", rating: 4.2, imagePath: Assets.images.wp1929534FastFoodWallpapers1.path, ), const SizedBox(width: 16), FirstPurchaseCard( title: "Cafe Monarch", category: "Cafe", discount: "Up to 25% Off", rating: 4.9, imagePath: Assets.images.media.path, ), // For testing with more cards: // const SizedBox(width: 16), // FirstPurchaseCard( // title: "Another Cafe", // category: "Cafe", // discount: "15% Off", // rating: 4.5, // imagePath: Assets.images.media.path, // ), ], ), ), ); } } class FlashSaleCard extends StatelessWidget { final String imagePath; final String title; final String location; final String originalPrice; final String discountedPrice; final String discountPercent; final String expiryTimeString; final String categoryIconPath; const FlashSaleCard({ super.key, required this.imagePath, required this.title, required this.location, required this.originalPrice, required this.discountedPrice, required this.discountPercent, required this.expiryTimeString, required this.categoryIconPath, }); @override Widget build(BuildContext context) { final timer = RemainingTime() ..initializeFromExpiry(expiryTime: expiryTimeString); return Container( decoration: BoxDecoration( color: AppColors.cardBackground, borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(8, 8, 8, 4), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ Center( child: SvgPicture.asset( Assets.icons.timer.path, color: AppColors.offerTimer, height: 20, ), ), const SizedBox(width: 10), Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Limited time deal", style: TextStyle( color: AppColors.textPrimary, fontSize: 12, fontWeight: FontWeight.bold, ), ), ValueListenableBuilder( valueListenable: timer.remainingSeconds, builder: (context, _, __) => Text( timer.formatTime(), style: TextStyle( color: AppColors.offerTimer, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), const SizedBox( height: 5, ) ], ), ], ), ), Image.asset( imagePath, height: 110, width: double.infinity, fit: BoxFit.cover, ), Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ SvgPicture.asset( categoryIconPath, color: AppColors.textSecondary, width: 18, ), const SizedBox(width: 8), Expanded( child: Text( title, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14, color: AppColors.textPrimary, ), ), ), ], ), const SizedBox(height: 8), Row( children: [ SvgPicture.asset( Assets.icons.location.path, color: AppColors.textSecondary, width: 18, ), const SizedBox(width: 4), Text( location, style: TextStyle( color: AppColors.offerCardDetail, fontSize: 12), ), ], ), const SizedBox(height: 8), Row( children: [ SvgPicture.asset( Assets.icons.coin.path, color: AppColors.textSecondary, width: 18, ), const SizedBox(width: 4), Text.rich( TextSpan( style: TextStyle( fontSize: 12, color: AppColors.offerCardDetail, ), children: [ TextSpan( text: '$originalPrice\$', style: const TextStyle( decoration: TextDecoration.lineThrough, ), ), TextSpan( text: ' - $discountedPrice\$', style: TextStyle( color: AppColors.offerCardDetail, fontWeight: FontWeight.normal, fontSize: 14, decoration: TextDecoration.none, ), ), ], ), ), const SizedBox( width: 10, ), Text( '($discountPercent% off)', style: TextStyle( color: AppColors.confirmButton, fontSize: 14, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), border: Border.all( color: AppColors.confirmButton, width: 1.0), color: Colors.transparent, ), child: Padding( padding: const EdgeInsets.fromLTRB(8, 4, 8, 4), child: Row( children: [ SvgPicture.asset( Assets.icons.cardPos.path, color: AppColors.textSecondary, height: 17, ), const SizedBox(width: 4), Text( "Delivery", style: TextStyle( color: AppColors.textSecondary, fontWeight: FontWeight.w500, fontSize: 12, ), ), ], ), ), ), const SizedBox(width: 8), Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), border: Border.all( color: AppColors.confirmButton, width: 1.0), color: Colors.transparent, ), child: Padding( padding: const EdgeInsets.fromLTRB(8, 4, 8, 4), child: Row( children: [ SvgPicture.asset( Assets.icons.shoppingCart.path, color: AppColors.textSecondary, height: 17, ), const SizedBox(width: 4), Text( "Pickup", style: TextStyle( color: AppColors.textSecondary, fontWeight: FontWeight.w500, fontSize: 12, ), ), ], ), ), ), ], ), ], ), ), ], ), ); } } class SeasonalDiscountCard extends StatelessWidget { final String title; final String brand; final String discount; final String imagePath; final double width; const SeasonalDiscountCard({ super.key, required this.title, required this.brand, required this.discount, required this.imagePath, required this.width, }); @override Widget build(BuildContext context) { return SizedBox( width: width, height: 110, child: ClipRRect( borderRadius: BorderRadius.circular(16), child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.divider), ), child: Row( children: [ Expanded( flex: 2, child: Container( color: AppColors.cardBackground, child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildDetailRow( icon: Assets.icons.winter.path, text: title, textStyle: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, color: AppColors.textPrimary, ), ), _buildDetailRow( icon: Assets.icons.shop.path, text: brand, textStyle: TextStyle( color: AppColors.textPrimary, fontSize: 12, ), ), _buildDetailRow( icon: Assets.icons.icRoundLocalOffer.path, text: discount, textStyle: TextStyle( color: AppColors.offerTimer, fontWeight: FontWeight.normal, fontSize: 14, ), ), ], ), ), ), ), Expanded( flex: 1, child: Image.asset( imagePath, height: double.infinity, fit: BoxFit.cover, ), ), ], ), ), ), ); } Widget _buildDetailRow({ required String icon, required String text, required TextStyle textStyle, }) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(top: 2.0), child: SvgPicture.asset( icon, width: 20, ), ), const SizedBox(width: 8), Expanded( child: Text( text, style: textStyle, softWrap: true, overflow: TextOverflow.ellipsis, ), ), ], ); } } class FirstPurchaseCard extends StatelessWidget { final String title; final String category; final String discount; final double rating; final String imagePath; const FirstPurchaseCard({ super.key, required this.title, required this.category, required this.discount, required this.rating, required this.imagePath, }); @override Widget build(BuildContext context) { return SizedBox( width: 160, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(12)), child: Image.asset( imagePath, height: 120, width: double.infinity, fit: BoxFit.cover, ), ), Padding( padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 15, color: AppColors.textPrimary, ), ), const SizedBox(height: 5), Text( category, style: TextStyle( color: AppColors.textSecondary, fontSize: 14), ), const SizedBox(height: 5), Text( discount, style: TextStyle( fontWeight: FontWeight.w500, color: AppColors.textSecondary), ), const SizedBox(height: 5), Row( children: [ SvgPicture.asset(Assets.icons.star.path, width: 16,), const SizedBox(width: 4), Text( rating.toString(), style: TextStyle( color: AppColors.textSecondary, fontWeight: FontWeight.w500, ), ), ], ), ], ), ), ], ), ); } }