diff --git a/assets/images/checkout/bags.png b/assets/images/checkout/bags.png new file mode 100644 index 00000000..19aa28f2 Binary files /dev/null and b/assets/images/checkout/bags.png differ diff --git a/assets/images/checkout/dark_card.png b/assets/images/checkout/dark_card.png new file mode 100644 index 00000000..cc7230ca Binary files /dev/null and b/assets/images/checkout/dark_card.png differ diff --git a/assets/images/checkout/dhl.png b/assets/images/checkout/dhl.png new file mode 100644 index 00000000..8ea28fb7 Binary files /dev/null and b/assets/images/checkout/dhl.png differ diff --git a/assets/images/checkout/fedex.png b/assets/images/checkout/fedex.png new file mode 100644 index 00000000..9013ef7a Binary files /dev/null and b/assets/images/checkout/fedex.png differ diff --git a/assets/images/checkout/light_card.png b/assets/images/checkout/light_card.png new file mode 100644 index 00000000..a1f1be2b Binary files /dev/null and b/assets/images/checkout/light_card.png differ diff --git a/assets/images/checkout/mastercard.png b/assets/images/checkout/mastercard.png new file mode 100644 index 00000000..119d30f3 Binary files /dev/null and b/assets/images/checkout/mastercard.png differ diff --git a/assets/images/checkout/success.png b/assets/images/checkout/success.png new file mode 100644 index 00000000..ee2f08a7 Binary files /dev/null and b/assets/images/checkout/success.png differ diff --git a/assets/images/checkout/usps.png b/assets/images/checkout/usps.png new file mode 100644 index 00000000..3f6e031c Binary files /dev/null and b/assets/images/checkout/usps.png differ diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee8..e8efba11 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee8..399e9340 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 21e4dc1c..5dda2fad 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + F821E4F7499F31FC3552ADF3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 591BB2C9B9333B32BDFBD5C7 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -39,6 +40,9 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 3B9CC7B3762CD13F71A85A9B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 3F44D75436C4DD89C59726FF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 591BB2C9B9333B32BDFBD5C7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -50,6 +54,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9B0A26276ABF171DE36BEEAE /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,6 +64,7 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + F821E4F7499F31FC3552ADF3 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -84,6 +90,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + FCA609B3975DD31A2AD3AD62 /* Pods */, + C2F634981E5363BA02E35F7D /* Frameworks */, ); sourceTree = ""; }; @@ -118,6 +126,25 @@ name = "Supporting Files"; sourceTree = ""; }; + C2F634981E5363BA02E35F7D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 591BB2C9B9333B32BDFBD5C7 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + FCA609B3975DD31A2AD3AD62 /* Pods */ = { + isa = PBXGroup; + children = ( + 3B9CC7B3762CD13F71A85A9B /* Pods-Runner.debug.xcconfig */, + 9B0A26276ABF171DE36BEEAE /* Pods-Runner.release.xcconfig */, + 3F44D75436C4DD89C59726FF /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -125,12 +152,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 464C10B199D0292F9B67E53E /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 7650B0023506C1D4B8B42E25 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -203,6 +232,43 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; + 464C10B199D0292F9B67E53E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 7650B0023506C1D4B8B42E25 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16..21a3cc14 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/config/routes.dart b/lib/config/routes.dart index f017d2be..79cba239 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -3,12 +3,14 @@ // Date: 2020-02-06 class OpenFlutterEcommerceRoutes { - static final home = "/"; - static final shop = "shop"; - static final cart = "cart"; - static final favourites = "favourites"; - static final profile = "profile"; - static const SIGNUP = "signup"; - static const SIGNIN = "signin"; - static const FORGET_PASSWORD = "forget_pass"; + static const home = "/"; + static const shop = "shop"; + static const cart = "cart"; + static const favourites = "favourites"; + static const profile = "profile"; + static const checkout = "checkout"; + static const signup = "signup"; + static const signin = "signin"; + static const forgotPassword = "forgot_pass"; + static const settings = "settings"; } diff --git a/lib/config/theme.dart b/lib/config/theme.dart index 2dcdb188..ad3008bc 100644 --- a/lib/config/theme.dart +++ b/lib/config/theme.dart @@ -5,15 +5,16 @@ import 'package:flutter/material.dart'; class AppSizes { - static int splashScreenTitleFontSize = 48; - static int titleFontSize = 34; - static double sidePadding = 15; - static double widgetSidePadding = 20; - static double buttonRadius = 25; - static double imageRadius = 8; - static double linePadding = 4; - static double widgetBorderRadius = 34; - static const TEXT_FIELD_RADIUS = 4.0; + static const int splashScreenTitleFontSize = 48; + static const int titleFontSize = 34; + static const double sidePadding = 15; + static const double widgetSidePadding = 20; + static const double buttonRadius = 25; + static const double imageRadius = 8; + static const double linePadding = 4; + static const double widgetBorderRadius = 34; + static const double textFieldRadius = 4.0; + static const EdgeInsets bottomSheetPadding = EdgeInsets.symmetric(horizontal: 16, vertical: 10); } class AppColors { @@ -25,6 +26,7 @@ class AppColors { static const orange = Color(0xFFFFBA49); static const background = Color(0xFFE5E5E5); static const transparent = Color(0x00000000); + static const success = Color(0xFF2AA952); } class OpenFlutterEcommerceTheme { @@ -38,44 +40,50 @@ class OpenFlutterEcommerceTheme { backgroundColor: AppColors.background, errorColor: AppColors.red, appBarTheme: theme.appBarTheme.copyWith( - color: AppColors.white, - iconTheme: IconThemeData(color: AppColors.black), - textTheme: theme.textTheme.copyWith( - caption: TextStyle(color: AppColors.black, fontSize: 18))), + color: AppColors.white, + iconTheme: IconThemeData(color: AppColors.black), + textTheme: theme.textTheme.copyWith( + caption: TextStyle(color: AppColors.black, fontSize: 18))), textTheme: theme.textTheme.copyWith( - //over image white text - headline: theme.textTheme.headline - .copyWith(fontSize: 48, color: AppColors.white), - subtitle: theme.textTheme.headline - .copyWith(fontSize: 18, color: AppColors.black), - subhead: theme.textTheme.headline.copyWith( - fontSize: 24, - color: AppColors.white, - fontWeight: FontWeight.bold), - //red button with white text - button: theme.textTheme.button - .copyWith(fontSize: 14, color: AppColors.white), - //black caption title - caption: theme.textTheme.caption.copyWith( - fontSize: 34, - color: AppColors.black, - ), - //light gray small text - display1: theme.textTheme.display1.copyWith( - color: AppColors.lightGray, - fontSize: 11, - ), - //view all link - display2: theme.textTheme.display2 - .copyWith(color: AppColors.black, fontSize: 11), - //product title - display3: theme.textTheme.display2.copyWith( - color: AppColors.black, - fontSize: 16, - fontWeight: FontWeight.bold), - //product price - display4: theme.textTheme.display2 - .copyWith(color: AppColors.lightGray, fontSize: 14)), + //over image white text + headline1: theme.textTheme.headline1 + .copyWith(fontSize: 48, color: AppColors.white), + headline2: theme.textTheme.headline2, + + //product title + headline3: theme.textTheme.headline3.copyWith( + color: AppColors.black, + fontSize: 16, + fontWeight: FontWeight.bold), + + headline4: theme.textTheme.headline4, + //product price + headline5: theme.textTheme.headline5 + .copyWith(color: AppColors.lightGray, fontSize: 14), + headline6: theme.textTheme.headline6, + + subtitle1: theme.textTheme.headline1 + .copyWith(fontSize: 18, color: AppColors.black), + subtitle2: theme.textTheme.headline1.copyWith( + fontSize: 24, + color: AppColors.white, + fontWeight: FontWeight.bold), + //red button with white text + button: theme.textTheme.button + .copyWith(fontSize: 14, color: AppColors.white), + //black caption title + caption: theme.textTheme.caption.copyWith( + fontSize: 34, + color: AppColors.black, + ), + //light gray small text + bodyText1: theme.textTheme.bodyText1.copyWith( + color: AppColors.lightGray, + fontSize: 11, + ), + //view all link + bodyText2: theme.textTheme.bodyText2 + .copyWith(color: AppColors.black, fontSize: 11),), buttonTheme: theme.buttonTheme.copyWith( minWidth: 50, buttonColor: AppColors.red, diff --git a/lib/main.dart b/lib/main.dart index da65fe71..445583b2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,15 +4,18 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:openflutterecommerce/config/routes.dart'; import 'package:openflutterecommerce/config/theme.dart'; +import 'package:openflutterecommerce/screens/cart/cart_screen.dart'; import 'package:openflutterecommerce/screens/categories/categories_screen.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_translate/flutter_translate.dart'; import 'package:openflutterecommerce/screens/home/home_screen.dart'; +import 'package:openflutterecommerce/screens/settings/settings_screen.dart'; import 'package:openflutterecommerce/screens/signin/forget_password.dart'; import 'package:openflutterecommerce/screens/signin/signup.dart'; import 'package:openflutterecommerce/screens/splash_screen.dart'; import 'authentication/authentication.dart'; import 'config/routes.dart'; +import 'screens/checkout/checkout_screen.dart'; import 'screens/home/home_screen.dart'; import 'screens/signin/signin.dart'; import 'package:flutter_translate/flutter_translate.dart'; @@ -89,9 +92,9 @@ class OpenFlutterEcommerceApp extends StatelessWidget { OpenFlutterEcommerceRoutes.home: (context) => HomeScreen(), OpenFlutterEcommerceRoutes.cart: (context) => HomeScreen(), OpenFlutterEcommerceRoutes.favourites: (context) => HomeScreen(), - OpenFlutterEcommerceRoutes.SIGNIN: (context) => _signIn, - OpenFlutterEcommerceRoutes.SIGNUP: (context) => _signUp, - OpenFlutterEcommerceRoutes.FORGET_PASSWORD: (context) => + OpenFlutterEcommerceRoutes.signin: (context) => _signIn, + OpenFlutterEcommerceRoutes.signup: (context) => _signUp, + OpenFlutterEcommerceRoutes.forgotPassword: (context) => _forgetPassword, OpenFlutterEcommerceRoutes.shop: (context) => CategoriesScreen(), OpenFlutterEcommerceRoutes.profile: (context) => diff --git a/lib/screens/cart/cart.dart b/lib/screens/cart/cart.dart new file mode 100644 index 00000000..8edab2bf --- /dev/null +++ b/lib/screens/cart/cart.dart @@ -0,0 +1,4 @@ +export 'cart_bloc.dart'; +export 'cart_event.dart'; +export 'cart_screen.dart'; +export 'cart_state.dart'; \ No newline at end of file diff --git a/lib/screens/cart/cart_bloc.dart b/lib/screens/cart/cart_bloc.dart new file mode 100644 index 00000000..327288de --- /dev/null +++ b/lib/screens/cart/cart_bloc.dart @@ -0,0 +1,32 @@ +// Home Screen Bloc +// Author: openflutterproject@gmail.com +// Date: 2020-02-06 + +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/repos/product_repository.dart'; + +import 'cart.dart'; + +class CartBloc extends Bloc { + final ProductRepository productRepository; + + CartBloc({ + @required this.productRepository, + }) : assert(productRepository != null); + + @override + CartState get initialState => CartInitialState(); + + @override + Stream mapEventToState(CartEvent event) async* { + if (event is CartLoadedEvent) { + if (this.state is CartInitialState) { + yield new CartLoadedState( + cartProducts: this.productRepository.getProducts(1)); + } else if (this.state is CartLoadedState) { + yield this.state; + } + } + } +} diff --git a/lib/screens/cart/cart_event.dart b/lib/screens/cart/cart_event.dart new file mode 100644 index 00000000..12660704 --- /dev/null +++ b/lib/screens/cart/cart_event.dart @@ -0,0 +1,18 @@ +// Home Screen Bloc Events +// Author: openflutterproject@gmail.com +// Date: 2020-02-06 + +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + +@immutable +abstract class CartEvent extends Equatable { + @override + List get props => []; +} + +@immutable +class CartLoadedEvent extends CartEvent { + @override + String toString() => 'Cart wass Loaded'; +} diff --git a/lib/screens/cart/cart_screen.dart b/lib/screens/cart/cart_screen.dart new file mode 100644 index 00000000..20bec6ae --- /dev/null +++ b/lib/screens/cart/cart_screen.dart @@ -0,0 +1,54 @@ +// Home Screen +// Author: openflutterproject@gmail.com +// Date: 2020-02-06 + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:openflutterecommerce/repos/product_repository.dart'; +import 'package:openflutterecommerce/screens/cart/views/cart_view.dart'; +import 'package:openflutterecommerce/screens/wrapper.dart'; +import 'package:openflutterecommerce/widgets/scaffold.dart'; + +import 'cart.dart'; + +class CartScreen extends StatefulWidget { + @override + _CartScreenState createState() => _CartScreenState(); +} + +class _CartScreenState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: OpenFlutterScaffold( + background: null, + title: null, + body: BlocProvider( + create: (context) { + return CartBloc(productRepository: ProductRepository()) + ..add(CartLoadedEvent()); + }, + child: CartWrapper()), + bottomMenuIndex: 0, + )); + } +} + +class CartWrapper extends StatefulWidget { + @override + _CartWrapperState createState() => _CartWrapperState(); +} + +class _CartWrapperState extends OpenFlutterWrapperState { + //State createState() => OpenFlutterWrapperState(); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (BuildContext context, CartState state) { + return getPageView([ + CartView(changeView: changePage) + ]); + }); + } +} diff --git a/lib/screens/cart/cart_state.dart b/lib/screens/cart/cart_state.dart new file mode 100644 index 00000000..c112d35e --- /dev/null +++ b/lib/screens/cart/cart_state.dart @@ -0,0 +1,30 @@ +// Home Screen Bloc States +// Author: openflutterproject@gmail.com +// Date: 2020-02-06 + +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/repos/models/product.dart'; + +@immutable +abstract class CartState extends Equatable { + @override + List get props => []; +} + +@immutable +class CartInitialState extends CartState { + String toString() => 'HomeInitialState'; +} + +@immutable +class CartLoadedState extends CartState { + final List cartProducts; + + CartLoadedState({this.cartProducts}); + + String toString() => 'HomeLoadedState'; + + @override + List get props => [cartProducts]; +} diff --git a/lib/screens/cart/views/cart_view.dart b/lib/screens/cart/views/cart_view.dart new file mode 100644 index 00000000..9791d188 --- /dev/null +++ b/lib/screens/cart/views/cart_view.dart @@ -0,0 +1,46 @@ +// Home Screen View #1: Big top banner, list of products +// Author: openflutterproject@gmail.com +// Date: 2020-02-06 + +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/routes.dart'; +import 'package:openflutterecommerce/config/theme.dart'; +import 'package:openflutterecommerce/repos/models/product.dart'; +import 'package:openflutterecommerce/screens/wrapper.dart'; +import 'package:openflutterecommerce/widgets/block_header.dart'; +import 'package:openflutterecommerce/widgets/product_list_view.dart'; +import 'package:openflutterecommerce/widgets/widgets.dart'; + +class CartView extends StatefulWidget { + final List products; + final Function changeView; + + const CartView({Key key, this.products, this.changeView}) : super(key: key); + + @override + _CartViewState createState() => _CartViewState(); +} + +class _CartViewState extends State { + @override + Widget build(BuildContext context) { + ThemeData _theme = Theme.of(context); + final double width = MediaQuery.of(context).size.width; + final double widgetWidth = width - AppSizes.sidePadding*2; + return SingleChildScrollView( + child: Column( + children: [ + Text('User cart'), + OpenFlutterButton( + height: 50, + width: 200, + title: "Proceed to checkout", + onPressed: (() => { + Navigator.pushNamed(context, OpenFlutterEcommerceRoutes.checkout) + }) + ) + ] + ) + ); + } +} \ No newline at end of file diff --git a/lib/screens/categories/views/list_view.dart b/lib/screens/categories/views/list_view.dart index 4194268f..ebce8cb1 100644 --- a/lib/screens/categories/views/list_view.dart +++ b/lib/screens/categories/views/list_view.dart @@ -37,7 +37,7 @@ class _CategoriesListViewState extends State { return Container( padding: EdgeInsets.all(AppSizes.sidePadding), child: Text('An error occured', - style: _theme.textTheme.subtitle + style: _theme.textTheme.headline3 .copyWith(color: _theme.errorColor))); } return Container(); @@ -46,21 +46,23 @@ class _CategoriesListViewState extends State { if (state is CategoryListViewState) { return SingleChildScrollView( child: Column(children: [ - Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), - OpenFlutterButton( - onPressed: (() => { - BlocProvider.of(context) - .add(CategoryShowTilesEvent(1)), - widget.changeView(changeType: ViewChangeType.Forward) - }), - title: "VIEW ALL ITEMS", - width: widgetWidth, - height: 50), - Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), - state.isLoading - ? Center(child: CircularProgressIndicator()) - : Column(children: buildCategoryList(state.categories)) - ])); + Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), + OpenFlutterButton( + onPressed: (() => { + BlocProvider.of(context) + .add(CategoryShowTilesEvent(1)), + widget.changeView(changeType: ViewChangeType.Forward) + }), + title: "VIEW ALL ITEMS", + width: widgetWidth, + height: 50), + Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), + state.isLoading + ? Center(child: CircularProgressIndicator()) + : Column(children: buildCategoryList(state.categories)) + ] + ) + ); } return Center(child: CircularProgressIndicator()); })); diff --git a/lib/screens/categories/views/tile_view.dart b/lib/screens/categories/views/tile_view.dart index 8715c626..7eeec183 100644 --- a/lib/screens/categories/views/tile_view.dart +++ b/lib/screens/categories/views/tile_view.dart @@ -46,7 +46,7 @@ class _CategoriesTileViewState extends State return Container( padding: EdgeInsets.all(AppSizes.sidePadding), child: Text('An error occured', - style: _theme.textTheme.subtitle.copyWith( + style: _theme.textTheme.headline3.copyWith( color: _theme.errorColor ) ) @@ -77,9 +77,9 @@ class _CategoriesTileViewState extends State crossAxisAlignment: CrossAxisAlignment.center, children: [ Text('SUMMER SALES', - style: _theme.textTheme.subhead), + style: _theme.textTheme.headline3), Text('Up to 50% off', - style: _theme.textTheme.subtitle.copyWith( + style: _theme.textTheme.headline3.copyWith( color: AppColors.white ) ) diff --git a/lib/screens/checkout/checkout.dart b/lib/screens/checkout/checkout.dart index fe4e0a51..071466ef 100644 --- a/lib/screens/checkout/checkout.dart +++ b/lib/screens/checkout/checkout.dart @@ -1,4 +1,9 @@ export 'checkout_bloc.dart'; export 'checkout_event.dart'; export 'checkout_screen.dart'; -export 'checkout_state.dart'; \ No newline at end of file +export 'checkout_state.dart'; +export 'views/cart_view.dart'; +export 'views/payment_method_view.dart'; +export 'views/shipping_address_view.dart'; +export 'views/success1_view.dart'; +export 'views/success2_view.dart'; \ No newline at end of file diff --git a/lib/screens/checkout/checkout_bloc.dart b/lib/screens/checkout/checkout_bloc.dart index e69de29b..d41eafdc 100644 --- a/lib/screens/checkout/checkout_bloc.dart +++ b/lib/screens/checkout/checkout_bloc.dart @@ -0,0 +1,31 @@ +// Checkout Screen Bloc +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:bloc/bloc.dart'; +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/repos/product_repository.dart'; +import 'package:openflutterecommerce/screens/checkout/checkout.dart'; + +class CheckoutBloc extends Bloc { + final ProductRepository productRepository; + + CheckoutBloc({ + @required this.productRepository, + }) : assert(productRepository != null); + + @override + CheckoutState get initialState => CheckoutInitialState(); + + @override + Stream mapEventToState(CheckoutEvent event) async* { + if (event is CheckoutStartEvent) { + if (this.state is CheckoutInitialState) { + yield new CheckoutProceedState( + cartProducts: this.productRepository.getProducts(2)); + } else if (this.state is CheckoutProceedState) { + yield this.state; + } + } + } +} diff --git a/lib/screens/checkout/checkout_event.dart b/lib/screens/checkout/checkout_event.dart index e69de29b..5fbe16a2 100644 --- a/lib/screens/checkout/checkout_event.dart +++ b/lib/screens/checkout/checkout_event.dart @@ -0,0 +1,86 @@ +// Checkout Screen Bloc Events +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + +@immutable +abstract class CheckoutEvent extends Equatable { + @override + List get props => []; +} + +@immutable +class CheckoutStartEvent extends CheckoutEvent { + @override + String toString() => 'CheckoutStartEvent'; +} + +@immutable +class CheckoutFinishEvent extends CheckoutEvent { + @override + String toString() => 'CheckoutFinishEvent'; +} + +@immutable +class CheckoutShowAddNewCardEvent extends CheckoutEvent { + @override + String toString() => 'CheckoutShowAddNewCardEvent'; +} + +@immutable +class CheckoutSetDefaultCardEvent extends CheckoutEvent { + final int cardId; + + CheckoutSetDefaultCardEvent(this.cardId); + + @override + String toString() => 'CheckoutSetDefaultCardEvent'; +} + + +@immutable +class CheckoutAddNewCardEvent extends CheckoutEvent { + final String nameOnCard; + final String cardNumber; + final int expirationMonth; + final int expirationYear; + final int cvv; + final bool setAsDefault; + + CheckoutAddNewCardEvent(this.nameOnCard, this.cardNumber, + this.expirationMonth, this.expirationYear, + this.cvv, this.setAsDefault); + + @override + String toString() => 'CheckoutAddNewCardEvent'; +} + + +@immutable +class CheckoutSetDefaultShippingAddressEvent extends CheckoutEvent { + final int shippingAddressId; + + CheckoutSetDefaultShippingAddressEvent(this.shippingAddressId); + + @override + String toString() => 'CheckoutSetDefaultShippingAddressEvent'; +} + + +@immutable +class CheckoutAddNewShippingAddressEvent extends CheckoutEvent { + final String fullName; + final String address; + final String city; + final String state; + final String postal; + final String country; + + CheckoutAddNewShippingAddressEvent(this.fullName, this.address, this.city, this.state, this.postal, this.country); + + + @override + String toString() => 'CheckoutAddNewShippingAddressEvent'; +} diff --git a/lib/screens/checkout/checkout_screen.dart b/lib/screens/checkout/checkout_screen.dart index e69de29b..1b48ac5f 100644 --- a/lib/screens/checkout/checkout_screen.dart +++ b/lib/screens/checkout/checkout_screen.dart @@ -0,0 +1,59 @@ +// Checkout Screen +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:openflutterecommerce/repos/product_repository.dart'; +import 'package:openflutterecommerce/screens/checkout/checkout.dart'; +import 'package:openflutterecommerce/screens/wrapper.dart'; +import 'package:openflutterecommerce/widgets/scaffold.dart'; + +import 'checkout.dart'; + +class CheckoutScreen extends StatefulWidget { + @override + _CheckoutScreenState createState() => _CheckoutScreenState(); +} + +class _CheckoutScreenState extends State { + @override + Widget build(BuildContext context) { + return SafeArea( + child: OpenFlutterScaffold( + background: null, + title: "Checkout", + body: BlocProvider( + create: (context) { + return CheckoutBloc(productRepository: ProductRepository()) + ..add(CheckoutStartEvent()); + }, + child: CheckoutWrapper()), + bottomMenuIndex: 0, + ) + ); + } +} + +class CheckoutWrapper extends StatefulWidget { + @override + _CheckoutWrapperState createState() => _CheckoutWrapperState(); +} + +class _CheckoutWrapperState extends OpenFlutterWrapperState { + //State createState() => OpenFlutterWrapperState(); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (BuildContext context, CheckoutState state) { + return getPageView([ + CartView(changeView: changePage), + PaymentMethodView(changeView: changePage), + ShippingAddressView(changeView: changePage), + Success1View(changeView: changePage), + Success2View(changeView: changePage), + ]); + }); + } +} diff --git a/lib/screens/checkout/checkout_state.dart b/lib/screens/checkout/checkout_state.dart index e69de29b..c980da95 100644 --- a/lib/screens/checkout/checkout_state.dart +++ b/lib/screens/checkout/checkout_state.dart @@ -0,0 +1,36 @@ +// Checkout Screen Bloc States +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/repos/models/product.dart'; + +@immutable +abstract class CheckoutState extends Equatable { + @override + List get props => []; +} + +@immutable +class CheckoutInitialState extends CheckoutState { + String toString() => 'CheckoutInitialState'; +} + +@immutable +class CheckoutProceedState extends CheckoutState { + final List cartProducts; + + CheckoutProceedState({this.cartProducts}); + + String toString() => 'CheckoutProceedState'; + + @override + List get props => [cartProducts]; +} + + +@immutable +class CheckoutErrorState extends CheckoutState { + String toString() => 'CheckoutErrorState'; +} \ No newline at end of file diff --git a/lib/screens/checkout/views/cart_view.dart b/lib/screens/checkout/views/cart_view.dart new file mode 100644 index 00000000..54a31e99 --- /dev/null +++ b/lib/screens/checkout/views/cart_view.dart @@ -0,0 +1,133 @@ +// Checkout Cart View Screen +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:openflutterecommerce/config/theme.dart'; +import 'package:openflutterecommerce/widgets/action_card.dart'; +import 'package:openflutterecommerce/widgets/delivery_method.dart'; +import 'package:openflutterecommerce/widgets/payment_card.dart'; +import 'package:openflutterecommerce/widgets/summary_line.dart'; +import 'package:openflutterecommerce/widgets/widgets.dart'; + +import '../../wrapper.dart'; +import '../checkout.dart'; + +class CartView extends StatefulWidget { + + final Function changeView; + + const CartView({Key key, this.changeView}) : super(key: key); + + @override + _CartViewState createState() => _CartViewState(); +} + +class _CartViewState extends State { + @override + Widget build(BuildContext context) { + + final bloc = BlocProvider.of(context); + final ThemeData _theme = Theme.of(context); + final double width = MediaQuery.of(context).size.width - AppSizes.sidePadding*2; + + return BlocListener( + bloc: bloc, + listener: (context, state) { + if (state is CheckoutErrorState) { + return Container( + padding: EdgeInsets.all(AppSizes.sidePadding), + child: Text('An error occured', + style: _theme.textTheme.headline3 + .copyWith(color: _theme.errorColor))); + } + return Container(); + }, + child: BlocBuilder( + bloc: bloc, + builder: (BuildContext context, CheckoutState state) { + return SingleChildScrollView( + child: Column( + children: [ + OpenFlutterBlockSubtitle( + title: 'Shipping Address', + width: width + ), + OpenFlutterActionCard( + title: 'Jane Doe', + linkText: 'Change', + onLinkTap: ( () => { + BlocProvider.of(context) + .add(CheckoutShowAddNewCardEvent()), + widget.changeView(changeType: ViewChangeType.Backward) + }), + child: RichText( + text: TextSpan( + text:"3 Newbridge Court Chino Hills, CA 91709, United States", + style: _theme.textTheme.headline5.copyWith( + color: _theme.primaryColor + ) + ), + maxLines: 2, + ) + ), + + OpenFlutterBlockSubtitle( + title: 'Payment', + width: width, + linkText: "Change", + onLinkTap: ( () => { + + }), + ), + OpenFlutterPaymentCard( + cardNumber: "**** **** **** 3947", + ), + + OpenFlutterBlockSubtitle( + title: 'Delivery Method', + width: width, + linkText: "Change", + onLinkTap: ( () => { + + }), + ), + + OpenFlutterDeliveryMethod( + + ), + Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding*3)), + + OpenFlutterSummaryLine( + title: 'Order', + summary: '\$112' + ), + Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), + + OpenFlutterSummaryLine( + title: 'Delivery', + summary: '\$15' + ), + Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), + + OpenFlutterSummaryLine( + title: 'Summary', + summary: '\$127' + ), + Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), + + OpenFlutterButton( + title: 'SUBMIT ORDER', + onPressed: ( () => { + + }), + ) + ], + ) + ); + } + ) + ); + } +} \ No newline at end of file diff --git a/lib/screens/checkout/views/payment_method_view.dart b/lib/screens/checkout/views/payment_method_view.dart new file mode 100644 index 00000000..7bc69d18 --- /dev/null +++ b/lib/screens/checkout/views/payment_method_view.dart @@ -0,0 +1,24 @@ +// Checkout Payment Method View Screen +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:flutter/material.dart'; + +class PaymentMethodView extends StatefulWidget { + + final Function changeView; + + const PaymentMethodView({Key key, this.changeView}) : super(key: key); + + @override + _PaymentMethodViewState createState() => _PaymentMethodViewState(); +} + +class _PaymentMethodViewState extends State { + @override + Widget build(BuildContext context) { + return Container( + + ); + } +} \ No newline at end of file diff --git a/lib/screens/checkout/views/shipping_address_view.dart b/lib/screens/checkout/views/shipping_address_view.dart new file mode 100644 index 00000000..a6506d77 --- /dev/null +++ b/lib/screens/checkout/views/shipping_address_view.dart @@ -0,0 +1,24 @@ +// Checkout Shipping Address View Screen +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:flutter/material.dart'; + +class ShippingAddressView extends StatefulWidget { + + final Function changeView; + + const ShippingAddressView({Key key, this.changeView}) : super(key: key); + + @override + _ShippingAddressViewState createState() => _ShippingAddressViewState(); +} + +class _ShippingAddressViewState extends State { + @override + Widget build(BuildContext context) { + return Container( + + ); + } +} \ No newline at end of file diff --git a/lib/screens/checkout/views/success1_view.dart b/lib/screens/checkout/views/success1_view.dart new file mode 100644 index 00000000..ae6b026f --- /dev/null +++ b/lib/screens/checkout/views/success1_view.dart @@ -0,0 +1,24 @@ +// Checkout Success View Screen #1 +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:flutter/material.dart'; + +class Success1View extends StatefulWidget { + + final Function changeView; + + const Success1View({Key key, this.changeView}) : super(key: key); + + @override + _Success1ViewState createState() => _Success1ViewState(); +} + +class _Success1ViewState extends State { + @override + Widget build(BuildContext context) { + return Container( + + ); + } +} \ No newline at end of file diff --git a/lib/screens/checkout/views/success2_view.dart b/lib/screens/checkout/views/success2_view.dart new file mode 100644 index 00000000..19cfbca2 --- /dev/null +++ b/lib/screens/checkout/views/success2_view.dart @@ -0,0 +1,24 @@ +// Checkout Success View Screen #2 +// Author: openflutterproject@gmail.com +// Date: 2020-02-17 + +import 'package:flutter/material.dart'; + +class Success2View extends StatefulWidget { + + final Function changeView; + + const Success2View({Key key, this.changeView}) : super(key: key); + + @override + _Success2ViewState createState() => _Success2ViewState(); +} + +class _Success2ViewState extends State { + @override + Widget build(BuildContext context) { + return Container( + + ); + } +} \ No newline at end of file diff --git a/lib/screens/home/views/main1_view.dart b/lib/screens/home/views/main1_view.dart index 34b5e951..cd749f8e 100644 --- a/lib/screens/home/views/main1_view.dart +++ b/lib/screens/home/views/main1_view.dart @@ -28,51 +28,53 @@ class _Main1ViewState extends State { final double width = MediaQuery.of(context).size.width; final double widgetWidth = width - AppSizes.sidePadding * 2; return SingleChildScrollView( - child: Column(children: [ - Container( + child: Column(children: [ + Container( height: width * 1.43, width: width, decoration: new BoxDecoration( - image: new DecorationImage( - fit: BoxFit.fill, - image: AssetImage("assets/splash/splash-home.png"))), + image: new DecorationImage( + fit: BoxFit.fill, + image: AssetImage("assets/splash/splash-home.png"))), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: EdgeInsets.only(left: AppSizes.sidePadding), - width: width / 2, - child: Text(translate('fashionSale'), - style: _theme.textTheme.headline)), + padding: EdgeInsets.only(left: AppSizes.sidePadding), + width: width / 2, + child: Text(translate('fashionSale'), + style: _theme.textTheme.headline1)), Container( - padding: EdgeInsets.only( - left: AppSizes.sidePadding, - bottom: AppSizes.sidePadding, - top: AppSizes.sidePadding), + padding: EdgeInsets.only( + left: AppSizes.sidePadding, + bottom: AppSizes.sidePadding, + top: AppSizes.sidePadding), + width: 160, + child: OpenFlutterButton( + title: 'Check', width: 160, - child: OpenFlutterButton( - title: 'Check', - width: 160, - height: 48, - onPressed: (() => widget.changeView( - changeType: ViewChangeType.Forward)))) + height: 48, + onPressed: (() => widget.changeView( + changeType: ViewChangeType.Forward)))) ], - )), - OpenFlutterBlockHeader( - width: widgetWidth, - title: 'New', - linkText: 'View All', - onLinkTap: (() => {}), - description: 'You’ve never seen it before!', - ), - OpenFlutterProductListView(width: widgetWidth, products: widget.products), - OpenFlutterButton( + ) + ), + OpenFlutterBlockHeader( + width: widgetWidth, + title: 'New', + linkText: 'View All', + onLinkTap: (() => {}), + description: 'You’ve never seen it before!', + ), + OpenFlutterProductListView(width: widgetWidth, products: widget.products), + OpenFlutterButton( title: 'Next Home Page', width: 160, height: 48, onPressed: (() => - widget.changeView(changeType: ViewChangeType.Forward))) - ])); + widget.changeView(changeType: ViewChangeType.Forward))) + ]) + ); } } diff --git a/lib/screens/home/views/main2_view.dart b/lib/screens/home/views/main2_view.dart index 184581ef..a8154901 100644 --- a/lib/screens/home/views/main2_view.dart +++ b/lib/screens/home/views/main2_view.dart @@ -48,7 +48,7 @@ class _Main2ViewState extends State { padding: EdgeInsets.only(left: AppSizes.sidePadding), width: width, child: Text('Street clothes', - style: _theme.textTheme.headline.copyWith( + style: _theme.textTheme.headline1.copyWith( fontSize: 34 )) ) diff --git a/lib/screens/home/views/main3_view.dart b/lib/screens/home/views/main3_view.dart index 8946c7f9..feb91da2 100644 --- a/lib/screens/home/views/main3_view.dart +++ b/lib/screens/home/views/main3_view.dart @@ -44,7 +44,7 @@ class _Main3ViewState extends State { bottom: AppSizes.sidePadding), width: width, child: Text('New collection', - style: _theme.textTheme.headline.copyWith( + style: _theme.textTheme.headline1.copyWith( fontSize: 34 )) ) @@ -58,7 +58,7 @@ class _Main3ViewState extends State { height: width/2-2, padding: EdgeInsets.all(AppSizes.sidePadding), child: Text('Summer sale', - style: _theme.textTheme.headline.copyWith( + style: _theme.textTheme.headline1.copyWith( fontSize: 34, color: _theme.accentColor ))), @@ -75,7 +75,7 @@ class _Main3ViewState extends State { ) ), child: Text('Black', - style: _theme.textTheme.headline.copyWith( + style: _theme.textTheme.headline1.copyWith( fontSize: 34 ))), ],), @@ -91,7 +91,7 @@ class _Main3ViewState extends State { ) ), child: Text('Men’s hoodies', - style: _theme.textTheme.headline.copyWith( + style: _theme.textTheme.headline1.copyWith( fontSize: 34 ))), ],), diff --git a/lib/screens/products/views/card_view.dart b/lib/screens/products/views/card_view.dart index 90e334c2..235466b0 100644 --- a/lib/screens/products/views/card_view.dart +++ b/lib/screens/products/views/card_view.dart @@ -39,17 +39,17 @@ class _ProductsCardViewState extends State { return BlocListener(listener: (context, state) { if (state is ProductsErrorState) { return Container( - padding: EdgeInsets.all(AppSizes.sidePadding), - child: Text('An error occured', - style: _theme.textTheme.subtitle - .copyWith(color: _theme.errorColor))); + padding: EdgeInsets.all(AppSizes.sidePadding), + child: Text('An error occured', + style: _theme.textTheme.headline3 + .copyWith(color: _theme.errorColor))); } return Container(); }, child: BlocBuilder(builder: (context, state) { if (state is ProductsCardViewState) { return SingleChildScrollView( - child: Column(children: [ - Container( + child: Column(children: [ + Container( color: AppColors.white, child: Column(children: [ Padding(padding: EdgeInsets.only(top: AppSizes.sidePadding)), @@ -73,7 +73,7 @@ class _ProductsCardViewState extends State { onFilterClicked: (() => {}), onChangeViewClicked: (() => { BlocProvider.of(context) - .add(ProductShowCardEvent(state.category.id, sortBy)), + .add(ProductShowListEvent(state.category.id, sortBy)), widget.changeView(changeType: ViewChangeType.Backward) }), onSortClicked: ((SortBy sortBy) => { @@ -83,8 +83,9 @@ class _ProductsCardViewState extends State { }), ), ), - ])), - state.isLoading + ]) + ), + state.isLoading ? Center(child: CircularProgressIndicator()) : Container( height: MediaQuery.of(context).size.height - topPartHeight, @@ -127,10 +128,12 @@ class _ProductsCardViewState extends State { bloc..add(ProductChangeSortByEvent(state.category.id, newSortBy)) }) ) : Container() - ] - ) + ] + ) ) - ])); + ] + ) + ); } return Center(child: CircularProgressIndicator()); })); diff --git a/lib/screens/products/views/list_view.dart b/lib/screens/products/views/list_view.dart index 995f3140..39943663 100644 --- a/lib/screens/products/views/list_view.dart +++ b/lib/screens/products/views/list_view.dart @@ -37,7 +37,6 @@ class _ProductsListViewState extends State { final double topPartHeight = 360; final bloc = BlocProvider.of(context); - ThemeData _theme = Theme.of(context); return BlocListener( bloc: bloc, @@ -46,7 +45,7 @@ class _ProductsListViewState extends State { return Container( padding: EdgeInsets.all(AppSizes.sidePadding), child: Text('An error occured', - style: _theme.textTheme.subtitle + style: _theme.textTheme.headline3 .copyWith(color: _theme.errorColor))); } return Container(); diff --git a/lib/screens/settings/settings_screen.dart b/lib/screens/settings/settings_screen.dart new file mode 100644 index 00000000..c5fd363b --- /dev/null +++ b/lib/screens/settings/settings_screen.dart @@ -0,0 +1,251 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/theme.dart'; +import 'package:openflutterecommerce/widgets/widgets.dart'; + +class SettingsScreen extends StatefulWidget { + @override + _SettingsScreenState createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + bool _notifySales = true; + bool _notifyArrivals = false; + bool _notifyDelivery = false; + final GlobalKey scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; + double width = MediaQuery.of(context).size.width; + return Scaffold( + appBar: AppBar( + backgroundColor: AppColors.transparent, + brightness: Brightness.light, + elevation: 0, + iconTheme: IconThemeData(color: AppColors.black), + ), + backgroundColor: AppColors.background, + body: Container( + height: height * 0.9, + padding: EdgeInsets.symmetric(horizontal: AppSizes.sidePadding), + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Settings', + style: TextStyle(fontSize: 34, fontWeight: FontWeight.w500), + ), + SizedBox( + height: 23, + ), + Text( + 'Personal Information', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + SizedBox( + height: 21, + ), + OpenFlutterInputField( + hint: 'Full Name', + ), + SizedBox( + height: 24, + ), + OpenFlutterInputField( + hint: 'Date of Birth', + ), + SizedBox( + height: 55, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Password', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + GestureDetector( + onTap: () { + _showChangePasswordBottomSheet(context); + }, + child: Text( + 'Change', + style: TextStyle( + fontSize: 14, + color: AppColors.lightGray, + fontWeight: FontWeight.w500), + ), + ), + ], + ), + SizedBox( + height: 21, + ), + OpenFlutterInputField( + hint: 'Password', + ), + SizedBox( + height: 50, + ), + Text( + 'Notifications', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Sales', + style: TextStyle(fontSize: 14, color: AppColors.black), + ), + CupertinoSwitch( + trackColor: AppColors.lightGray, + value: _notifySales, + activeColor: AppColors.success, + onChanged: (newValue) { + setState(() { + _notifySales = newValue; + }); + }, + ), + ], + ), + SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'New arrivals', + style: TextStyle(fontSize: 14, color: AppColors.black), + ), + CupertinoSwitch( + trackColor: AppColors.lightGray, + value: _notifyArrivals, + activeColor: AppColors.success, + onChanged: (newValue) { + setState(() { + _notifyArrivals = newValue; + }); + }, + ), + ], + ), + SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Delivery status changes', + style: TextStyle(fontSize: 14, color: AppColors.black), + ), + CupertinoSwitch( + trackColor: AppColors.lightGray, + value: _notifyDelivery, + activeColor: AppColors.success, + onChanged: (newValue) { + setState(() { + _notifyDelivery = newValue; + }); + }, + ), + ], + ), + SizedBox( + height: 50, + ), + ], + ), + ), + ), + ); + } + + _showChangePasswordBottomSheet(BuildContext context) { + showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(34), topRight: Radius.circular(34)), + ), + builder: (BuildContext context) => Container( + height: 472, + padding: AppSizes.bottomSheetPadding, + decoration: BoxDecoration( + color: AppColors.background, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(34), + topRight: Radius.circular(34)), + boxShadow: []), + child: Column( + children: [ + Container( + height: 6, + width: 60, + decoration: BoxDecoration( + color: AppColors.lightGray, + borderRadius: BorderRadius.circular(3), + ), + ), + SizedBox( + height: 16, + ), + Text( + 'Password Change', + style: TextStyle( + color: AppColors.black, + fontSize: 18, + fontWeight: FontWeight.bold), + ), + SizedBox( + height: 18, + ), + OpenFlutterInputField( + hint: 'Old Password', + ), + SizedBox( + height: 18, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + 'Forgot Password?', + style: TextStyle(color: AppColors.lightGray), + ), + ], + ), + SizedBox( + height: 18, + ), + OpenFlutterInputField( + hint: 'New Password', + ), + SizedBox( + height: 18, + ), + OpenFlutterInputField( + hint: 'Repeat New Password', + ), + SizedBox( + height: 18, + ), + OpenFlutterButton( + title: 'Save Password', + height: 48, + onPressed: () {}, + ) + ], + ), + )); + } +} diff --git a/lib/screens/signin/forget_password_screen.dart b/lib/screens/signin/forget_password_screen.dart index 2185d8d4..15f8b11e 100644 --- a/lib/screens/signin/forget_password_screen.dart +++ b/lib/screens/signin/forget_password_screen.dart @@ -112,7 +112,7 @@ class _ForgetPasswordScreenState extends State { } void _showSignInScreen() { - Navigator.of(context).pushNamed(OpenFlutterEcommerceRoutes.SIGNIN); + Navigator.of(context).pushNamed(OpenFlutterEcommerceRoutes.signin); } void _validateAndSend() { diff --git a/lib/screens/signin/signin_screen.dart b/lib/screens/signin/signin_screen.dart index 6c6fca93..1e638a51 100644 --- a/lib/screens/signin/signin_screen.dart +++ b/lib/screens/signin/signin_screen.dart @@ -113,7 +113,7 @@ class _SignInScreenState extends State { } void _showForgotPassword() { - Navigator.of(context).pushNamed(OpenFlutterEcommerceRoutes.FORGET_PASSWORD); + Navigator.of(context).pushNamed(OpenFlutterEcommerceRoutes.forgotPassword); } void _validateAndSend() { diff --git a/lib/screens/signin/signup_screen.dart b/lib/screens/signin/signup_screen.dart index cbc0fe31..f0188949 100644 --- a/lib/screens/signin/signup_screen.dart +++ b/lib/screens/signin/signup_screen.dart @@ -121,7 +121,7 @@ class _SignUpScreenState extends State { } void _showSignInScreen() { - Navigator.of(context).pushNamed(OpenFlutterEcommerceRoutes.SIGNIN); + Navigator.of(context).pushNamed(OpenFlutterEcommerceRoutes.signin); } void _validateAndSend() { diff --git a/lib/widgets/action_card.dart b/lib/widgets/action_card.dart new file mode 100644 index 00000000..c5544248 --- /dev/null +++ b/lib/widgets/action_card.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/theme.dart'; + +class OpenFlutterActionCard extends StatelessWidget { + final String title; + final String linkText; + final Function onLinkTap; + final Widget child; + + const OpenFlutterActionCard({Key key, + @required this.title, + this.linkText, + this.child, + this.onLinkTap}) : super(key: key); + + @override + Widget build(BuildContext context) { + ThemeData _theme = Theme.of(context); + final double width = MediaQuery.of(context).size.width - AppSizes.sidePadding*4; + return Padding( + padding: EdgeInsets.all(AppSizes.sidePadding), + child: Container( + padding: EdgeInsets.all(AppSizes.sidePadding), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(AppSizes.imageRadius)), + color: AppColors.white, + boxShadow: [BoxShadow( + color: AppColors.lightGray.withOpacity(0.3), + blurRadius: AppSizes.imageRadius, + offset: Offset(0.0, AppSizes.imageRadius) + ) + ] + ), + child: Column(children: [ + Row(children: [ + Container( + width: width/3*2, + child: Text(title, + style: _theme.textTheme.headline5.copyWith( + color: _theme.primaryColor + ) + ) + ), + this.linkText != null ? + Container( + alignment: Alignment.centerRight, + width: width/3, + child: InkWell( + onTap: ( () => { + this.onLinkTap() + }), + child: Text(linkText, + style: _theme.textTheme.headline5.copyWith( + color: _theme.accentColor + )), + ) + ) + : Container() + ],), + Container( + padding: EdgeInsets.symmetric(vertical: AppSizes.linePadding*2), + child: this.child + ) + ],) + ) + ); + } +} \ No newline at end of file diff --git a/lib/widgets/block_header.dart b/lib/widgets/block_header.dart index 40384e68..68edc3f8 100644 --- a/lib/widgets/block_header.dart +++ b/lib/widgets/block_header.dart @@ -41,7 +41,7 @@ class OpenFlutterBlockHeader extends StatelessWidget { width: rightLinkWidth, child: Align(alignment: Alignment.centerRight, child: Text(this.linkText, - style: _theme.textTheme.display2 + style: _theme.textTheme.bodyText2 ) ) ) @@ -51,7 +51,7 @@ class OpenFlutterBlockHeader extends StatelessWidget { ), this.description != null? Text(this.description, - style: _theme.textTheme.display2) + style: _theme.textTheme.bodyText2) :Container() ] ) diff --git a/lib/widgets/block_subtitle.dart b/lib/widgets/block_subtitle.dart new file mode 100644 index 00000000..1648c73a --- /dev/null +++ b/lib/widgets/block_subtitle.dart @@ -0,0 +1,59 @@ +// Header of the block widget with title and description +// Author: openflutterproject@gmail.com +// Date: 2020-02-06 + +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/theme.dart'; + +class OpenFlutterBlockSubtitle extends StatelessWidget { + final double width; + final String title; + final String linkText; + final Function onLinkTap; + + const OpenFlutterBlockSubtitle({Key key, this.width, + this.title, this.linkText, this.onLinkTap}) : super(key: key); + + @override + Widget build(BuildContext context) { + ThemeData _theme = Theme.of(context); + double rightLinkWidth = 100; + return Container( + padding: EdgeInsets.only(top: AppSizes.sidePadding, + left: AppSizes.sidePadding), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Container( + width: this.width - rightLinkWidth, + child: Text(this.title, + style: _theme.textTheme.headline3.copyWith( + fontWeight: FontWeight.bold, + color: _theme.primaryColor + ) + ) + ), + this.linkText != null ? + InkWell( + onTap: (() => { this.onLinkTap() }), + child: Container( + width: rightLinkWidth, + child: Align(alignment: Alignment.centerRight, + child: Text(this.linkText, + style: _theme.textTheme.headline3.copyWith( + color: _theme.accentColor + ) + ) + ) + ) + ) + :Container() + ], + ) + ] + ) + ); + } +} \ No newline at end of file diff --git a/lib/widgets/bottom_menu.dart b/lib/widgets/bottom_menu.dart index 2e53f13f..3ec4784c 100644 --- a/lib/widgets/bottom_menu.dart +++ b/lib/widgets/bottom_menu.dart @@ -50,7 +50,7 @@ class OpenFlutterBottomMenu extends StatelessWidget { Navigator.pushNamed(context, OpenFlutterEcommerceRoutes.cart); break; case 3: - Navigator.pushNamed(context, OpenFlutterEcommerceRoutes.favourites); + Navigator.pushNamed(context, OpenFlutterEcommerceRoutes.settings); break; case 4: Navigator.pushNamed(context, OpenFlutterEcommerceRoutes.profile); diff --git a/lib/widgets/category_list_element.dart b/lib/widgets/category_list_element.dart index c3722ead..55694177 100644 --- a/lib/widgets/category_list_element.dart +++ b/lib/widgets/category_list_element.dart @@ -28,7 +28,7 @@ class OpenFlutterCatregoryListElement extends StatelessWidget { ), ), child: Text(category.title, - style: _theme.textTheme.display3.copyWith( + style: _theme.textTheme.headline3.copyWith( fontWeight: FontWeight.normal ) ) diff --git a/lib/widgets/category_tile.dart b/lib/widgets/category_tile.dart index b343ad7d..6912dfb4 100644 --- a/lib/widgets/category_tile.dart +++ b/lib/widgets/category_tile.dart @@ -30,7 +30,7 @@ class OpenFlutterCategoryTile extends StatelessWidget { alignment: Alignment.centerLeft, width: this.width - 200, child: Text(category.title, - style: _theme.textTheme.subtitle) + style: _theme.textTheme.headline3) ), Container( width: 200, diff --git a/lib/widgets/clickable_line.dart b/lib/widgets/clickable_line.dart index 4dcbacd0..1f76e934 100644 --- a/lib/widgets/clickable_line.dart +++ b/lib/widgets/clickable_line.dart @@ -35,7 +35,7 @@ class OpenFlutterClickableLine extends StatelessWidget { width: width, color: this.backgroundColor, child: Text(title, - style: _theme.textTheme.display3.copyWith( + style: _theme.textTheme.headline3.copyWith( fontWeight: FontWeight.normal, color: textColor ) diff --git a/lib/widgets/delivery_method.dart b/lib/widgets/delivery_method.dart new file mode 100644 index 00000000..8a1e62cb --- /dev/null +++ b/lib/widgets/delivery_method.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/theme.dart'; + +class OpenFlutterDeliveryMethod extends StatelessWidget { + @override + Widget build(BuildContext context) { + final ThemeData _theme = Theme.of(context); + final double width = MediaQuery.of(context).size.width; + final double widgetWidth = (width)/3; + final double height = 90; + return Container( + width: width, + height: height, + padding: EdgeInsets.only(left: AppSizes.sidePadding, + top: AppSizes.sidePadding + ), + child: Row(children: [ + buildElement("assets/images/checkout/fedex.png", + '2-3 days', _theme, widgetWidth, height), + buildElement("assets/images/checkout/usps.png", + '2-3 days', _theme, widgetWidth, height), + buildElement("assets/images/checkout/dhl.png", + '2-3 days', _theme, widgetWidth, height), + ],), + ); + } + + Widget buildElement(String assetImage, String title, ThemeData _theme, double width, double height){ + return Padding( + padding: EdgeInsets.only(right: AppSizes.sidePadding), + child: Container( + width: width - AppSizes.linePadding*2-AppSizes.sidePadding, + height: height, + padding: EdgeInsets.all(AppSizes.linePadding), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(AppSizes.imageRadius)), + color: AppColors.white, + boxShadow: [BoxShadow( + color: AppColors.lightGray.withOpacity(0.3), + blurRadius: AppSizes.imageRadius, + offset: Offset(0.0, AppSizes.imageRadius) + ) + ] + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.all(AppSizes.sidePadding), + child: Image.asset(assetImage, width: 61,), + ), + Text(title, + style: _theme.textTheme.bodyText2.copyWith( + color: _theme.primaryColorLight + )) + ],), + ) + ); + } +} \ No newline at end of file diff --git a/lib/widgets/input_field.dart b/lib/widgets/input_field.dart index ed1e70dc..9098ad42 100644 --- a/lib/widgets/input_field.dart +++ b/lib/widgets/input_field.dart @@ -44,12 +44,12 @@ class OpenFlutterInputFieldState extends State { ? RoundedRectangleBorder( side: BorderSide(color: AppColors.red, width: 1.0), borderRadius: - BorderRadius.circular(AppSizes.TEXT_FIELD_RADIUS), + BorderRadius.circular(AppSizes.textFieldRadius), ) : RoundedRectangleBorder( side: BorderSide(color: Colors.white, width: 1.0), borderRadius: - BorderRadius.circular(AppSizes.TEXT_FIELD_RADIUS), + BorderRadius.circular(AppSizes.textFieldRadius), ), color: AppColors.white, child: Padding( diff --git a/lib/widgets/payment_card.dart b/lib/widgets/payment_card.dart new file mode 100644 index 00000000..064c7106 --- /dev/null +++ b/lib/widgets/payment_card.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/theme.dart'; + +class OpenFlutterPaymentCard extends StatelessWidget { + final String cardNumber; + + const OpenFlutterPaymentCard({Key key, this.cardNumber}) : super(key: key); + + @override + Widget build(BuildContext context) { + final ThemeData _theme = Theme.of(context); + return Container( + padding: EdgeInsets.all(AppSizes.sidePadding), + child: Row(children: [ + Container( + width: 64, + height: 38, + color: AppColors.white, + child: Image.asset("assets/images/checkout/mastercard.png", height: 38), + ), + Container( + padding: EdgeInsets.only(left: AppSizes.sidePadding), + child: Text(cardNumber, + style: _theme.textTheme.headline5.copyWith( + color: _theme.primaryColor + )),) + ],) + ); + } +} \ No newline at end of file diff --git a/lib/widgets/product_card.dart b/lib/widgets/product_card.dart index 14f0b7b6..8a4476fa 100644 --- a/lib/widgets/product_card.dart +++ b/lib/widgets/product_card.dart @@ -43,9 +43,9 @@ class OpenFlutterProductCard extends StatelessWidget { ), buildRating(product, _theme), Text(product.categoryTitle, - style: _theme.textTheme.display1), + style: _theme.textTheme.bodyText1), Text(product.title, - style: _theme.textTheme.display3), + style: _theme.textTheme.headline3), buildPrice(product, _theme), ] ), @@ -59,7 +59,7 @@ class OpenFlutterProductCard extends StatelessWidget { return Row( children: [ Text("\$" + product.price.toStringAsFixed(0), - style: _theme.textTheme.display4.copyWith( + style: _theme.textTheme.headline5.copyWith( decoration: discountPrice>0? TextDecoration.lineThrough: TextDecoration.none, ) @@ -67,7 +67,7 @@ class OpenFlutterProductCard extends StatelessWidget { Padding(padding: EdgeInsets.only(left: AppSizes.linePadding),), discountPrice>0? Text("\$" + discountPrice.toStringAsFixed(0), - style: _theme.textTheme.display4.copyWith( + style: _theme.textTheme.headline5.copyWith( color: _theme.errorColor )): Container() @@ -100,7 +100,7 @@ class OpenFlutterProductCard extends StatelessWidget { color: AppColors.black, ), child: Text('NEW', - style: theme.textTheme.display1.copyWith( + style: theme.textTheme.bodyText1.copyWith( color: AppColors.white, fontWeight: FontWeight.bold ) @@ -114,7 +114,7 @@ class OpenFlutterProductCard extends StatelessWidget { color: theme.errorColor, ), child: Text("-" + product.discountPercent.toStringAsFixed(0)+"%", - style: theme.textTheme.display1.copyWith( + style: theme.textTheme.bodyText1.copyWith( color: AppColors.white, fontWeight: FontWeight.bold, ) diff --git a/lib/widgets/product_filter.dart b/lib/widgets/product_filter.dart index ede1595f..445fd3d4 100644 --- a/lib/widgets/product_filter.dart +++ b/lib/widgets/product_filter.dart @@ -49,7 +49,7 @@ class OpenFlutterProductFilter extends StatelessWidget { padding: EdgeInsets.only(left: iconSize/3), width: thirdWidth, child: Text('Filters', - style: _theme.textTheme.display1) + style: _theme.textTheme.bodyText1) ) ] ) @@ -66,7 +66,7 @@ class OpenFlutterProductFilter extends StatelessWidget { padding: EdgeInsets.only(left: iconSize/3), width: thirdWidth*2, child: Text(getSortTitle(sortBy), - style: _theme.textTheme.display1) + style: _theme.textTheme.bodyText1) ) ] ) diff --git a/lib/widgets/product_rating.dart b/lib/widgets/product_rating.dart index 02bd8890..47d9ead6 100644 --- a/lib/widgets/product_rating.dart +++ b/lib/widgets/product_rating.dart @@ -46,7 +46,7 @@ class OpenFlutterProductRating extends StatelessWidget { ), ratingCount>0? Text('('+ratingCount.toString()+')', - style: _theme.textTheme.display1.copyWith( + style: _theme.textTheme.bodyText1.copyWith( fontSize: 14) ) : Container(), diff --git a/lib/widgets/product_tile.dart b/lib/widgets/product_tile.dart index 04319c0c..266215e4 100644 --- a/lib/widgets/product_tile.dart +++ b/lib/widgets/product_tile.dart @@ -45,9 +45,9 @@ class OpenFlutterProductTile extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children:[ Text(product.title, - style: _theme.textTheme.subtitle), + style: _theme.textTheme.headline3), Text(product.categoryTitle, - style: _theme.textTheme.display1), + style: _theme.textTheme.bodyText1), Padding(padding: EdgeInsets.only(top: AppSizes.linePadding)), OpenFlutterProductRating( rating: product.rating, @@ -56,7 +56,7 @@ class OpenFlutterProductTile extends StatelessWidget { ), Padding(padding: EdgeInsets.only(top: AppSizes.linePadding)), Text('\$'+product.price.toStringAsFixed(2), - style: _theme.textTheme.display4.copyWith( + style: _theme.textTheme.headline5.copyWith( color: _theme.primaryColor, fontWeight: FontWeight.bold ) diff --git a/lib/widgets/sortby.dart b/lib/widgets/sortby.dart index 71568e21..0d9421ee 100644 --- a/lib/widgets/sortby.dart +++ b/lib/widgets/sortby.dart @@ -40,7 +40,7 @@ class OpenFlutterSortBy extends StatelessWidget { ), ), Text("Sort by", - style: _theme.textTheme.subtitle + style: _theme.textTheme.headline3 ), Container( padding: EdgeInsets.only(top: AppSizes.sidePadding), diff --git a/lib/widgets/summary_line.dart b/lib/widgets/summary_line.dart new file mode 100644 index 00000000..eed7ef6e --- /dev/null +++ b/lib/widgets/summary_line.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:openflutterecommerce/config/theme.dart'; + +class OpenFlutterSummaryLine extends StatelessWidget { + final String title; + final String summary; + + const OpenFlutterSummaryLine({Key key, this.title, this.summary}) : super(key: key); + + @override + Widget build(BuildContext context) { + final double width = MediaQuery.of(context).size.width - AppSizes.sidePadding*2; + final ThemeData _theme = Theme.of(context); + return Container( + padding: EdgeInsets.symmetric( + horizontal: AppSizes.sidePadding, + vertical: AppSizes.linePadding), + child: Row(children: [ + Container( + width: width/2, + child: Text(title, + style: _theme.textTheme.headline5 + ) + ), + Container( + alignment: Alignment.centerRight, + width: width/2, + child: Text(summary, + style: _theme.textTheme.headline5.copyWith( + fontWeight: FontWeight.bold, + color: _theme.primaryColor + ) + ) + ), + ],) + ); + } +} \ No newline at end of file diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index 26d0bade..d1a314cf 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -1,4 +1,5 @@ export 'block_header.dart'; +export 'block_subtitle.dart'; export 'bottom_menu.dart'; export 'category_list_element.dart'; export 'category_tile.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 746340e6..f8aba82b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,6 +53,7 @@ flutter: - assets/icons/products/ - assets/icons/signin/ - assets/images/products/ + - assets/images/checkout/ - assets/splash/ - assets/thumbs/ - assets/thumbs/dress/