diff --git a/lib/component/billing.dart b/lib/component/billing.dart index b1854f6..9589873 100644 --- a/lib/component/billing.dart +++ b/lib/component/billing.dart @@ -1,101 +1,109 @@ +import 'package:cart_sample/model/menu_count_model.dart'; +import 'package:cart_sample/utils/currency_formatter.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; class Billing extends StatelessWidget { - - final format = NumberFormat.currency(locale: "ko_KR", name: "", decimalDigits: 0 ); - final int orderPrice; + final int menuPrice; final int deliveryPrice; - Billing({Key? key, required this.orderPrice, required this.deliveryPrice}) : super(key: key); + Billing({ + Key? key, + required this.menuPrice, + required this.deliveryPrice, + }) : super(key: key); @override Widget build(BuildContext context) { - var _deliveryPrice = format.format(deliveryPrice); - var _orderPrice = format.format(orderPrice); - var _totalPrice = format.format(orderPrice + deliveryPrice); + final _deliveryPrice = CurrencyFormatter.convert(deliveryPrice); - return Container( - decoration: BoxDecoration( - color: Colors.white, - border: Border( - bottom: BorderSide( - color: Colors.grey.withOpacity(0.3), - width: 2, + return Consumer( + builder: (context, menuCounter, child) => Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border( + bottom: BorderSide( + color: Colors.grey.withOpacity(0.3), + width: 2, + ), ), ), - ), - child: Column( - children: [ - SizedBox( - height: 20, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - Text('총 주문금액'), - Spacer(), - Text('$_orderPrice원'), - ], + child: Column( + children: [ + SizedBox( + height: 20, ), - ), - SizedBox( - height: 10, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - Text( - '배탈팁', - style: TextStyle( - fontSize: 16, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Text('총 주문금액'), + Spacer(), + Text( + '${CurrencyFormatter.convert(calculateOrderPrice(menuCounter))}원'), + ], + ), + ), + SizedBox( + height: 10, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Text( + '배탈팁', + style: TextStyle( + fontSize: 16, + ), ), - ), - Spacer(), - Text( - '$_deliveryPrice원', - style: TextStyle( - fontSize: 16, + Spacer(), + Text( + '$_deliveryPrice원', + style: TextStyle( + fontSize: 16, + ), ), - ), - ], + ], + ), ), - ), - Padding( - padding: const EdgeInsets.all(20), - child: Divider( - color: Colors.grey, + Padding( + padding: const EdgeInsets.all(20), + child: Divider( + color: Colors.grey, + ), ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Row( - children: [ - Text( - '결제예정금액', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Row( + children: [ + Text( + '결제예정금액', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), - ), - Spacer(), - Text( - '$_totalPrice원', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, + Spacer(), + Text( + '${CurrencyFormatter.convert(deliveryPrice + (calculateOrderPrice(menuCounter)))}원', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), ), - ), - ], + ], + ), ), - ), - SizedBox( - height: 20, - ), - ], + SizedBox( + height: 20, + ), + ], + ), ), ); } + + int calculateOrderPrice(MenuCounterModel menuCounter) => + menuPrice * menuCounter.menuCount; } diff --git a/lib/component/bottom_navigation_bar.dart b/lib/component/bottom_navigation_bar.dart new file mode 100644 index 0000000..93dbe8a --- /dev/null +++ b/lib/component/bottom_navigation_bar.dart @@ -0,0 +1,72 @@ +part of '../../screen/cart_screen.dart'; + +class BottomButton extends StatelessWidget { + final int _menuPrice; + final int _deliveryPrice; + + const BottomButton({Key? key, required menuPrice, required deliveryPrice}) + : _menuPrice = menuPrice, + _deliveryPrice = deliveryPrice, + super(key: key); + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (context, menuCount, child) => Container( + color: Colors.white, + child: SafeArea( + child: Container( + height: 65, + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 10, + ), + child: ElevatedButton( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 25, + height: 25, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.circle, + ), + child: Center( + child: Text( + '1', + style: TextStyle( + color: Color.fromRGBO(44, 191, 188, 1.0), + fontWeight: FontWeight.bold, + ), + ), + ), + ), + SizedBox( + width: 7, + ), + Text( + '${_calculateTotalPrice(menuCount)}원 배달 주문하기', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all( + Color.fromRGBO(44, 191, 188, 1.0), + ), + ), + onPressed: () {}, + ), + ), + ), + ), + ); + } + + int _calculateTotalPrice(MenuCounterModel menuCounter) => + _deliveryPrice + (_menuPrice * menuCounter.menuCount); +} diff --git a/lib/component/menu.dart b/lib/component/menu.dart index 44bd050..128428f 100644 --- a/lib/component/menu.dart +++ b/lib/component/menu.dart @@ -1,94 +1,137 @@ +import 'package:cart_sample/model/menu_count_model.dart'; +import 'package:cart_sample/utils/currency_formatter.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; class Menu extends StatelessWidget { + final String _menuName; + final String _menuImage; + final String _menuDescription; + final String _formattedPrice; - final format = NumberFormat.currency(locale: "ko_KR", name: "", decimalDigits: 0); - final String menuName; - final String menuImage; - final int price; - final String menuDescription; - - - Menu( - {Key? key, - required this.menuName, - required this.menuImage, - required this.price, - required this.menuDescription}) - : super(key: key); + Menu({ + Key? key, + required menuName, + required menuImage, + required price, + required menuDescription, + }) : _menuName = menuName, + _menuImage = menuImage, + _menuDescription = menuDescription, + _formattedPrice = CurrencyFormatter.convert(price), + super(key: key); @override Widget build(BuildContext context) { - var _price = format.format(price); - return Container( - color: Colors.white, - child: Column( - children: [ - Row( - children: [ - SizedBox( - width: 20, - ), - Text( - menuName, - style: TextStyle( - fontSize: 17, - fontWeight: FontWeight.bold, - ), - ), - Spacer(), - IconButton( - icon: Icon( - Icons.close, - color: Colors.grey, + return Consumer( + builder: (context, menuCounter, child) => Container( + color: Colors.white, + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: 20, ), - onPressed: () {}, - ), - ], - ), - Row( - children: [ - SizedBox( - width: 20, - ), - Container( - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey.withOpacity(0.3), - width: 1, + Text( + _menuName, + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.bold, ), - borderRadius: BorderRadius.circular(12), ), - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Image.asset( - menuImage, - width: 70, - height: 70, - fit: BoxFit.cover, + Spacer(), + IconButton( + icon: Icon( + Icons.close, + color: Colors.grey, ), + onPressed: () {}, ), - ), - SizedBox( - width: 10, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - menuDescription, - style: TextStyle( - color: Color.fromRGBO(125, 125, 125, 1.0), + ], + ), + Row( + children: [ + SizedBox( + width: 20, + ), + Container( + decoration: BoxDecoration( + border: Border.all( + color: Colors.grey.withOpacity(0.3), + width: 1, + ), + borderRadius: BorderRadius.circular(12), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Image.asset( + _menuImage, + width: 70, + height: 70, + fit: BoxFit.cover, ), ), - Text('$_price원'), - ], - ), - ], + ), + SizedBox( + width: 10, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _menuDescription, + style: TextStyle( + color: Color.fromRGBO(125, 125, 125, 1.0), + ), + ), + Text('$_formattedPrice원'), + ], + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + _menuCountButton(menuCounter), + SizedBox( + width: 20, + ), + ], + ), + SizedBox( + height: 20, + ), + ], + ), + ), + ); + } + + Widget _menuCountButton(MenuCounterModel menuCounter) { + return Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey.withOpacity(0.4)), + borderRadius: BorderRadius.circular(6), + ), + child: Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + IconButton( + icon: Icon(Icons.remove), + disabledColor: Colors.grey, + onPressed: menuCounter.menuCount <= 1 + ? null + : () { + menuCounter.minus(); + }, ), - SizedBox( - height: 20, + Text('${menuCounter.menuCount}'), + IconButton( + icon: Icon(Icons.add), + onPressed: () { + menuCounter.add(); + }, ), ], ), diff --git a/lib/component/store_name.dart b/lib/component/store_name.dart index 40afe32..78bd6ea 100644 --- a/lib/component/store_name.dart +++ b/lib/component/store_name.dart @@ -1,11 +1,16 @@ import 'package:flutter/material.dart'; class StoreName extends StatelessWidget { + final String _storeName; + final String _storeImage; - final String storeName; - final String storeImage; - - const StoreName({Key? key, required this.storeName, required this.storeImage, }) : super(key: key); + const StoreName({ + Key? key, + required storeName, + required storeImage, + }) : _storeName = storeName, + _storeImage = storeImage, + super(key: key); @override Widget build(BuildContext context) { @@ -20,7 +25,7 @@ class StoreName extends StatelessWidget { ClipRRect( borderRadius: BorderRadius.circular(12), child: Image.asset( - storeImage, + _storeImage, width: 35, height: 35, ), @@ -29,7 +34,7 @@ class StoreName extends StatelessWidget { width: 10, ), Text( - storeName, + _storeName, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), ) ], diff --git a/lib/main.dart b/lib/main.dart index 08216b5..c2d6670 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ +import 'package:cart_sample/model/menu_count_model.dart'; import 'package:cart_sample/screen/cart_screen.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; void main() { runApp(const MyApp()); @@ -11,7 +13,8 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - home: CartScreen(), + home: ChangeNotifierProvider( + create: (context) => MenuCounterModel(), child: CartScreen()), ); } } \ No newline at end of file diff --git a/lib/model/menu_count_model.dart b/lib/model/menu_count_model.dart new file mode 100644 index 0000000..fea4c26 --- /dev/null +++ b/lib/model/menu_count_model.dart @@ -0,0 +1,22 @@ +import 'package:flutter/foundation.dart'; + +class MenuCounterModel extends ChangeNotifier { + static const int minimumCount = 1; + + var _menuCount = 1; + + int get menuCount => _menuCount; + + void add() { + _menuCount++; + notifyListeners(); + } + + void minus() { + if (_menuCount == minimumCount) { + return; + } + _menuCount--; + notifyListeners(); + } +} diff --git a/lib/screen/cart_screen.dart b/lib/screen/cart_screen.dart index a3c24b8..4fc764a 100644 --- a/lib/screen/cart_screen.dart +++ b/lib/screen/cart_screen.dart @@ -2,8 +2,11 @@ import 'package:cart_sample/component/add_more.dart'; import 'package:cart_sample/component/billing.dart'; import 'package:cart_sample/component/menu.dart'; import 'package:cart_sample/component/store_name.dart'; +import 'package:cart_sample/model/menu_count_model.dart'; import 'package:flutter/material.dart'; -import 'package:intl/intl.dart'; +import 'package:provider/provider.dart'; + +part '../component/bottom_navigation_bar.dart'; class CartScreen extends StatefulWidget { const CartScreen({Key? key}) : super(key: key); @@ -15,12 +18,8 @@ class CartScreen extends StatefulWidget { class _CartScreenState extends State { @override Widget build(BuildContext context) { - - final format = NumberFormat.currency(locale: "ko_KR", name: "", decimalDigits: 0); - - var _deliveryPrice = 3000; - var _menuPrice = 18000; - var _totalPrice = format.format(_deliveryPrice + _menuPrice); + const deliveryPrice = 3000; + const menuPrice = 18000; return Scaffold( backgroundColor: const Color.fromRGBO(246, 246, 246, 1.0), @@ -52,7 +51,7 @@ class _CartScreenState extends State { Menu( menuName: '황금 올리브 후라이드 치킨', menuImage: 'images/chicken.png', - price: _menuPrice, + price: menuPrice, menuDescription: '• 찜 & 리뷰 약속 : 참여. 서비스음료제공', ), SizedBox( @@ -60,62 +59,14 @@ class _CartScreenState extends State { ), AddMore(), Billing( - orderPrice: _menuPrice, - deliveryPrice: _deliveryPrice, + menuPrice: menuPrice, + deliveryPrice: deliveryPrice, ), ], ), - bottomNavigationBar: Container( - color: Colors.white, - child: SafeArea( - child: Container( - height: 65, - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 10, - ), - child: ElevatedButton( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 25, - height: 25, - decoration: BoxDecoration( - color: Colors.white, - shape: BoxShape.circle, - ), - child: Center( - child: Text( - '1', - style: TextStyle( - color: Color.fromRGBO(44, 191, 188, 1.0), - fontWeight: FontWeight.bold, - ), - ), - ), - ), - SizedBox( - width: 7, - ), - Text( - '$_totalPrice원 배달 주문하기', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - ], - ), - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Color.fromRGBO(44, 191, 188, 1.0), - ), - ), - onPressed: () {}, - ), - ), - ), + bottomNavigationBar: BottomButton( + deliveryPrice: deliveryPrice, + menuPrice: menuPrice, ), ); } diff --git a/lib/utils/currency_formatter.dart b/lib/utils/currency_formatter.dart new file mode 100644 index 0000000..764a214 --- /dev/null +++ b/lib/utils/currency_formatter.dart @@ -0,0 +1,9 @@ +import 'package:intl/intl.dart'; + +class CurrencyFormatter { + static final _formatter = NumberFormat.currency(locale: "ko_KR", name: "", decimalDigits: 0); + + static String convert(int currency) { + return _formatter.format(currency); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index e782a3d..f79f262 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 intl: ^0.17.0 + provider: ^6.0.4 dev_dependencies: