add some features to product details

This commit is contained in:
mohamadmahdi jebeli 2025-08-16 16:08:09 +03:30
parent fb2119548e
commit af14d2d7fc
5 changed files with 584 additions and 219 deletions

View File

@ -126,7 +126,7 @@ class _DiscoverState extends State<Discover> with TickerProviderStateMixin {
const SizedBox(height: 12), const SizedBox(height: 12),
_buildAnimatedSection(_buildSeasonalDiscountSection(), 3), _buildAnimatedSection(_buildSeasonalDiscountSection(), 3),
const SizedBox(height: 24), const SizedBox(height: 24),
_buildAnimatedSection(_buildSectionTitle("Crafting something for you"), 4), _buildAnimatedSection(_buildSectionTitle("Occasion Specials"), 4),
const SizedBox(height: 12), const SizedBox(height: 12),
_buildAnimatedSection(_buildCraftingSomethingSection(), 5), _buildAnimatedSection(_buildCraftingSomethingSection(), 5),
const SizedBox(height: 24), const SizedBox(height: 24),
@ -483,7 +483,7 @@ class _DiscoverState extends State<Discover> with TickerProviderStateMixin {
final int itemCount = (seasonalItems.length / 2).ceil(); final int itemCount = (seasonalItems.length / 2).ceil();
return SizedBox( return SizedBox(
height: 110 * 2 + 16, // Height for two cards + spacing height: 110 * 2 + 16,
child: ListView.builder( child: ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
@ -958,12 +958,8 @@ class FirstPurchaseCard extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return SizedBox(
width: 160, width: 160,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade200),
),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [

View File

@ -6,6 +6,7 @@ import 'package:lba/gen/assets.gen.dart';
import 'package:lba/res/colors.dart'; import 'package:lba/res/colors.dart';
import 'package:lba/widgets/buildWarpedInfo.dart'; import 'package:lba/widgets/buildWarpedInfo.dart';
import 'package:lba/widgets/orderType.dart'; import 'package:lba/widgets/orderType.dart';
import 'package:lba/widgets/price_reserve_widget.dart';
import 'package:lba/widgets/rate.dart'; import 'package:lba/widgets/rate.dart';
import 'package:lba/widgets/reviews.dart'; import 'package:lba/widgets/reviews.dart';
@ -82,14 +83,14 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
displayedReviews = reviews.length > 2 ? reviews.sublist(0, 2) : List.from(reviews); displayedReviews =
reviews.length > 2 ? reviews.sublist(0, 2) : List.from(reviews);
_staggeredController = AnimationController( _staggeredController = AnimationController(
vsync: this, vsync: this,
duration: const Duration(milliseconds: 1200), duration: const Duration(milliseconds: 1200),
); );
// --- FIX: Changed itemCount from 7 to 8 ---
final int itemCount = 8; final int itemCount = 8;
_staggeredAnimations = List.generate(itemCount, (index) { _staggeredAnimations = List.generate(itemCount, (index) {
return Tween<double>(begin: 0.0, end: 1.0).animate( return Tween<double>(begin: 0.0, end: 1.0).animate(
@ -116,7 +117,7 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
void _showAllReviewsWithAnimation() async { void _showAllReviewsWithAnimation() async {
final newItems = reviews.sublist(displayedReviews.length); final newItems = reviews.sublist(displayedReviews.length);
for (int i = 0; i < newItems.length; i++) { for (int i = 0; i < newItems.length; i++) {
await Future.delayed(Duration(milliseconds: 150)); await Future.delayed(const Duration(milliseconds: 150));
displayedReviews.add(newItems[i]); displayedReviews.add(newItems[i]);
_listKey.currentState?.insertItem(displayedReviews.length - 1); _listKey.currentState?.insertItem(displayedReviews.length - 1);
setState(() {}); setState(() {});
@ -143,7 +144,6 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -152,20 +152,21 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
widget.title, widget.title,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
), ),
), ),
0, 0,
), ),
SizedBox(height: 5), const SizedBox(height: 5),
_buildAnimatedWidget( _buildAnimatedWidget(
Row( Row(
children: [ children: [
Text("Brand: "), const Text("Brand: "),
Expanded( Expanded(
child: Text( child: Text(
widget.brand, widget.brand,
style: TextStyle(color: LightAppColors.primary), style: const TextStyle(color: LightAppColors.primary),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
@ -173,13 +174,13 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
), ),
1, 1,
), ),
SizedBox(height: 10), const SizedBox(height: 10),
_buildAnimatedWidget( _buildAnimatedWidget(
Row( Row(
children: [ children: [
CustomStarRating(rating: 4.8), const CustomStarRating(rating: 4.8),
SizedBox(width: 3), const SizedBox(width: 3),
Text( const Text(
"4.8", "4.8",
style: TextStyle(color: LightAppColors.productDetailDivider), style: TextStyle(color: LightAppColors.productDetailDivider),
), ),
@ -187,7 +188,7 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
), ),
2, 2,
), ),
SizedBox(height: 15), const SizedBox(height: 15),
_buildAnimatedWidget( _buildAnimatedWidget(
Row( Row(
children: [ children: [
@ -196,7 +197,7 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
typename: "Delivery", typename: "Delivery",
fill: true, fill: true,
), ),
SizedBox(width: 7), const SizedBox(width: 7),
OrderType( OrderType(
icon: Assets.icons.shoppingCart.path, icon: Assets.icons.shoppingCart.path,
typename: "Pickup", typename: "Pickup",
@ -206,24 +207,26 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
), ),
3, 3,
), ),
SizedBox(height: 15), const SizedBox(height: 15),
_buildAnimatedWidget(buildWrappedInfo("Dimensions:", widget.dimensions), 4), _buildAnimatedWidget(
buildWrappedInfo("Dimensions:", widget.dimensions), 4),
_buildAnimatedWidget(buildWrappedInfo("Colour:", widget.colour), 5), _buildAnimatedWidget(buildWrappedInfo("Colour:", widget.colour), 5),
_buildAnimatedWidget(buildWrappedInfo("Material:", widget.material), 6), _buildAnimatedWidget(
_buildAnimatedWidget(buildWrappedInfo("Description:", widget.description), 7), // Now this is valid buildWrappedInfo("Material:", widget.material), 6),
SizedBox(height: 30), _buildAnimatedWidget(
Center( buildWrappedInfo("Description:", widget.description), 7),
const SizedBox(height: 30),
const Center(
child: Text( child: Text(
"Top reviews from the United Arab Emirates", "Top reviews from the United Arab Emirates",
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
), ),
), ),
SizedBox(height: 15), const SizedBox(height: 15),
AnimatedList( AnimatedList(
key: _listKey, key: _listKey,
shrinkWrap: true, shrinkWrap: true,
physics: NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
initialItemCount: displayedReviews.length, initialItemCount: displayedReviews.length,
itemBuilder: (context, index, animation) { itemBuilder: (context, index, animation) {
final review = displayedReviews[index]; final review = displayedReviews[index];
@ -231,7 +234,8 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
position: Tween<Offset>( position: Tween<Offset>(
begin: const Offset(-1, 0), begin: const Offset(-1, 0),
end: Offset.zero, end: Offset.zero,
).animate(CurvedAnimation(parent: animation, curve: Curves.easeInOut)), ).animate(CurvedAnimation(
parent: animation, curve: Curves.easeInOut)),
child: SizeTransition( child: SizeTransition(
sizeFactor: animation, sizeFactor: animation,
axisAlignment: -1, axisAlignment: -1,
@ -247,7 +251,6 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
); );
}, },
), ),
if (!showAllReviews && reviews.length > 2) if (!showAllReviews && reviews.length > 2)
Column( Column(
children: [ children: [
@ -257,7 +260,7 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( const Text(
"See all reviews", "See all reviews",
style: TextStyle( style: TextStyle(
color: LightAppColors.allReviewOpener, color: LightAppColors.allReviewOpener,
@ -265,7 +268,7 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
fontSize: 18, fontSize: 18,
), ),
), ),
SizedBox(width: 10), const SizedBox(width: 10),
SvgPicture.asset( SvgPicture.asset(
Assets.icons.arrowDown.path, Assets.icons.arrowDown.path,
color: LightAppColors.allReviewOpener, color: LightAppColors.allReviewOpener,
@ -274,12 +277,12 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
), ),
), ),
), ),
SizedBox(height: 50,)
], ],
), ),
const SizedBox(height: 20),
const PriceReserveWidget(),
], ],
), ),
),
); );
} }
} }

View File

@ -9,6 +9,7 @@ import 'package:lba/widgets/customCard.dart';
import 'package:lba/widgets/dividerTitle.dart'; import 'package:lba/widgets/dividerTitle.dart';
import 'package:lba/widgets/openChecker.dart'; import 'package:lba/widgets/openChecker.dart';
import 'package:lba/widgets/rate.dart'; import 'package:lba/widgets/rate.dart';
import 'package:lba/widgets/similar_business_card.dart';
import 'package:maps_launcher/maps_launcher.dart'; import 'package:maps_launcher/maps_launcher.dart';
class Shop extends StatefulWidget { class Shop extends StatefulWidget {
@ -39,7 +40,28 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
late AnimationController _staggeredController; late AnimationController _staggeredController;
late List<Animation<double>> _staggeredAnimations; late List<Animation<double>> _staggeredAnimations;
late AnimationController _listAnimationController;
late List<Animation<double>> _itemAnimations;
late AnimationController _similarBusinessAnimationController;
late List<Animation<double>> _similarBusinessAnimations;
final List<Map<String, String>> similarBusinesses = [
{
"imagePath": Assets.images.image.path,
"name": "The Odd Piece",
"location": "Al Quoz 1",
},
{
"imagePath": Assets.images.topDealsAndStores.path,
"name": "IKEA",
"location": "Dubai Festival City",
},
{
"imagePath": Assets.images.media.path,
"name": "Home Centre",
"location": "Mall of the Emirates",
}
];
@override @override
void initState() { void initState() {
@ -51,7 +73,17 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
duration: const Duration(milliseconds: 1200), duration: const Duration(milliseconds: 1200),
); );
final int itemCount = 8; _listAnimationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1000),
);
_similarBusinessAnimationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1200),
);
final int itemCount = 9;
_staggeredAnimations = List.generate(itemCount, (index) { _staggeredAnimations = List.generate(itemCount, (index) {
return Tween<double>(begin: 0.0, end: 1.0).animate( return Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation( CurvedAnimation(
@ -65,12 +97,43 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
); );
}); });
_itemAnimations = List.generate(2, (index) {
return Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _listAnimationController,
curve: Interval(
(0.2 * index),
(0.6 + 0.2 * index).clamp(0.0, 1.0),
curve: Curves.easeOut,
),
),
);
});
_similarBusinessAnimations =
List.generate(similarBusinesses.length, (index) {
return Tween<double>(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent: _similarBusinessAnimationController,
curve: Interval(
(0.2 * index),
(0.6 + 0.2 * index).clamp(0.0, 1.0),
curve: Curves.easeOut,
),
),
);
});
_staggeredController.forward(); _staggeredController.forward();
_listAnimationController.forward();
_similarBusinessAnimationController.forward();
} }
@override @override
void dispose() { void dispose() {
_staggeredController.dispose(); _staggeredController.dispose();
_listAnimationController.dispose();
_similarBusinessAnimationController.dispose();
super.dispose(); super.dispose();
} }
@ -115,30 +178,33 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
color: Colors.black, color: Colors.black,
height: 25, height: 25,
), ),
SizedBox(width: 10), const SizedBox(width: 10),
Text( Text(
widget.shopName, widget.shopName,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 17), style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 17),
), ),
], ],
), ),
0, 0,
), ),
SizedBox(height: 15), const SizedBox(height: 15),
_buildAnimatedWidget( _buildAnimatedWidget(
Row( Row(
children: [ children: [
CustomStarRating(rating: widget.star), CustomStarRating(rating: widget.star),
SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
widget.star.toString(), widget.star.toString(),
style: TextStyle(color: LightAppColors.productDetailDivider), style: const TextStyle(
color: LightAppColors.productDetailDivider,
),
), ),
], ],
), ),
1, 1,
), ),
SizedBox(height: 5), const SizedBox(height: 5),
_buildAnimatedWidget( _buildAnimatedWidget(
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -149,10 +215,10 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
Assets.icons.location.path, Assets.icons.location.path,
color: Colors.black, color: Colors.black,
), ),
SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
selectedPlace, selectedPlace,
style: TextStyle( style: const TextStyle(
color: LightAppColors.productDetailDivider, color: LightAppColors.productDetailDivider,
), ),
), ),
@ -183,47 +249,50 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
), ),
2, 2,
), ),
SizedBox(height: 5), const SizedBox(height: 5),
_buildAnimatedWidget( _buildAnimatedWidget(
Row( Row(
children: [ children: [
SvgPicture.asset(Assets.icons.clock.path), SvgPicture.asset(Assets.icons.clock.path),
SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
isOpen ? 'Open Now' : 'Closed', isOpen ? 'Open Now' : 'Closed',
style: TextStyle(color: isOpen ? Colors.green : Colors.red), style: TextStyle(color: isOpen ? Colors.green : Colors.red),
), ),
SizedBox(width: 5), const SizedBox(width: 5),
Container( Container(
color: LightAppColors.productDetailDivider, color: LightAppColors.productDetailDivider,
width: 1, width: 1,
height: 13, height: 13,
), ),
SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
timeRange, timeRange,
style: TextStyle(color: LightAppColors.productDetailDivider), style: const TextStyle(
color: LightAppColors.productDetailDivider,
),
), ),
], ],
), ),
3, 3,
), ),
SizedBox(height: 15), const SizedBox(height: 15),
_buildAnimatedWidget(DividerTitleWidget(title: "Facilities"), 4), _buildAnimatedWidget(
const DividerTitleWidget(title: "Facilities"), 4),
_buildAnimatedWidget( _buildAnimatedWidget(
SizedBox( SizedBox(
height: 50, height: 50,
child: ListView.builder( child: ListView.builder(
physics: NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemCount: 1, itemCount: 1,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Row( return Row(
children: [ children: [
SvgPicture.asset(Assets.icons.tick.path), SvgPicture.asset(Assets.icons.tick.path),
SizedBox(width: 5), const SizedBox(width: 5),
Text( Text(
widget.facilities, widget.facilities,
style: TextStyle( style: const TextStyle(
color: LightAppColors.productDetailDivider, color: LightAppColors.productDetailDivider,
), ),
), ),
@ -234,7 +303,7 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
), ),
5, 5,
), ),
SizedBox(height: 20), const SizedBox(height: 20),
_buildAnimatedWidget( _buildAnimatedWidget(
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
@ -254,31 +323,26 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
Assets.icons.routing2.path, Assets.icons.routing2.path,
color: Colors.black, color: Colors.black,
), ),
SizedBox(width: 5), const SizedBox(width: 5),
Text( const Text(
"Direction", "Direction",
style: const TextStyle( style: TextStyle(color: Colors.black, fontSize: 16),
color: Colors.black,
fontSize: 16,
),
), ),
], ],
), ),
), ),
6, 6,
), ),
SizedBox(height: 30), const SizedBox(height: 30),
_buildAnimatedWidget( _buildAnimatedWidget(
Text( const Text(
"List of offers", "List of offers",
style: TextStyle( style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
fontWeight: FontWeight.bold,
fontSize: 18,
),
), ),
7, 7,
), ),
SizedBox(height: 15), const SizedBox(height: 15),
_buildAnimatedWidget(
Container( Container(
height: 45, height: 45,
width: 150, width: 150,
@ -288,48 +352,54 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
), ),
child: Row( child: Row(
children: [ children: [
GestureDetector( Expanded(
child: GestureDetector(
onTap: () { onTap: () {
setState(() { setState(() {
isActiveOffer = true; isActiveOffer = true;
}); });
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(3.0),
child: Container( child: Container(
height: 35, height: 35,
width: 70,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: isActiveOffer ? Colors.white : Colors.transparent, color:
isActiveOffer ? Colors.white : Colors.transparent,
), ),
child: Center(child: Text("Active")), child: const Center(child: Text("Active")),
), ),
), ),
), ),
GestureDetector( ),
Expanded(
child: GestureDetector(
onTap: () { onTap: () {
setState(() { setState(() {
isActiveOffer = false; isActiveOffer = false;
}); });
}, },
child: Padding( child: Padding(
padding: const EdgeInsets.all(5.0), padding: const EdgeInsets.all(3.0),
child: Container( child: Container(
height: 35, height: 35,
width: 60,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
color: !isActiveOffer ? Colors.white : Colors.transparent, color:
!isActiveOffer ? Colors.white : Colors.transparent,
),
child: const Center(child: Text("Old")),
), ),
child: Center(child: Text("Old")),
), ),
), ),
), ),
], ],
), ),
), ),
SizedBox(height: 15), 8,
),
const SizedBox(height: 15),
SizedBox( SizedBox(
height: 160, height: 160,
child: ListView.builder( child: ListView.builder(
@ -337,9 +407,80 @@ class _ShopState extends State<Shop> with TickerProviderStateMixin {
shrinkWrap: true, shrinkWrap: true,
itemCount: 2, itemCount: 2,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return CustomCard( return FadeTransition(
opacity: _itemAnimations[index],
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.5, 0.0),
end: Offset.zero,
).animate(_itemAnimations[index]),
child: ColorFiltered(
colorFilter: !isActiveOffer
? const ColorFilter.matrix(<double>[
0.2126,
0.7152,
0.0722,
0,
0,
0.2126,
0.7152,
0.0722,
0,
0,
0.2126,
0.7152,
0.0722,
0,
0,
0,
0,
0,
1,
0,
])
: const ColorFilter.mode(
Colors.transparent,
BlendMode.multiply,
),
child: const CustomCard(
title: "Calamaro Table Lamp", title: "Calamaro Table Lamp",
description: "Elegant lighting with a modern twist.", description: "Elegant lighting with a modern twist.",
),
),
),
);
},
),
),
const SizedBox(height: 20),
const Text(
"Similar Business",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
const SizedBox(height: 15),
SizedBox(
height: 280,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: similarBusinesses.length,
itemBuilder: (context, index) {
final business = similarBusinesses[index];
return FadeTransition(
opacity: _similarBusinessAnimations[index],
child: SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.5, 0.0),
end: Offset.zero,
).animate(_similarBusinessAnimations[index]),
child: SimilarBusinessCard(
imagePath: business['imagePath']!,
name: business['name']!,
location: business['location']!,
onTap: () {
print("${business['name']} tapped!");
},
),
),
); );
}, },
), ),

View File

@ -0,0 +1,112 @@
import 'package:flutter/material.dart';
import 'package:lba/res/colors.dart';
class PriceReserveWidget extends StatelessWidget {
const PriceReserveWidget({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 12),
decoration: BoxDecoration(
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// بخش قیمت
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Container(
padding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
decoration: BoxDecoration(
color: LightAppColors.offerTimer,
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'HOT',
style: TextStyle(
color: Colors.white,
fontSize: 11,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(width: 8),
Row(
children: [
const Text(
'2126.88',
style: TextStyle(
fontSize: 14,
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
),
SizedBox(width: 5,),
const Text(
'(12%)',
style: TextStyle(
fontSize: 14,
color: LightAppColors.offerTimer,
),
),
],
),
],
),
const SizedBox(height: 6),
const FittedBox(
fit: BoxFit.scaleDown,
child: Text(
'AED 1,899',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: LightAppColors.offerTimer,
),
maxLines: 1,
),
),
],
),
),
const SizedBox(width: 16),
SizedBox(
width: 200,
height: 50,
child: ElevatedButton(
onPressed: () {
// TODO: Add reservation logic here
},
style: ElevatedButton.styleFrom(
backgroundColor: LightAppColors.offerTimer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: const Text(
'Reserve',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
);
}
}

View File

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:lba/gen/assets.gen.dart';
import 'package:lba/res/colors.dart';
class SimilarBusinessCard extends StatelessWidget {
final String imagePath;
final String name;
final String location;
final VoidCallback onTap;
const SimilarBusinessCard({
super.key,
required this.imagePath,
required this.name,
required this.location,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return Container(
width: 220,
margin: const EdgeInsets.symmetric(horizontal: 8),
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
offset: const Offset(0, 4),
blurRadius: 8,
spreadRadius: 1,
),
],
borderRadius: BorderRadius.circular(12),
color: LightAppColors.nearbyPopup,
border: Border.all(color: Colors.white, width: 4.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 15,),
Center(
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(8)),
child: Image.asset(
imagePath,
height: 110,
width: 180,
fit: BoxFit.cover,
),
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(
fontWeight: FontWeight.normal,
fontSize: 16,
color: Colors.black,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 6),
Row(
children: [
SvgPicture.asset(
Assets.icons.location.path,
color: Colors.black,
width: 16,
),
const SizedBox(width: 6),
Expanded(
child: Text(
location,
style: TextStyle(
fontSize: 14,
color: Colors.black,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 16),
SizedBox(
width: 120,
child: ElevatedButton(
onPressed: onTap,
style: ElevatedButton.styleFrom(
backgroundColor: LightAppColors.primary,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
),
child: const Text("See more about",style: TextStyle(fontWeight: FontWeight.bold),),
),
),
],
),
),
],
),
);
}
}