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(
@ -106,7 +107,7 @@ class _ItemState extends State<Item> with TickerProviderStateMixin {
_staggeredController.forward(); _staggeredController.forward();
} }
@override @override
void dispose() { void dispose() {
_staggeredController.dispose(); _staggeredController.dispose();
@ -116,10 +117,10 @@ 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(() {});
} }
setState(() { setState(() {
showAllReviews = true; showAllReviews = true;
@ -143,142 +144,144 @@ 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: [ _buildAnimatedWidget(
_buildAnimatedWidget( Align(
Align( alignment: Alignment.centerLeft,
alignment: Alignment.centerLeft,
child: Text(
widget.title,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
),
0,
),
SizedBox(height: 5),
_buildAnimatedWidget(
Row(
children: [
Text("Brand: "),
Expanded(
child: Text(
widget.brand,
style: TextStyle(color: LightAppColors.primary),
overflow: TextOverflow.ellipsis,
),
),
],
),
1,
),
SizedBox(height: 10),
_buildAnimatedWidget(
Row(
children: [
CustomStarRating(rating: 4.8),
SizedBox(width: 3),
Text(
"4.8",
style: TextStyle(color: LightAppColors.productDetailDivider),
),
],
),
2,
),
SizedBox(height: 15),
_buildAnimatedWidget(
Row(
children: [
OrderType(
icon: Assets.icons.cardPos.path,
typename: "Delivery",
fill: true,
),
SizedBox(width: 7),
OrderType(
icon: Assets.icons.shoppingCart.path,
typename: "Pickup",
fill: true,
),
],
),
3,
),
SizedBox(height: 15),
_buildAnimatedWidget(buildWrappedInfo("Dimensions:", widget.dimensions), 4),
_buildAnimatedWidget(buildWrappedInfo("Colour:", widget.colour), 5),
_buildAnimatedWidget(buildWrappedInfo("Material:", widget.material), 6),
_buildAnimatedWidget(buildWrappedInfo("Description:", widget.description), 7), // Now this is valid
SizedBox(height: 30),
Center(
child: Text( child: Text(
"Top reviews from the United Arab Emirates", widget.title,
style: TextStyle(fontWeight: FontWeight.bold), style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
), ),
), ),
SizedBox(height: 15), 0,
),
AnimatedList( const SizedBox(height: 5),
key: _listKey, _buildAnimatedWidget(
shrinkWrap: true, Row(
physics: NeverScrollableScrollPhysics(), children: [
initialItemCount: displayedReviews.length, const Text("Brand: "),
itemBuilder: (context, index, animation) { Expanded(
final review = displayedReviews[index]; child: Text(
return SlideTransition( widget.brand,
position: Tween<Offset>( style: const TextStyle(color: LightAppColors.primary),
begin: const Offset(-1, 0), overflow: TextOverflow.ellipsis,
end: Offset.zero,
).animate(CurvedAnimation(parent: animation, curve: Curves.easeInOut)),
child: SizeTransition(
sizeFactor: animation,
axisAlignment: -1,
child: Reviews(
name: review['name'],
comment: review['comment'],
rate: review['rate'],
yesCount: review['yesCount'],
noCount: review['noCount'],
date: review['date'],
),
), ),
); ),
}, ],
), ),
1,
if (!showAllReviews && reviews.length > 2) ),
Column( const SizedBox(height: 10),
children: [ _buildAnimatedWidget(
Center( Row(
child: InkWell( children: [
onTap: _showAllReviewsWithAnimation, const CustomStarRating(rating: 4.8),
child: Row( const SizedBox(width: 3),
mainAxisAlignment: MainAxisAlignment.center, const Text(
children: [ "4.8",
Text( style: TextStyle(color: LightAppColors.productDetailDivider),
"See all reviews", ),
style: TextStyle( ],
color: LightAppColors.allReviewOpener, ),
fontWeight: FontWeight.bold, 2,
fontSize: 18, ),
), const SizedBox(height: 15),
), _buildAnimatedWidget(
SizedBox(width: 10), Row(
SvgPicture.asset( children: [
Assets.icons.arrowDown.path, OrderType(
icon: Assets.icons.cardPos.path,
typename: "Delivery",
fill: true,
),
const SizedBox(width: 7),
OrderType(
icon: Assets.icons.shoppingCart.path,
typename: "Pickup",
fill: true,
),
],
),
3,
),
const SizedBox(height: 15),
_buildAnimatedWidget(
buildWrappedInfo("Dimensions:", widget.dimensions), 4),
_buildAnimatedWidget(buildWrappedInfo("Colour:", widget.colour), 5),
_buildAnimatedWidget(
buildWrappedInfo("Material:", widget.material), 6),
_buildAnimatedWidget(
buildWrappedInfo("Description:", widget.description), 7),
const SizedBox(height: 30),
const Center(
child: Text(
"Top reviews from the United Arab Emirates",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 15),
AnimatedList(
key: _listKey,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
initialItemCount: displayedReviews.length,
itemBuilder: (context, index, animation) {
final review = displayedReviews[index];
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-1, 0),
end: Offset.zero,
).animate(CurvedAnimation(
parent: animation, curve: Curves.easeInOut)),
child: SizeTransition(
sizeFactor: animation,
axisAlignment: -1,
child: Reviews(
name: review['name'],
comment: review['comment'],
rate: review['rate'],
yesCount: review['yesCount'],
noCount: review['noCount'],
date: review['date'],
),
),
);
},
),
if (!showAllReviews && reviews.length > 2)
Column(
children: [
Center(
child: InkWell(
onTap: _showAllReviewsWithAnimation,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"See all reviews",
style: TextStyle(
color: LightAppColors.allReviewOpener, color: LightAppColors.allReviewOpener,
fontWeight: FontWeight.bold,
fontSize: 18,
), ),
], ),
), const SizedBox(width: 10),
SvgPicture.asset(
Assets.icons.arrowDown.path,
color: LightAppColors.allReviewOpener,
),
],
), ),
), ),
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,92 +323,164 @@ 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),
Container( _buildAnimatedWidget(
height: 45, Container(
width: 150, height: 45,
decoration: BoxDecoration( width: 150,
borderRadius: BorderRadius.circular(10), decoration: BoxDecoration(
color: const Color.fromARGB(17, 77, 77, 77), borderRadius: BorderRadius.circular(10),
), color: const Color.fromARGB(17, 77, 77, 77),
child: Row( ),
children: [ child: Row(
GestureDetector( children: [
onTap: () { Expanded(
setState(() { child: GestureDetector(
isActiveOffer = true; onTap: () {
}); setState(() {
}, isActiveOffer = true;
child: Padding( });
padding: const EdgeInsets.all(5.0), },
child: Container( child: Padding(
height: 35, padding: const EdgeInsets.all(3.0),
width: 70, child: Container(
decoration: BoxDecoration( height: 35,
borderRadius: BorderRadius.circular(10), decoration: BoxDecoration(
color: isActiveOffer ? Colors.white : Colors.transparent, borderRadius: BorderRadius.circular(10),
color:
isActiveOffer ? Colors.white : Colors.transparent,
),
child: const Center(child: Text("Active")),
),
), ),
child: Center(child: Text("Active")),
), ),
), ),
), Expanded(
GestureDetector( 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:
color: !isActiveOffer ? Colors.white : Colors.transparent, !isActiveOffer ? Colors.white : Colors.transparent,
),
child: const Center(child: Text("Old")),
),
), ),
child: Center(child: Text("Old")),
), ),
), ),
), ],
], ),
), ),
8,
), ),
SizedBox(height: 15), const SizedBox(height: 15),
SizedBox( SizedBox(
height: 160, height: 160,
child: ListView.builder( child: ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
shrinkWrap: true, shrinkWrap: true,
itemCount: 2, itemCount: 2,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return CustomCard( return FadeTransition(
title: "Calamaro Table Lamp", opacity: _itemAnimations[index],
description: "Elegant lighting with a modern twist.", 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",
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),),
),
),
],
),
),
],
),
);
}
}