From 79b23b837a551aa2b50c723f478b17688f2b2586 Mon Sep 17 00:00:00 2001 From: ChunhThanhDe Date: Wed, 4 Dec 2024 17:19:02 +0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20Create=20Screen=20Detai?= =?UTF-8?q?l=20and=20BarCart?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/detail/detail_screen.dart | 165 ++++++++++++++++++ .../presentation/detail/widgets/cart_bar.dart | 80 +++++++++ 2 files changed, 245 insertions(+) create mode 100644 foods_selection_screen/lib/presentation/detail/detail_screen.dart create mode 100644 foods_selection_screen/lib/presentation/detail/widgets/cart_bar.dart diff --git a/foods_selection_screen/lib/presentation/detail/detail_screen.dart b/foods_selection_screen/lib/presentation/detail/detail_screen.dart new file mode 100644 index 0000000..fd2779b --- /dev/null +++ b/foods_selection_screen/lib/presentation/detail/detail_screen.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; +import 'package:foods_selection_screen/data/food_data.dart'; +import 'package:foods_selection_screen/presentation/detail/widgets/cart_bar.dart'; + +class DetailScreen extends StatefulWidget { + final Item data; + final String tag; + + const DetailScreen({super.key, required this.data, required this.tag}); + + @override + State createState() => _DetailScreenState(); +} + +class _DetailScreenState extends State + with SingleTickerProviderStateMixin { + bool showCart = false; + late final AnimationController _rotationController; + + @override + void initState() { + super.initState(); + _rotationController = AnimationController( + vsync: this, + duration: const Duration(seconds: 10), + )..repeat(); + } + + @override + void dispose() { + _rotationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Stack( + children: [ + SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + children: [ + _buildHeader(context), + const SizedBox(height: 20), + _buildRotatingFoodImage(), + const Spacer(), + _buildFoodTitle(), + const SizedBox(height: 10), + _buildRating(), + const SizedBox(height: 10), + _buildDescription(), + const Spacer(), + _buildPriceAndCartButton(), + const Spacer(), + ], + ), + ), + ), + // _buildCartBar(context), + CartBar( + showCart: showCart, + onClose: () => setState(() => showCart = false), + ), + ], + ), + ); + } + + Widget _buildHeader(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + onPressed: () => Navigator.pop(context), + icon: const Icon(Icons.arrow_back_ios), + ), + GestureDetector( + onTap: () => setState(() => showCart = true), + child: CircleAvatar( + radius: 20, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + child: const Icon(Icons.shopping_cart, color: Colors.black), + ), + ), + ], + ); + } + + Widget _buildRotatingFoodImage() { + return Center( + child: RotationTransition( + turns: _rotationController, + child: Hero( + tag: widget.tag, + child: CircleAvatar( + radius: 150, + backgroundColor: Colors.transparent, + backgroundImage: AssetImage(widget.data.image), + ), + ), + ), + ); + } + + Widget _buildFoodTitle() { + return Text( + widget.data.title, + style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 32), + textAlign: TextAlign.center, + ); + } + + Widget _buildRating() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate( + 5, + (index) => const Icon(Icons.star, color: Colors.orange, size: 20), + ), + ); + } + + Widget _buildDescription() { + return Text( + widget.data.description, + style: TextStyle(fontSize: 16, color: Colors.grey.shade600), + maxLines: 4, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + ); + } + + Widget _buildPriceAndCartButton() { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + "Giá món: ${widget.data.price} đ", + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ElevatedButton( + onPressed: () { + setState(() => showCart = true); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black, + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: const Text( + "Thêm món", + style: TextStyle( + fontSize: 18, + color: Colors.white, + ), + ), + ), + ], + ); + } +} diff --git a/foods_selection_screen/lib/presentation/detail/widgets/cart_bar.dart b/foods_selection_screen/lib/presentation/detail/widgets/cart_bar.dart new file mode 100644 index 0000000..9082cee --- /dev/null +++ b/foods_selection_screen/lib/presentation/detail/widgets/cart_bar.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:foods_selection_screen/data/food_data.dart'; + +class CartBar extends StatelessWidget { + final bool showCart; + final Function() onClose; + + const CartBar({ + super.key, + required this.showCart, + required this.onClose, + }); + + @override + Widget build(BuildContext context) { + return AnimatedPositioned( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOutBack, + right: showCart ? 10 : -150, + top: MediaQuery.sizeOf(context).height * 0.2, + bottom: MediaQuery.sizeOf(context).height * 0.2, + child: Container( + width: 100, + height: MediaQuery.sizeOf(context).height * 0.6, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 10, + ), + ], + ), + child: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + GestureDetector( + onTap: onClose, + child: CircleAvatar( + radius: 22, + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + child: const Icon(Icons.close, color: Colors.black), + ), + ), + const SizedBox(height: 20), + const Text("Đơn mua", + textAlign: TextAlign.center, + style: TextStyle(fontSize: 18)), + const SizedBox(height: 20), + Expanded( + child: ListView.builder( + itemCount: items.length, + itemBuilder: (context, index) => + Image.asset(items[index].image, height: 50), + ), + ), + const SizedBox(height: 20), + const Text("Tổng:", + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text("${items.length} món", + style: const TextStyle(fontSize: 14)), + const SizedBox(height: 5), + const Text("250.000 đ", + style: + TextStyle(fontSize: 16, fontWeight: FontWeight.w800)), + const SizedBox(height: 20), + ], + ), + ), + ), + ), + ); + } +}