diff --git a/packages/flutter_order_details/lib/flutter_order_details.dart b/packages/flutter_order_details/lib/flutter_order_details.dart index 3e879d7..d22fb55 100644 --- a/packages/flutter_order_details/lib/flutter_order_details.dart +++ b/packages/flutter_order_details/lib/flutter_order_details.dart @@ -1,6 +1,8 @@ /// Flutter component for shopping cart. library flutter_order_details; +export "package:flutter_form_wizard/flutter_form.dart"; + export "src/configuration/order_detail_configuration.dart"; export "src/configuration/order_detail_translations.dart"; export "src/order_detail_screen.dart"; diff --git a/packages/flutter_order_details/lib/src/configuration/order_detail_configuration.dart b/packages/flutter_order_details/lib/src/configuration/order_detail_configuration.dart index 6e98263..89a6a5a 100644 --- a/packages/flutter_order_details/lib/src/configuration/order_detail_configuration.dart +++ b/packages/flutter_order_details/lib/src/configuration/order_detail_configuration.dart @@ -2,7 +2,6 @@ import "package:animated_toggle/animated_toggle.dart"; import "package:flutter/material.dart"; -import "package:flutter_form_wizard/flutter_form.dart"; import "package:flutter_order_details/flutter_order_details.dart"; import "package:flutter_shopping_interface/flutter_shopping_interface.dart"; @@ -14,19 +13,25 @@ class OrderDetailConfiguration { required this.onNextStep, required this.onStepsCompleted, required this.onCompleteOrderDetails, - this.pages = _defaultPages, - this.translations = const OrderDetailTranslations(), - this.appBar = _defaultAppBar, - this.nextbuttonBuilder = _defaultNextButtonBuilder, - this.orderSuccessBuilder = _defaultOrderSuccess, - }); + this.pages, + this.translations, + this.appBar, + this.nextbuttonBuilder, + this.orderSuccessBuilder, + }) { + pages ??= _defaultPages; + translations ??= const OrderDetailTranslations(); + appBar ??= _defaultAppBar; + nextbuttonBuilder ??= _defaultNextButtonBuilder; + orderSuccessBuilder ??= _defaultOrderSuccess; + } /// The shopping service that is used final ShoppingService shoppingService; /// The different steps that the user has to go through to complete the order. /// Each step contains a list of fields that the user has to fill in. - final List Function(BuildContext context) pages; + List Function(BuildContext context)? pages; /// Callback function that is called when the user has completed the order. /// The result of the order is passed as an argument to the function. @@ -38,33 +43,37 @@ class OrderDetailConfiguration { ) onStepsCompleted; /// Callback function that is called when the user has completed a step. - final Function(int currentStep, Map data) onNextStep; + final Function( + int currentStep, + Map data, + FlutterFormController controller, + ) onNextStep; /// Localization for the order detail screen. - final OrderDetailTranslations translations; + OrderDetailTranslations? translations; /// Optional app bar that you can pass to the order detail screen. - final AppBar Function( + AppBar Function( BuildContext context, String title, - ) appBar; + )? appBar; /// Optional next button builder that you can pass to the order detail screen. - final Widget Function( + Widget Function( int currentStep, // ignore: avoid_positional_boolean_parameters bool checkingPages, BuildContext context, OrderDetailConfiguration configuration, FlutterFormController controller, - ) nextbuttonBuilder; + )? nextbuttonBuilder; /// Optional builder for the order success screen. - final Widget Function( + Widget Function( BuildContext context, OrderDetailConfiguration, Map> orderDetails, - ) orderSuccessBuilder; + )? orderSuccessBuilder; /// This function is called after the order has been completed and /// the success screen has been shown. @@ -107,8 +116,11 @@ Widget _defaultNextButtonBuilder( width: double.infinity, child: FilledButton( onPressed: () async { - controller.validateAndSaveCurrentStep(); - await controller.autoNextStep(); + configuration.onNextStep( + currentStep, + controller.getCurrentStepResults(), + controller, + ); }, style: theme.filledButtonTheme.style?.copyWith( backgroundColor: WidgetStateProperty.all( diff --git a/packages/flutter_order_details/lib/src/order_detail_screen.dart b/packages/flutter_order_details/lib/src/order_detail_screen.dart index 5914c44..b1a07e3 100644 --- a/packages/flutter_order_details/lib/src/order_detail_screen.dart +++ b/packages/flutter_order_details/lib/src/order_detail_screen.dart @@ -1,5 +1,4 @@ import "package:flutter/material.dart"; -import "package:flutter_form_wizard/flutter_form.dart"; import "package:flutter_order_details/flutter_order_details.dart"; /// Order Detail Screen. @@ -22,22 +21,22 @@ class _OrderDetailScreenState extends State { Widget build(BuildContext context) { var controller = FlutterFormController(); return Scaffold( - appBar: widget.configuration.appBar.call( + appBar: widget.configuration.appBar!.call( context, - widget.configuration.translations.orderDetailsTitle, + widget.configuration.translations!.orderDetailsTitle, ), body: FlutterForm( formController: controller, options: FlutterFormOptions( nextButton: (pageNumber, checkingPages) => - widget.configuration.nextbuttonBuilder( + widget.configuration.nextbuttonBuilder!( pageNumber, checkingPages, context, widget.configuration, controller, ), - pages: widget.configuration.pages.call(context), + pages: widget.configuration.pages!.call(context), onFinished: (data) async { widget.configuration.onStepsCompleted.call( widget.configuration.shoppingService.shopService.selectedShop!.id, @@ -47,7 +46,7 @@ class _OrderDetailScreenState extends State { ); }, onNext: (step, data) { - widget.configuration.onNextStep.call(step, data); + }, ), ), diff --git a/packages/flutter_order_details/pubspec.yaml b/packages/flutter_order_details/pubspec.yaml index 9b0e18b..5e39831 100644 --- a/packages/flutter_order_details/pubspec.yaml +++ b/packages/flutter_order_details/pubspec.yaml @@ -24,10 +24,6 @@ dependencies: ref: 2.0.0 collection: ^1.18.0 -dependency_overrides: - flutter_shopping_interface: - path: ../flutter_shopping_interface - dev_dependencies: flutter_test: sdk: flutter diff --git a/packages/flutter_product_page/lib/src/configuration/product_page_configuration.dart b/packages/flutter_product_page/lib/src/configuration/product_page_configuration.dart index edb3527..97340ac 100644 --- a/packages/flutter_product_page/lib/src/configuration/product_page_configuration.dart +++ b/packages/flutter_product_page/lib/src/configuration/product_page_configuration.dart @@ -1,5 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_product_page/flutter_product_page.dart"; +import "package:flutter_product_page/src/widgets/product_item.dart"; import "package:flutter_product_page/src/widgets/product_item_popup.dart"; import "package:flutter_shopping_interface/flutter_shopping_interface.dart"; @@ -13,20 +14,31 @@ class ProductPageConfiguration { required this.onAddToCart, required this.onNavigateToShoppingCart, required this.getProductsInShoppingCart, - this.shoppingCartButtonBuilder = _defaultShoppingCartButtonBuilder, + this.shoppingCartButtonBuilder, this.initialShopId, this.productBuilder, this.onShopSelectionChange, - this.translations = const ProductPageTranslations(), - this.shopSelectorStyle = ShopSelectorStyle.spacedWrap, - this.pagePadding = const EdgeInsets.all(4), - this.appBar = _defaultAppBar, + this.translations, + this.shopSelectorStyle, + this.pagePadding, + this.appBar, this.bottomNavigationBar, - this.onProductDetail = _onProductDetail, - this.discountDescription = _defaultDiscountDescription, - this.noContentBuilder = _defaultNoContentBuilder, - this.errorBuilder = _defaultErrorBuilder, - }); + this.onProductDetail, + this.discountDescription, + this.noContentBuilder, + this.errorBuilder, + }) { + shoppingCartButtonBuilder ??= _defaultShoppingCartButtonBuilder; + productBuilder ??= _defaultProductBuilder; + appBar ??= _defaultAppBar; + onProductDetail ??= _onProductDetail; + discountDescription ??= _defaultDiscountDescription; + noContentBuilder ??= _defaultNoContentBuilder; + errorBuilder ??= _defaultErrorBuilder; + translations ??= const ProductPageTranslations(); + shopSelectorStyle ??= ShopSelectorStyle.row; + pagePadding ??= const EdgeInsets.all(4); + } /// The shopping service that is used final ShoppingService shoppingService; @@ -42,32 +54,36 @@ class ProductPageConfiguration { final Future> Function(Shop shop) getProducts; /// The localizations for the product page. - final ProductPageTranslations translations; + ProductPageTranslations? translations; /// Builder for the product item. These items will be displayed in the list /// for each product in their seperated category. This builder should only /// build the widget for one specific product. This builder has a default /// in-case the developer does not override it. - Widget Function(BuildContext context, Product product)? productBuilder; + Widget Function( + BuildContext context, + Product product, + ProductPageConfiguration configuration, + )? productBuilder; /// The builder for the product popup. This builder should return a widget Function( BuildContext context, Product product, String closeText, - ) onProductDetail; + )? onProductDetail; /// The builder for the shopping cart. This builder should return a widget /// that navigates to the shopping cart overview page. Widget Function( BuildContext context, ProductPageConfiguration configuration, - ) shoppingCartButtonBuilder; + )? shoppingCartButtonBuilder; /// The function that returns the discount description for a product. String Function( Product product, - ) discountDescription; + )? discountDescription; /// This function must be implemented by the developer and should handle the /// adding of a product to the cart. @@ -86,20 +102,20 @@ class ProductPageConfiguration { final Function() onNavigateToShoppingCart; /// The style of the shop selector. - final ShopSelectorStyle shopSelectorStyle; + ShopSelectorStyle? shopSelectorStyle; /// The padding for the page. - final EdgeInsets pagePadding; + EdgeInsets? pagePadding; /// Optional app bar that you can pass to the product page screen. final Widget? bottomNavigationBar; /// Optional app bar that you can pass to the order detail screen. - final AppBar Function(BuildContext context)? appBar; + AppBar Function(BuildContext context)? appBar; /// Builder for the no content widget. This builder is used when there is no /// content to display. - final Widget Function( + Widget Function( BuildContext context, )? noContentBuilder; @@ -109,7 +125,7 @@ class ProductPageConfiguration { BuildContext context, Object? error, StackTrace? stackTrace, - ) errorBuilder; + )? errorBuilder; } AppBar _defaultAppBar( @@ -157,7 +173,7 @@ Widget _defaultShoppingCartButtonBuilder( vertical: 12, ), child: Text( - configuration.translations.navigateToShoppingCart, + configuration.translations!.navigateToShoppingCart, style: theme.textTheme.displayLarge, ), ), @@ -214,3 +230,15 @@ Widget _defaultErrorBuilder( ), ); } + +Widget _defaultProductBuilder( + BuildContext context, + Product product, + ProductPageConfiguration configuration, +) => + ProductItem( + product: product, + onProductDetail: configuration.onProductDetail!, + onAddToCart: (Product product) => configuration.onAddToCart(product), + translations: configuration.translations!, + ); diff --git a/packages/flutter_product_page/lib/src/product_page_screen.dart b/packages/flutter_product_page/lib/src/product_page_screen.dart index 85aaf6f..0f1e414 100644 --- a/packages/flutter_product_page/lib/src/product_page_screen.dart +++ b/packages/flutter_product_page/lib/src/product_page_screen.dart @@ -23,11 +23,11 @@ class ProductPageScreen extends StatelessWidget { @override Widget build(BuildContext context) => Scaffold( - appBar: configuration.appBar!.call(context), + appBar: configuration.appBar?.call(context), bottomNavigationBar: configuration.bottomNavigationBar, body: SafeArea( child: Padding( - padding: configuration.pagePadding, + padding: configuration.pagePadding!, child: FutureBuilder( // ignore: discarded_futures future: configuration.shops(), @@ -43,7 +43,7 @@ class ProductPageScreen extends StatelessWidget { } if (data.hasError) { - return configuration.errorBuilder( + return configuration.errorBuilder!( context, data.error, data.stackTrace, @@ -53,7 +53,7 @@ class ProductPageScreen extends StatelessWidget { List? shops = data.data; if (shops == null || shops.isEmpty) { - return configuration.errorBuilder(context, null, null); + return configuration.errorBuilder!(context, null, null); } if (initialBuildShopId != null) { @@ -137,7 +137,7 @@ class _ProductPage extends StatelessWidget { pageContent, Align( alignment: Alignment.bottomCenter, - child: configuration.shoppingCartButtonBuilder( + child: configuration.shoppingCartButtonBuilder!( context, configuration, ), @@ -159,7 +159,7 @@ class _ShopContents extends StatelessWidget { var theme = Theme.of(context); return Padding( padding: EdgeInsets.symmetric( - horizontal: configuration.pagePadding.horizontal, + horizontal: configuration.pagePadding!.horizontal, ), child: FutureBuilder( // ignore: discarded_futures @@ -172,7 +172,7 @@ class _ShopContents extends StatelessWidget { } if (snapshot.hasError) { - return configuration.errorBuilder( + return configuration.errorBuilder!( context, snapshot.error, snapshot.stackTrace, diff --git a/packages/flutter_product_page/lib/src/services/category_service.dart b/packages/flutter_product_page/lib/src/services/category_service.dart index c09def2..91cd36c 100644 --- a/packages/flutter_product_page/lib/src/services/category_service.dart +++ b/packages/flutter_product_page/lib/src/services/category_service.dart @@ -1,7 +1,6 @@ import "package:flutter/material.dart"; import "package:flutter_nested_categories/flutter_nested_categories.dart"; import "package:flutter_product_page/flutter_product_page.dart"; -import "package:flutter_product_page/src/widgets/product_item.dart"; import "package:flutter_shopping_interface/flutter_shopping_interface.dart"; /// Generates a [CategoryList] from a list of [Product]s and a @@ -25,15 +24,8 @@ Widget getCategoryList( categorizedProducts.forEach((categoryName, productList) { var productWidgets = productList .map( - (product) => configuration.productBuilder != null - ? configuration.productBuilder!(context, product) - : ProductItem( - product: product, - onProductDetail: configuration.onProductDetail, - onAddToCart: (Product product) => - configuration.onAddToCart(product), - translations: configuration.translations, - ), + (product) => + configuration.productBuilder!(context, product, configuration), ) .toList(); var category = Category( diff --git a/packages/flutter_product_page/lib/src/widgets/weekly_discount.dart b/packages/flutter_product_page/lib/src/widgets/weekly_discount.dart index 79d0cc9..7323ffe 100644 --- a/packages/flutter_product_page/lib/src/widgets/weekly_discount.dart +++ b/packages/flutter_product_page/lib/src/widgets/weekly_discount.dart @@ -28,7 +28,7 @@ class WeeklyDiscount extends StatelessWidget { var bottomText = Padding( padding: const EdgeInsets.all(20.0), child: Text( - configuration.discountDescription(product), + configuration.discountDescription!(product), style: theme.textTheme.bodyMedium, textAlign: TextAlign.left, ), @@ -51,7 +51,7 @@ class WeeklyDiscount extends StatelessWidget { Icons.error_outline_rounded, color: Colors.red, ), - Text(configuration.translations.failedToLoadImageExplenation), + Text(configuration.translations!.failedToLoadImageExplenation), ], ), ), @@ -87,7 +87,7 @@ class WeeklyDiscount extends StatelessWidget { horizontal: 16, ), child: Text( - configuration.translations.discountTitle, + configuration.translations!.discountTitle, style: theme.textTheme.headlineSmall, textAlign: TextAlign.left, ), diff --git a/packages/flutter_product_page/pubspec.yaml b/packages/flutter_product_page/pubspec.yaml index 8477f9d..c28c746 100644 --- a/packages/flutter_product_page/pubspec.yaml +++ b/packages/flutter_product_page/pubspec.yaml @@ -23,10 +23,6 @@ dependencies: collection: ^1.18.0 provider: ^6.1.2 -dependency_overrides: - flutter_shopping_interface: - path: ../flutter_shopping_interface - dev_dependencies: flutter_test: sdk: flutter diff --git a/packages/flutter_shopping/example/.gitignore b/packages/flutter_shopping/example/.gitignore deleted file mode 100644 index 700e523..0000000 --- a/packages/flutter_shopping/example/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ -.metadata -pubspec.lock - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release - -# Platforms -android/ -ios/ -linux/ -macos/ -web/ -windows/ diff --git a/packages/flutter_shopping/example/README.md b/packages/flutter_shopping/example/README.md deleted file mode 100644 index 2b3fce4..0000000 --- a/packages/flutter_shopping/example/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# example - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/packages/flutter_shopping/example/analysis_options.yaml b/packages/flutter_shopping/example/analysis_options.yaml deleted file mode 100644 index 2a97d5c..0000000 --- a/packages/flutter_shopping/example/analysis_options.yaml +++ /dev/null @@ -1,7 +0,0 @@ -include: package:flutter_iconica_analysis/analysis_options.yaml - -analyzer: - exclude: - -linter: - rules: diff --git a/packages/flutter_shopping/example/lib/main.dart b/packages/flutter_shopping/example/lib/main.dart deleted file mode 100644 index 1157c00..0000000 --- a/packages/flutter_shopping/example/lib/main.dart +++ /dev/null @@ -1,22 +0,0 @@ -import "package:example/src/routes.dart"; -import "package:example/src/utils/theme.dart"; -import "package:flutter/material.dart"; -import "package:hooks_riverpod/hooks_riverpod.dart"; - -void main() { - runApp(const ProviderScope(child: MyApp())); -} - -class MyApp extends HookConsumerWidget { - const MyApp({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) => MaterialApp.router( - debugShowCheckedModeBanner: false, - restorationScopeId: "app", - theme: getTheme(), - routerConfig: ref.read(routerProvider), - ); -} diff --git a/packages/flutter_shopping/example/lib/src/configuration/configuration.dart b/packages/flutter_shopping/example/lib/src/configuration/configuration.dart deleted file mode 100644 index bb3454e..0000000 --- a/packages/flutter_shopping/example/lib/src/configuration/configuration.dart +++ /dev/null @@ -1,189 +0,0 @@ -import "package:example/src/routes.dart"; -import "package:example/src/services/order_service.dart"; -import "package:example/src/services/shop_service.dart"; -import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; - -// (REQUIRED): Create your own instance of the ProductService. -final ProductService productService = ProductService([]); - -FlutterShoppingConfiguration getFlutterShoppingConfiguration() => - FlutterShoppingConfiguration( - // (REQUIRED): Shop builder configuration - shopBuilder: ( - BuildContext context, - String? initialBuildShopId, - String? streetName, - ) => - ProductPageScreen( - configuration: ProductPageConfiguration( - // (REQUIRED): List of shops that should be displayed - // If there is only one, make a list with just one shop. - shops: Future.value(getShops()), - - // (REQUIRED): Function to add a product to the cart - onAddToCart: productService.addProduct, - - // (REQUIRED): Function to get the products for a shop - getProducts: (ProductPageShop shop) => - Future.value( - getShopContent(shop.id), - ), - - // (REQUIRED): Function to navigate to the shopping cart - onNavigateToShoppingCart: () async => onCompleteProductPage(context), - - // (RECOMMENDED): Function to get the number of products in the - // shopping cart. This is used to display the number of products - // in the shopping cart on the product page. - getProductsInShoppingCart: productService.countProducts, - - // (RECOMMENDED) Function that returns the description for a - // product that is on sale. - getDiscountDescription: (product) => - """${product.name} for just \$${product.discountPrice?.toStringAsFixed(2)}""", - - // (RECOMMENDED) Function that is fired when the shop selection - // changes. You could use this to clear your shopping cart or to - // change the products so they belong to the correct shop again. - onShopSelectionChange: (ProductPageShop shop) => - productService.clear(), - - // (RECOMMENDED) The shop that is initially selected. - // Must be one of the shops in the [shops] list. - initialShopId: getShops().first.id, - - // (RECOMMENDED) Localizations for the product page. - localizations: const ProductPageLocalization(), - - // (OPTIONAL) Appbar - appBar: (context) => AppBar( - title: const Text("Shop"), - leading: IconButton( - icon: const Icon( - Icons.arrow_back, - color: Colors.white, - ), - onPressed: () { - context.go(homePage); - }, - ), - ), - ), - - // (OPTIONAL): Initial build shop id that overrides the initialShop - initialBuildShopId: initialBuildShopId, - ), - - // (REQUIRED): Shopping cart builder configuration - shoppingCartBuilder: (BuildContext context) => ShoppingCartScreen( - configuration: ShoppingCartConfig( - // (REQUIRED) product service instance: - productService: productService, - - // (REQUIRED) product item builder: - productItemBuilder: (context, locale, product, service, config) => - ListTile( - title: Text(product.name), - subtitle: Text(product.price.toStringAsFixed(2)), - leading: Image.network( - product.imageUrl, - errorBuilder: (context, error, stackTrace) => const Tooltip( - message: "Error loading image", - child: Icon( - Icons.error, - color: Colors.red, - ), - ), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.remove), - onPressed: () => productService.removeOneProduct(product), - ), - Text("${product.quantity}"), - IconButton( - icon: const Icon(Icons.add), - onPressed: () => productService.addProduct(product), - ), - ], - ), - ), - - // (OPTIONAL/REQUIRED) on confirm order callback: - // Either use this callback or the placeOrderButtonBuilder. - onConfirmOrder: (products) async => onCompleteShoppingCart(context), - - // (RECOMMENDED) localizations: - localizations: const ShoppingCartLocalizations(), - - /// (OPTIONAL) no content builder for when there are no products - /// in the shopping cart. - noContentBuilder: (context) => const Center( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 128), - child: Column( - children: [ - Icon( - Icons.warning, - ), - SizedBox( - height: 16, - ), - Text( - "Geen producten in winkelmandje", - ), - ], - ), - ), - ), - - // (OPTIONAL) custom appbar: - appBar: AppBar( - title: const Text("Shopping Cart"), - leading: IconButton( - icon: const Icon( - Icons.arrow_back, - color: Colors.white, - ), - onPressed: () { - context.go(FlutterShoppingPathRoutes.shop); - }, - ), - ), - ), - ), - - // (REQUIRED): Configuration on what to do when the user story is - // completed. - onCompleteUserStory: (BuildContext context) { - context.go(homePage); - }, - - // (RECOMMENDED) Handle processing of the order details. This function - // should return true if the order was processed successfully, otherwise - // false. - // - // If this function is not provided, it is assumed that the order is - // always processed successfully. - // - // Example use cases that could be implemented here: - // - Sending and storing the order on a server, - // - Processing payment (if the user decides to pay upfront). - // - And many more... - onCompleteOrderDetails: - (BuildContext context, OrderResult orderDetails) async { - if (orderDetails.order["payment_option"] == "Pay now") { - // Make the user pay upfront. - } - - // If all went well, we can store the order in the database. - // Make sure to register whether or not the order was paid. - storeOrderInDatabase(productService.products, orderDetails); - - return true; - }, - ); diff --git a/packages/flutter_shopping/example/lib/src/models/my_shop.dart b/packages/flutter_shopping/example/lib/src/models/my_shop.dart deleted file mode 100644 index 9018fcc..0000000 --- a/packages/flutter_shopping/example/lib/src/models/my_shop.dart +++ /dev/null @@ -1,8 +0,0 @@ -import "package:flutter_shopping/flutter_shopping.dart"; - -class MyShop extends ProductPageShop { - const MyShop({ - required super.id, - required super.name, - }); -} diff --git a/packages/flutter_shopping/example/lib/src/routes.dart b/packages/flutter_shopping/example/lib/src/routes.dart deleted file mode 100644 index 4899345..0000000 --- a/packages/flutter_shopping/example/lib/src/routes.dart +++ /dev/null @@ -1,31 +0,0 @@ -import "package:example/src/configuration/configuration.dart"; -import "package:example/src/ui/homepage.dart"; -import "package:example/src/utils/go_router.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; -import "package:hooks_riverpod/hooks_riverpod.dart"; - -const String homePage = "/"; - -final routerProvider = Provider( - (ref) => GoRouter( - initialLocation: homePage, - routes: [ - // Flutter Shopping Story Routes - ...getShoppingStoryRoutes( - configuration: getFlutterShoppingConfiguration(), - ), - - // Home Route - GoRoute( - name: "home", - path: homePage, - pageBuilder: (context, state) => buildScreenWithFadeTransition( - context: context, - state: state, - child: const Homepage(), - ), - ), - ], - ), -); diff --git a/packages/flutter_shopping/example/lib/src/services/order_service.dart b/packages/flutter_shopping/example/lib/src/services/order_service.dart deleted file mode 100644 index 6078e6a..0000000 --- a/packages/flutter_shopping/example/lib/src/services/order_service.dart +++ /dev/null @@ -1,6 +0,0 @@ -import "package:flutter_shopping/flutter_shopping.dart"; - -/// Example implementation of storing an order in a database. -void storeOrderInDatabase(List products, OrderResult result) { - return; -} diff --git a/packages/flutter_shopping/example/lib/src/services/shop_service.dart b/packages/flutter_shopping/example/lib/src/services/shop_service.dart deleted file mode 100644 index a8e8f65..0000000 --- a/packages/flutter_shopping/example/lib/src/services/shop_service.dart +++ /dev/null @@ -1,49 +0,0 @@ -import "package:example/src/models/my_shop.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; - -/// This function should have your own implementation. Generally this would -/// contain some API call to fetch the list of shops. -List getShops() => [ - const MyShop(id: "1", name: "Shop 1"), - const MyShop(id: "2", name: "Shop 2"), - const MyShop(id: "3", name: "Shop 3"), - ]; - -ProductPageContent getShopContent(String shopId) { - var products = getProducts(shopId); - return ProductPageContent( - discountedProduct: products.first, - products: products, - ); -} - -/// This function should have your own implementation. Generally this would -/// contain some API call to fetch the list of products for a shop. -List getProducts(String shopId) => [ - Product( - id: "1", - name: "White bread", - price: 2.99, - category: "Loaves", - imageUrl: "https://via.placeholder.com/150", - hasDiscount: true, - discountPrice: 1.99, - description: "", - ), - Product( - id: "2", - name: "Brown bread", - price: 2.99, - category: "Loaves", - imageUrl: "https://via.placeholder.com/150", - description: "", - ), - Product( - id: "3", - name: "Cheese sandwich", - price: 1.99, - category: "Sandwiches", - imageUrl: "https://via.placeholder.com/150", - description: "", - ), - ]; diff --git a/packages/flutter_shopping/example/lib/src/ui/homepage.dart b/packages/flutter_shopping/example/lib/src/ui/homepage.dart deleted file mode 100644 index 46e1373..0000000 --- a/packages/flutter_shopping/example/lib/src/ui/homepage.dart +++ /dev/null @@ -1,20 +0,0 @@ -import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; - -class Homepage extends StatelessWidget { - const Homepage({super.key}); - - @override - Widget build(BuildContext context) => Scaffold( - body: Center( - child: Badge( - label: const Text("1"), - child: IconButton( - icon: const Icon(Icons.shopping_cart_outlined, size: 50), - onPressed: () => context.go(FlutterShoppingPathRoutes.shop), - ), - ), - ), - ); -} diff --git a/packages/flutter_shopping/example/lib/src/utils/go_router.dart b/packages/flutter_shopping/example/lib/src/utils/go_router.dart deleted file mode 100644 index d7b239a..0000000 --- a/packages/flutter_shopping/example/lib/src/utils/go_router.dart +++ /dev/null @@ -1,26 +0,0 @@ -import "package:flutter/material.dart"; -import "package:go_router/go_router.dart"; - -CustomTransitionPage buildScreenWithFadeTransition({ - required BuildContext context, - required GoRouterState state, - required Widget child, -}) => - CustomTransitionPage( - key: state.pageKey, - child: child, - transitionsBuilder: (context, animation, secondaryAnimation, child) => - FadeTransition(opacity: animation, child: child), - ); - -CustomTransitionPage buildScreenWithoutTransition({ - required BuildContext context, - required GoRouterState state, - required Widget child, -}) => - CustomTransitionPage( - key: state.pageKey, - child: child, - transitionsBuilder: (context, animation, secondaryAnimation, child) => - child, - ); diff --git a/packages/flutter_shopping/example/lib/src/utils/theme.dart b/packages/flutter_shopping/example/lib/src/utils/theme.dart deleted file mode 100644 index a0bf1d8..0000000 --- a/packages/flutter_shopping/example/lib/src/utils/theme.dart +++ /dev/null @@ -1,32 +0,0 @@ -import "package:flutter/material.dart"; - -ThemeData getTheme() => ThemeData( - scaffoldBackgroundColor: const Color.fromRGBO(250, 249, 246, 1), - textTheme: const TextTheme( - labelMedium: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - color: Colors.black, - ), - titleMedium: TextStyle( - fontSize: 16, - color: Color.fromRGBO(60, 60, 59, 1), - fontWeight: FontWeight.w700, - ), - ), - inputDecorationTheme: const InputDecorationTheme( - fillColor: Colors.white, - ), - colorScheme: const ColorScheme.light( - primary: Color.fromRGBO(64, 87, 122, 1), - secondary: Colors.white, - surface: Color.fromRGBO(250, 249, 246, 1), - ), - appBarTheme: const AppBarTheme( - backgroundColor: Color.fromRGBO(64, 87, 122, 1), - titleTextStyle: TextStyle( - fontSize: 28, - color: Colors.white, - ), - ), - ); diff --git a/packages/flutter_shopping/example/pubspec.yaml b/packages/flutter_shopping/example/pubspec.yaml deleted file mode 100644 index d9bf03b..0000000 --- a/packages/flutter_shopping/example/pubspec.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: example -description: Demonstrates how to use the flutter_shopping package." -publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.0 - -environment: - sdk: '>=3.3.4 <4.0.0' - -dependencies: - flutter: - sdk: flutter - flutter_hooks: ^0.20.0 - hooks_riverpod: ^2.1.1 - go_router: 12.1.3 - flutter_shopping: - git: - url: https://github.com/Iconica-Development/flutter_shopping - path: packages/flutter_shopping - ref: 2.0.0 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_iconica_analysis: - git: - url: https://github.com/Iconica-Development/flutter_iconica_analysis - ref: 7.0.0 - -flutter: - uses-material-design: true - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic diff --git a/packages/flutter_shopping/example_amazon/.gitignore b/packages/flutter_shopping/example_amazon/.gitignore deleted file mode 100644 index 8760a85..0000000 --- a/packages/flutter_shopping/example_amazon/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ -.metadata -pubspec.lock - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release - -# Platforms -/android/ -/ios/ -/linux/ -/macos/ -/web/ -/windows/ diff --git a/packages/flutter_shopping/example_amazon/README.md b/packages/flutter_shopping/example_amazon/README.md deleted file mode 100644 index eddfc9c..0000000 --- a/packages/flutter_shopping/example_amazon/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# amazon - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/packages/flutter_shopping/example_amazon/analysis_options.yaml b/packages/flutter_shopping/example_amazon/analysis_options.yaml deleted file mode 100644 index 0d29021..0000000 --- a/packages/flutter_shopping/example_amazon/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/flutter_shopping/example_amazon/lib/main.dart b/packages/flutter_shopping/example_amazon/lib/main.dart deleted file mode 100644 index a48842e..0000000 --- a/packages/flutter_shopping/example_amazon/lib/main.dart +++ /dev/null @@ -1,22 +0,0 @@ -import "package:amazon/src/routes.dart"; -import "package:amazon/src/utils/theme.dart"; -import "package:flutter/material.dart"; -import "package:hooks_riverpod/hooks_riverpod.dart"; - -void main() { - runApp(const ProviderScope(child: MyApp())); -} - -class MyApp extends HookConsumerWidget { - const MyApp({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) => MaterialApp.router( - debugShowCheckedModeBanner: false, - restorationScopeId: "app", - theme: getTheme(), - routerConfig: ref.read(routerProvider), - ); -} diff --git a/packages/flutter_shopping/example_amazon/lib/src/configuration/shopping_configuration.dart b/packages/flutter_shopping/example_amazon/lib/src/configuration/shopping_configuration.dart deleted file mode 100644 index 3bcce30..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/configuration/shopping_configuration.dart +++ /dev/null @@ -1,362 +0,0 @@ -import "package:amazon/src/routes.dart"; -import "package:amazon/src/services/category_service.dart"; -import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; - -// (REQUIRED): Create your own instance of the ProductService. -final ProductService productService = ProductService([]); - -FlutterShoppingConfiguration getFlutterShoppingConfiguration() => - FlutterShoppingConfiguration( - // (REQUIRED): Shop builder configuration - shopBuilder: ( - BuildContext context, - String? initialBuildShopId, - String? streetName, - ) { - var theme = Theme.of(context); - - return ProductPageScreen( - configuration: ProductPageConfiguration( - // (REQUIRED): List of shops that should be displayed - // If there is only one, make a list with just one shop. - shops: Future.value(getCategories()), - - pagePadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4), - - // (REQUIRED): Function to add a product to the cart - onAddToCart: (product) { - return productService.addProduct(product); - }, - - // (REQUIRED): Function to get the products for a shop - getProducts: (ProductPageShop shop) => - Future.value( - getShopContent(shop.id), - ), - - // (REQUIRED): Function to navigate to the shopping cart - onNavigateToShoppingCart: () => onCompleteProductPage(context), - - shopSelectorStyle: ShopSelectorStyle.row, - - navigateToShoppingCartBuilder: (context, productpageinfo, shop) { - return const SizedBox.shrink(); - }, - - bottomNavigationBar: BottomNavigationBar( - fixedColor: theme.primaryColor, - unselectedItemColor: Colors.black, - type: BottomNavigationBarType.fixed, - items: const [ - BottomNavigationBarItem( - icon: Icon(Icons.home), - label: "Home", - ), - BottomNavigationBarItem( - icon: Icon(Icons.person_2_outlined), - label: "Profile", - ), - BottomNavigationBarItem( - icon: Icon(Icons.shopping_cart_outlined), - label: "Cart", - ), - BottomNavigationBarItem( - icon: Icon(Icons.menu), - label: "Menu", - ), - ], - showSelectedLabels: false, - showUnselectedLabels: false, - onTap: (index) { - switch (index) { - case 0: - // context.go(homePage); - break; - case 1: - break; - case 2: - context.go(FlutterShoppingPathRoutes.shoppingCart); - break; - case 3: - break; - } - }, - ), - - productBuilder: (context, product) => Card( - elevation: 0, - color: const Color.fromARGB(255, 233, 233, 233), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.zero, - ), - child: Row( - children: [ - Expanded( - flex: 3, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.network( - product.imageUrl, - loadingBuilder: (context, child, loadingProgress) => - loadingProgress == null - ? child - : const Center( - child: CircularProgressIndicator(), - ), - errorBuilder: (context, error, stackTrace) => - const Tooltip( - message: "Error loading image", - child: Icon( - Icons.error, - color: Colors.red, - ), - ), - ), - ), - ), - Expanded( - flex: 5, - child: ColoredBox( - color: theme.scaffoldBackgroundColor, - child: Padding( - padding: const EdgeInsets.all(8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - product.name, - style: theme.textTheme.titleMedium, - maxLines: 3, - overflow: TextOverflow.ellipsis, - ), - Row( - children: [ - Text( - "4.5", - style: theme.textTheme.bodyMedium?.copyWith( - color: Colors.blue, - ), - ), - const Icon(Icons.star, color: Colors.orange), - const Icon(Icons.star, color: Colors.orange), - const Icon(Icons.star, color: Colors.orange), - const Icon(Icons.star, color: Colors.orange), - const Icon(Icons.star_half, - color: Colors.orange), - Text( - "(3)", - style: theme.textTheme.bodyMedium?.copyWith( - color: Colors.grey, - ), - ), - ], - ), - Text( - "\$${product.price.toStringAsFixed(2)}", - style: theme.textTheme.titleMedium, - ), - Text( - "Gratis bezorging door Amazon", - style: theme.textTheme.bodyMedium?.copyWith( - color: Colors.grey, - ), - ), - const SizedBox(height: 12), - FilledButton( - onPressed: () { - productService.addProduct(product); - }, - child: const Text("In winkelwagen"), - ), - ], - ), - ), - ), - ), - ], - ), - ), - - // (RECOMMENDED) The shop that is initially selected. - // Must be one of the shops in the [shops] list. - initialShopId: getCategories().first.id, - - // (RECOMMENDED) Localizations for the product page. - localizations: const ProductPageLocalization(), - - noContentBuilder: (context) => Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 128), - child: Column( - children: [ - const Icon( - Icons.warning, - size: 48, - ), - const SizedBox( - height: 16, - ), - Text( - "Geen producten gevonden", - style: theme.textTheme.titleLarge, - ), - ], - ), - ), - ), - - // (OPTIONAL) Appbar - appBar: (context) => AppBar( - title: const SizedBox( - height: 40, - child: SearchBar( - hintText: "Search products", - leading: Icon( - Icons.search, - color: Colors.black, - ), - trailing: [ - Icon( - Icons.fit_screen_outlined, - ), - ], - ), - ), - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () { - context.go(homePage); - }, - ), - bottom: AppBar( - backgroundColor: const Color.fromRGBO(203, 237, 230, 1), - title: Row( - children: [ - const Icon(Icons.location_on_outlined), - const SizedBox(width: 12), - Expanded( - child: Text( - "Bestemming: ${streetName ?? "Mark - 1234AB Doetinchem Nederland"}", - overflow: TextOverflow.ellipsis, - style: theme.textTheme.titleMedium?.copyWith( - color: Colors.black, - ), - ), - ), - ], - ), - primary: false, - ), - ), - ), - - // (OPTIONAL): Initial build shop id that overrides the initialShop - initialBuildShopId: initialBuildShopId, - ); - }, - - // (REQUIRED): Shopping cart builder configuration - shoppingCartBuilder: (BuildContext context) => ShoppingCartScreen( - configuration: ShoppingCartConfig( - // (REQUIRED) product service instance: - productService: productService, - - // (REQUIRED) product item builder: - productItemBuilder: (context, locale, product, service, config) => - ListTile( - title: Text(product.name), - subtitle: Text(product.price.toStringAsFixed(2)), - leading: Image.network( - product.imageUrl, - errorBuilder: (context, error, stackTrace) => const Tooltip( - message: "Error loading image", - child: Icon( - Icons.error, - color: Colors.red, - ), - ), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.remove), - onPressed: () => productService.removeOneProduct(product), - ), - Text("${product.quantity}"), - IconButton( - icon: const Icon(Icons.add), - onPressed: () => productService.addProduct(product), - ), - ], - ), - ), - - // (OPTIONAL/REQUIRED) on confirm order callback: - // Either use this callback or the placeOrderButtonBuilder. - onConfirmOrder: (products) => onCompleteShoppingCart(context), - - // (RECOMMENDED) localizations: - localizations: const ShoppingCartLocalizations(), - - /// (OPTIONAL) no content builder for when there are no products - /// in the shopping cart. - noContentBuilder: (context) => const Center( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 128), - child: Column( - children: [ - Icon( - Icons.warning, - ), - SizedBox( - height: 16, - ), - Text( - "Geen producten in winkelmandje", - ), - ], - ), - ), - ), - - // (OPTIONAL) custom appbar: - appBar: AppBar( - title: const Text("Shopping Cart"), - leading: IconButton( - icon: const Icon( - Icons.arrow_back, - color: Colors.white, - ), - onPressed: () { - context.go(FlutterShoppingPathRoutes.shop); - }, - ), - ), - ), - ), - - // (REQUIRED): Configuration on what to do when the user story is - // completed. - onCompleteUserStory: (BuildContext context) { - context.go(homePage); - }, - - // (RECOMMENDED) Handle processing of the order details. This function - // should return true if the order was processed successfully, otherwise - // false. - // - // If this function is not provided, it is assumed that the order is - // always processed successfully. - // - // Example use cases that could be implemented here: - // - Sending and storing the order on a server, - // - Processing payment (if the user decides to pay upfront). - // - And many more... - // onCompleteOrderDetails: - // (BuildContext context, OrderResult orderDetails) async { - // return true; - // }, - ); diff --git a/packages/flutter_shopping/example_amazon/lib/src/models/my_category.dart b/packages/flutter_shopping/example_amazon/lib/src/models/my_category.dart deleted file mode 100644 index 0899d37..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/models/my_category.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:flutter_shopping/flutter_shopping.dart'; - -class MyCategory extends ProductPageShop { - const MyCategory({ - required super.id, - required super.name, - }); -} diff --git a/packages/flutter_shopping/example_amazon/lib/src/routes.dart b/packages/flutter_shopping/example_amazon/lib/src/routes.dart deleted file mode 100644 index 8e82277..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/routes.dart +++ /dev/null @@ -1,30 +0,0 @@ -import "package:amazon/src/configuration/shopping_configuration.dart"; -import "package:amazon/src/ui/homepage.dart"; -import "package:amazon/src/utils/go_router.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; -import "package:hooks_riverpod/hooks_riverpod.dart"; - -const String homePage = "/"; - -final routerProvider = Provider( - (ref) => GoRouter( - initialLocation: homePage, - routes: [ - // Flutter Shopping Story Routes - ...getShoppingStoryRoutes( - configuration: getFlutterShoppingConfiguration(), - ), - // Home Route - GoRoute( - name: "home", - path: homePage, - pageBuilder: (context, state) => buildScreenWithFadeTransition( - context: context, - state: state, - child: const Homepage(), - ), - ), - ], - ), -); diff --git a/packages/flutter_shopping/example_amazon/lib/src/services/category_service.dart b/packages/flutter_shopping/example_amazon/lib/src/services/category_service.dart deleted file mode 100644 index 69af668..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/services/category_service.dart +++ /dev/null @@ -1,93 +0,0 @@ -import "package:amazon/src/models/my_category.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; - -Map categories = { - "Electronics": "Electronica", - "Smart phones": "Telefoons", - "TV's": "TV's", -}; - -List allProducts() => [ - Product( - id: "1", - name: - "Skar Audio Single 8\" Complete 1,200 Watt EVL Series Subwoofer Bass Package - Includes Loaded Enclosure with...", - price: 2.99, - category: categories["Electronics"]!, - imageUrl: - "https://m.media-amazon.com/images/I/710n3hnbfXL._AC_UY218_.jpg", - description: "", - ), - Product( - id: "2", - name: - "Frameo 10.1 Inch WiFi Digital Picture Frame, 1280x800 HD IPS Touch Screen Photo Frame Electronic, 32GB Memory, Auto...", - price: 2.99, - category: categories["Electronics"]!, - imageUrl: - "https://m.media-amazon.com/images/I/61O+aorCp0L._AC_UY218_.jpg", - description: "", - ), - Product( - id: "3", - name: - "STREBITO Electronics Precision Screwdriver Sets 142-Piece with 120 Bits Magnetic Repair Tool Kit for iPhone, MacBook,...", - price: 1.99, - category: categories["Electronics"]!, - imageUrl: - "https://m.media-amazon.com/images/I/81-C7lGtQsL._AC_UY218_.jpg", - description: "", - ), - Product( - id: "4", - name: - "Samsung Galaxy A15 (SM-155M/DSN), 128GB 6GB RAM, Dual SIM, Factory Unlocked GSM, International Version (Wall...", - price: 1.99, - category: categories["Smart phones"]!, - imageUrl: - "https://m.media-amazon.com/images/I/51rp0nqaPoL._AC_UY218_.jpg", - description: "", - ), - Product( - id: "5", - name: - "SAMSUNG Galaxy S24 Ultra Cell Phone, 512GB AI Smartphone, Unlocked Android, 50MP Zoom Camera, Long...", - price: 1.99, - category: categories["Smart phones"]!, - imageUrl: - "https://m.media-amazon.com/images/I/71ZoDT7a2wL._AC_UY218_.jpg", - description: "", - ), - ]; - -List getCategories() => [ - MyCategory(id: "1", name: categories["Electronics"]!), - MyCategory(id: "2", name: categories["Smart phones"]!), - MyCategory(id: "3", name: categories["TV's"]!), - const MyCategory(id: "4", name: "Monitoren"), - const MyCategory(id: "5", name: "Speakers"), - const MyCategory(id: "6", name: "Toetsenborden"), - ]; - -ProductPageContent getShopContent(String shopId) { - var products = getProducts(shopId); - return ProductPageContent( - products: products, - ); -} - -List getProducts(String categoryId) { - if (categoryId == "1") { - return allProducts(); - } else if (categoryId == "2") { - return allProducts() - .where((product) => product.category == categories["Smart phones"]!) - .toList(); - } else if (categoryId == "3") { - return allProducts() - .where((product) => product.category == categories["TV's"]!) - .toList(); - } else { - return []; - } -} diff --git a/packages/flutter_shopping/example_amazon/lib/src/ui/homepage.dart b/packages/flutter_shopping/example_amazon/lib/src/ui/homepage.dart deleted file mode 100644 index 46e1373..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/ui/homepage.dart +++ /dev/null @@ -1,20 +0,0 @@ -import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; - -class Homepage extends StatelessWidget { - const Homepage({super.key}); - - @override - Widget build(BuildContext context) => Scaffold( - body: Center( - child: Badge( - label: const Text("1"), - child: IconButton( - icon: const Icon(Icons.shopping_cart_outlined, size: 50), - onPressed: () => context.go(FlutterShoppingPathRoutes.shop), - ), - ), - ), - ); -} diff --git a/packages/flutter_shopping/example_amazon/lib/src/utils/go_router.dart b/packages/flutter_shopping/example_amazon/lib/src/utils/go_router.dart deleted file mode 100644 index d7b239a..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/utils/go_router.dart +++ /dev/null @@ -1,26 +0,0 @@ -import "package:flutter/material.dart"; -import "package:go_router/go_router.dart"; - -CustomTransitionPage buildScreenWithFadeTransition({ - required BuildContext context, - required GoRouterState state, - required Widget child, -}) => - CustomTransitionPage( - key: state.pageKey, - child: child, - transitionsBuilder: (context, animation, secondaryAnimation, child) => - FadeTransition(opacity: animation, child: child), - ); - -CustomTransitionPage buildScreenWithoutTransition({ - required BuildContext context, - required GoRouterState state, - required Widget child, -}) => - CustomTransitionPage( - key: state.pageKey, - child: child, - transitionsBuilder: (context, animation, secondaryAnimation, child) => - child, - ); diff --git a/packages/flutter_shopping/example_amazon/lib/src/utils/theme.dart b/packages/flutter_shopping/example_amazon/lib/src/utils/theme.dart deleted file mode 100644 index 0342db9..0000000 --- a/packages/flutter_shopping/example_amazon/lib/src/utils/theme.dart +++ /dev/null @@ -1,43 +0,0 @@ -import "package:flutter/material.dart"; - -ThemeData getTheme() => ThemeData( - scaffoldBackgroundColor: const Color.fromRGBO(250, 249, 246, 1), - textTheme: const TextTheme( - labelMedium: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w400, - color: Colors.black, - ), - titleMedium: TextStyle( - fontSize: 16, - color: Color.fromRGBO(60, 60, 59, 1), - fontWeight: FontWeight.w700, - ), - ), - inputDecorationTheme: const InputDecorationTheme( - fillColor: Colors.white, - ), - colorScheme: const ColorScheme.light( - primary: Color.fromRGBO(161, 203, 211, 1), - secondary: Color.fromRGBO(221, 235, 238, 1), - surface: Color.fromRGBO(255, 255, 255, 1), - ), - appBarTheme: const AppBarTheme( - backgroundColor: Color.fromRGBO(161, 220, 218, 1), - foregroundColor: Colors.black, - titleTextStyle: TextStyle( - fontSize: 28, - color: Colors.white, - ), - ), - filledButtonTheme: FilledButtonThemeData( - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - Colors.yellow, - ), - foregroundColor: WidgetStateProperty.all( - Colors.black, - ), - ), - ), - ); diff --git a/packages/flutter_shopping/example_amazon/pubspec.yaml b/packages/flutter_shopping/example_amazon/pubspec.yaml deleted file mode 100644 index fb6267b..0000000 --- a/packages/flutter_shopping/example_amazon/pubspec.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: amazon -description: "A new Flutter project." -publish_to: 'none' -version: 1.0.0 - -environment: - sdk: '>=3.4.1 <4.0.0' - -dependencies: - flutter: - sdk: flutter - flutter_hooks: ^0.20.0 - hooks_riverpod: ^2.1.1 - go_router: 12.1.3 - flutter_nested_categories: - git: - url: https://github.com/Iconica-Development/flutter_nested_categories - ref: 0.0.1 - flutter_shopping: - git: - url: https://github.com/Iconica-Development/flutter_shopping - path: packages/flutter_shopping - ref: 2.0.0 - -dev_dependencies: - flutter_test: - sdk: flutter - flutter_lints: ^3.0.0 - -flutter: - uses-material-design: true diff --git a/packages/flutter_shopping/example_amazon/test/widget_test.dart b/packages/flutter_shopping/example_amazon/test/widget_test.dart deleted file mode 100644 index 2c6d019..0000000 --- a/packages/flutter_shopping/example_amazon/test/widget_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Iconica -// -// SPDX-License-Identifier: BSD-3-Clause - -import "package:flutter_test/flutter_test.dart"; - -void main() { - test("", () { - expect(true, true); - }); -} diff --git a/packages/flutter_shopping/lib/flutter_shopping.dart b/packages/flutter_shopping/lib/flutter_shopping.dart index 5e962e1..7732379 100644 --- a/packages/flutter_shopping/lib/flutter_shopping.dart +++ b/packages/flutter_shopping/lib/flutter_shopping.dart @@ -5,8 +5,5 @@ export "package:flutter_order_details/flutter_order_details.dart"; export "package:flutter_product_page/flutter_product_page.dart"; export "package:flutter_shopping_cart/flutter_shopping_cart.dart"; -export "src/config/flutter_shopping_configuration.dart"; -export "src/models/product.dart"; -export "src/routes.dart"; -export "src/user_stores/flutter_shopping_userstory_go_router.dart"; -export "src/user_stores/flutter_shopping_userstory_navigation.dart"; +export "src/configuration/shopping_configuration.dart"; +export "src/flutter_shopping_navigator_userstory.dart"; diff --git a/packages/flutter_shopping/lib/src/config/flutter_shopping_configuration.dart b/packages/flutter_shopping/lib/src/config/flutter_shopping_configuration.dart deleted file mode 100644 index 7b18e74..0000000 --- a/packages/flutter_shopping/lib/src/config/flutter_shopping_configuration.dart +++ /dev/null @@ -1,43 +0,0 @@ -import "package:flutter/material.dart"; -import "package:flutter_order_details/flutter_order_details.dart"; - -/// Configuration class for the flutter_shopping user-story. -class FlutterShoppingConfiguration { - /// Constructor for the FlutterShoppingConfiguration. - const FlutterShoppingConfiguration({ - required this.shopBuilder, - required this.shoppingCartBuilder, - required this.onCompleteUserStory, - this.orderDetailsBuilder, - this.onCompleteOrderDetails, - this.orderSuccessBuilder, - this.orderFailedBuilder, - }); - - /// Builder for the shop/product page. - final Widget Function( - BuildContext context, - String? initialBuildShopId, - String? streetName, - ) shopBuilder; - - /// Builder for the shopping cart page. - final Widget Function(BuildContext context) shoppingCartBuilder; - - /// Function that is called when the user-story is completed. - final Function(BuildContext context) onCompleteUserStory; - - /// Builder for the order details page. This does not have to be set if you - /// are using the default order details page. - final Widget Function(BuildContext context)? orderDetailsBuilder; - - /// Allows you to execute actions before - final Future Function(BuildContext context, OrderResult result)? - onCompleteOrderDetails; - - /// Builder for when the order is successful. - final Widget Function(BuildContext context)? orderSuccessBuilder; - - /// Builder for when the order failed. - final Widget Function(BuildContext context)? orderFailedBuilder; -} diff --git a/packages/flutter_shopping/lib/src/config/order_details_localizations.dart b/packages/flutter_shopping/lib/src/config/order_details_localizations.dart deleted file mode 100644 index af50182..0000000 --- a/packages/flutter_shopping/lib/src/config/order_details_localizations.dart +++ /dev/null @@ -1,10 +0,0 @@ -/// Contains the localized strings for the order details screen. -class OrderDetailsLocalizations { - /// Creates order details localizations - OrderDetailsLocalizations({ - this.orderDetailsTitle = "Information", - }); - - /// Title for the order details screen. - final String orderDetailsTitle; -} diff --git a/packages/flutter_shopping/lib/src/configuration/shopping_configuration.dart b/packages/flutter_shopping/lib/src/configuration/shopping_configuration.dart new file mode 100644 index 0000000..b1ae186 --- /dev/null +++ b/packages/flutter_shopping/lib/src/configuration/shopping_configuration.dart @@ -0,0 +1,218 @@ +import "package:flutter/material.dart"; +import "package:flutter_shopping/flutter_shopping.dart"; +import "package:flutter_shopping_interface/flutter_shopping_interface.dart"; + +/// configuration for the shopping userstory +class ShoppingConfiguration { + /// constructor for the userstory configuration + const ShoppingConfiguration({ + /// ProductPage configurations + required this.shoppingService, + this.onGetProducts, + this.onGetShops, + this.onAddToCart, + this.onNavigateToShoppingCart, + this.getProductsInShoppingCart, + this.shoppingCartButtonBuilder, + this.initialShopid, + this.productBuilder, + this.onShopSelectionChange, + this.productPageTranslations, + this.shopSelectorStyle, + this.productPagePagePadding, + this.productPageAppBarBuilder, + this.bottomNavigationBarBuilder, + this.onProductDetail, + this.discountDescription, + this.noContentBuilder, + this.errorBuilder, + + /// ShoppingCart configurations + this.onConfirmOrder, + this.productItemBuilder, + this.confirmOrderButtonBuilder, + this.confirmOrderButtonHeight, + this.sumBottomSheetBuilder, + this.sumBottomSheetHeight, + this.titleBuilder, + this.shoppingCartTranslations, + this.shoppingCartPagePadding, + this.shoppingCartBottomPadding, + this.shoppingCartAppBarBuilder, + + /// OrderDetail configurations + this.onNextStep, + this.onStepsCompleted, + this.onCompleteOrderDetails, + this.pages, + this.orderDetailTranslations, + this.orderDetailAppBarBuilder, + this.orderDetailNextbuttonBuilder, + this.orderSuccessBuilder, + }); + + /// The service that will be used for the userstory + final ShoppingService shoppingService; + + /// Function that will be called when the products are requested + final Future> Function(String shopId)? onGetProducts; + + /// Function that will be called when the shops are requested + final Future> Function()? onGetShops; + + /// Function that will be called when an item is added to the shopping cart + final Function(Product)? onAddToCart; + + /// Function that will be called when the user navigates to the shopping cart + final Function()? onNavigateToShoppingCart; + + /// Function that will be called to get the amount of + /// products in the shopping cart + final int Function()? getProductsInShoppingCart; + + /// Default shopping cart button builder + final Widget Function(BuildContext, ProductPageConfiguration)? + shoppingCartButtonBuilder; + + /// Initial shop that will be selected + final String? initialShopid; + + /// ProductPage item builder + final Widget Function( + BuildContext, + Product, + ProductPageConfiguration configuration, + )? productBuilder; + + /// Function that will be called when the shop selection changes + final Function(Shop)? onShopSelectionChange; + + /// Translations for the product page + final ProductPageTranslations? productPageTranslations; + + /// Shop selector style + final ShopSelectorStyle? shopSelectorStyle; + + /// ProductPage padding + final EdgeInsets? productPagePagePadding; + + /// AppBar builder + final AppBar Function(BuildContext)? productPageAppBarBuilder; + + /// BottomNavigationBarBuilder + final Widget? bottomNavigationBarBuilder; + + /// Function that will be called when the product detail is requested + final Function(BuildContext, Product, String)? onProductDetail; + + /// Function that will be called when the discount description is requested + final String Function(Product)? discountDescription; + + /// Function that will be called when there are no products + final Widget Function(BuildContext)? noContentBuilder; + + /// Function that will be called when there is an error + final Widget Function(BuildContext, Object?, StackTrace?)? errorBuilder; + + /// Function that will be called when the order button on + /// the shopping cart page is pressed + final Function(List)? onConfirmOrder; + + /// Shopping cart item builder + final Widget Function(BuildContext, Product, ShoppingCartConfig)? + productItemBuilder; + + /// Shopping cart confirm order button builder + final Widget Function( + BuildContext, + ShoppingCartConfig, + dynamic Function(List), + )? confirmOrderButtonBuilder; + + /// The height of the confirm order button + /// This will not set the height of the button itself + /// this is only used to create some extra space on the bottom + /// of the product list so the button doesn't overlap with the + /// last product + final double? confirmOrderButtonHeight; + + /// Shopping cart sum bottom sheet builder + final Widget Function(BuildContext, ShoppingCartConfig)? + sumBottomSheetBuilder; + + /// The height of the sum bottom sheet + /// This will not set the height of the sheet itself + /// this is only used to create some extra space on the bottom + /// of the product list so the sheet doesn't overlap with the + /// last product + final double? sumBottomSheetHeight; + + /// Function to override the title on the shopping cart screen + final Widget Function(BuildContext, String)? titleBuilder; + + /// Shopping cart translations + final ShoppingCartTranslations? shoppingCartTranslations; + + /// Shopping cart page padding + final EdgeInsets? shoppingCartPagePadding; + + /// Shopping cart bottom padding + final EdgeInsets? shoppingCartBottomPadding; + + /// Shopping cart app bar builder + final AppBar Function(BuildContext)? shoppingCartAppBarBuilder; + + // = _defaultPages, +// = const OrderDetailTranslations(), +// = _defaultAppBar, +// = _defaultNextButtonBuilder, +// = _defaultOrderSuccess, + + /// Function that gets called when the user navigates to the next + /// step of the order details + final dynamic Function( + int, + Map, + FlutterFormController controller, + )? onNextStep; + + /// Function that gets called when the Navigates + /// to the order confirmationp page + final dynamic Function( + String, + List, + Map>, + OrderDetailConfiguration, + )? onStepsCompleted; + + /// Function that gets called when pressing the complete order + /// button on the confirmation page + final Function(BuildContext, OrderDetailConfiguration)? + onCompleteOrderDetails; + + /// The order detail pages that are used in the order detail screen + final List Function(BuildContext)? pages; + + /// The translations for the order detail screen + final OrderDetailTranslations? orderDetailTranslations; + + /// The app bar for the order detail screen + final AppBar Function(BuildContext, String)? orderDetailAppBarBuilder; + + /// The builder for the next button on the order detail screen + final Widget Function( + int, + // ignore: avoid_positional_boolean_parameters + bool, + BuildContext, + OrderDetailConfiguration, + FlutterFormController, + )? orderDetailNextbuttonBuilder; + + /// The builder for the order success screen + final Widget Function( + BuildContext, + OrderDetailConfiguration, + Map>, + )? orderSuccessBuilder; +} diff --git a/packages/flutter_shopping/lib/src/flutter_shopping_navigator_userstory.dart b/packages/flutter_shopping/lib/src/flutter_shopping_navigator_userstory.dart new file mode 100644 index 0000000..aa32db5 --- /dev/null +++ b/packages/flutter_shopping/lib/src/flutter_shopping_navigator_userstory.dart @@ -0,0 +1,209 @@ +// ignore_for_file: public_member_api_docs + +import "package:flutter/material.dart"; +import "package:flutter_shopping/flutter_shopping.dart"; +import "package:flutter_shopping_local/flutter_shopping_local.dart"; + +class ShoppingNavigatorUserStory extends StatelessWidget { + const ShoppingNavigatorUserStory({ + this.shoppingConfiguration, + super.key, + }); + + final ShoppingConfiguration? shoppingConfiguration; + + @override + Widget build(BuildContext context) => ShoppingProductPage( + shoppingConfiguration: shoppingConfiguration ?? + ShoppingConfiguration( + shoppingService: LocalShoppingService(), + ), + ); +} + +class ShoppingProductPage extends StatelessWidget { + const ShoppingProductPage({ + required this.shoppingConfiguration, + super.key, + }); + final ShoppingConfiguration shoppingConfiguration; + + @override + Widget build(BuildContext context) { + var service = shoppingConfiguration.shoppingService; + return ProductPageScreen( + initialBuildShopId: shoppingConfiguration.initialShopid, + configuration: ProductPageConfiguration( + shoppingService: service, + initialShopId: shoppingConfiguration.initialShopid, + shoppingCartButtonBuilder: + shoppingConfiguration.shoppingCartButtonBuilder, + productBuilder: shoppingConfiguration.productBuilder, + onShopSelectionChange: shoppingConfiguration.onShopSelectionChange, + translations: shoppingConfiguration.productPageTranslations, + shopSelectorStyle: shoppingConfiguration.shopSelectorStyle, + pagePadding: shoppingConfiguration.productPagePagePadding, + appBar: shoppingConfiguration.productPageAppBarBuilder, + bottomNavigationBar: shoppingConfiguration.bottomNavigationBarBuilder, + onProductDetail: shoppingConfiguration.onProductDetail, + discountDescription: shoppingConfiguration.discountDescription, + noContentBuilder: shoppingConfiguration.noContentBuilder, + errorBuilder: shoppingConfiguration.errorBuilder, + shops: () async { + if (shoppingConfiguration.onGetShops != null) { + return shoppingConfiguration.onGetShops!(); + } else { + return service.shopService.getShops(); + } + }, + getProducts: (shop) async { + if (shoppingConfiguration.onGetProducts != null) { + return shoppingConfiguration.onGetProducts!(shop.id); + } else { + return service.productService.getProducts(shop.id); + } + }, + onAddToCart: (product) { + if (shoppingConfiguration.onAddToCart != null) { + shoppingConfiguration.onAddToCart!(product); + return; + } else { + return service.shoppingCartService.addProduct(product); + } + }, + onNavigateToShoppingCart: () async { + if (shoppingConfiguration.onNavigateToShoppingCart != null) { + return shoppingConfiguration.onNavigateToShoppingCart!(); + } else { + return Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ShoppingCart( + shoppingConfiguration: shoppingConfiguration, + ), + ), + ); + } + }, + getProductsInShoppingCart: () { + if (shoppingConfiguration.getProductsInShoppingCart != null) { + return shoppingConfiguration.getProductsInShoppingCart!(); + } else { + return service.shoppingCartService.countProducts(); + } + }, + ), + ); + } +} + +class ShoppingCart extends StatelessWidget { + const ShoppingCart({ + required this.shoppingConfiguration, + super.key, + }); + + final ShoppingConfiguration shoppingConfiguration; + + @override + Widget build(BuildContext context) { + var service = shoppingConfiguration.shoppingService.shoppingCartService; + return ShoppingCartScreen( + configuration: ShoppingCartConfig( + service: service, + productItemBuilder: shoppingConfiguration.productItemBuilder, + confirmOrderButtonBuilder: + shoppingConfiguration.confirmOrderButtonBuilder, + confirmOrderButtonHeight: + shoppingConfiguration.confirmOrderButtonHeight, + sumBottomSheetBuilder: shoppingConfiguration.sumBottomSheetBuilder, + sumBottomSheetHeight: shoppingConfiguration.sumBottomSheetHeight, + titleBuilder: shoppingConfiguration.titleBuilder, + translations: shoppingConfiguration.shoppingCartTranslations, + pagePadding: shoppingConfiguration.shoppingCartPagePadding, + bottomPadding: shoppingConfiguration.shoppingCartBottomPadding, + appBar: shoppingConfiguration.shoppingCartAppBarBuilder, + onConfirmOrder: (products) async { + if (shoppingConfiguration.onConfirmOrder != null) { + return shoppingConfiguration.onConfirmOrder!(products); + } else { + return Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => ShoppingOrderDetails( + shoppingConfiguration: shoppingConfiguration, + ), + ), + ); + } + }, + ), + ); + } +} + +class ShoppingOrderDetails extends StatelessWidget { + const ShoppingOrderDetails({ + required this.shoppingConfiguration, + super.key, + }); + + final ShoppingConfiguration shoppingConfiguration; + + @override + Widget build(BuildContext context) => OrderDetailScreen( + configuration: OrderDetailConfiguration( + shoppingService: shoppingConfiguration.shoppingService, + pages: shoppingConfiguration.pages, + translations: shoppingConfiguration.orderDetailTranslations, + appBar: shoppingConfiguration.orderDetailAppBarBuilder, + nextbuttonBuilder: shoppingConfiguration.orderDetailNextbuttonBuilder, + orderSuccessBuilder: shoppingConfiguration.orderSuccessBuilder, + onNextStep: (currentStep, data, controller) async { + if (shoppingConfiguration.onNextStep != null) { + return shoppingConfiguration.onNextStep!( + currentStep, + data, + controller, + ); + } else { + await controller.autoNextStep(); + } + }, + onStepsCompleted: (shopId, products, data, configuration) async { + if (shoppingConfiguration.onStepsCompleted != null) { + return shoppingConfiguration.onStepsCompleted!( + shopId, + products, + data, + configuration, + ); + } else { + return Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (context) => DefaultOrderSucces( + configuration: configuration, + orderDetails: data, + ), + ), + ); + } + }, + onCompleteOrderDetails: (context, configuration) async { + if (shoppingConfiguration.onCompleteOrderDetails != null) { + return shoppingConfiguration.onCompleteOrderDetails!( + context, + configuration, + ); + } else { + shoppingConfiguration.shoppingService.shoppingCartService.clear(); + return Navigator.of(context).pushReplacement( + MaterialPageRoute( + builder: (context) => ShoppingProductPage( + shoppingConfiguration: shoppingConfiguration, + ), + ), + ); + } + }, + ), + ); +} diff --git a/packages/flutter_shopping/lib/src/go_router.dart b/packages/flutter_shopping/lib/src/go_router.dart deleted file mode 100644 index cce7de5..0000000 --- a/packages/flutter_shopping/lib/src/go_router.dart +++ /dev/null @@ -1,28 +0,0 @@ -import "package:flutter/material.dart"; -import "package:go_router/go_router.dart"; - -/// Builder with a fade transition for when navigating to a new screen. -CustomTransitionPage buildScreenWithFadeTransition({ - required BuildContext context, - required GoRouterState state, - required Widget child, -}) => - CustomTransitionPage( - key: state.pageKey, - child: child, - transitionsBuilder: (context, animation, secondaryAnimation, child) => - FadeTransition(opacity: animation, child: child), - ); - -/// Builder without a transition for when navigating to a new screen. -CustomTransitionPage buildScreenWithoutTransition({ - required BuildContext context, - required GoRouterState state, - required Widget child, -}) => - CustomTransitionPage( - key: state.pageKey, - child: child, - transitionsBuilder: (context, animation, secondaryAnimation, child) => - child, - ); diff --git a/packages/flutter_shopping/lib/src/models/product.dart b/packages/flutter_shopping/lib/src/models/product.dart deleted file mode 100644 index 680b5f5..0000000 --- a/packages/flutter_shopping/lib/src/models/product.dart +++ /dev/null @@ -1,43 +0,0 @@ -/// The product class contains all the information that a product can have. -/// This class is used in the shopping cart and the product page. -class Product { - /// Creates a product. - Product({ - required this.id, - required this.name, - required this.imageUrl, - required this.category, - required this.price, - required this.description, - this.hasDiscount = false, - this.discountPrice, - this.quantity = 1, - }); - - /// The unique identifier for the product. - final String id; - - /// The name of the product. - final String name; - - /// The image URL of the product. - final String imageUrl; - - /// The category of the product. - final String category; - - /// The price of the product. - final double price; - - /// Whether the product has a discount or not. - final bool hasDiscount; - - /// The discounted price of the product. Only used if [hasDiscount] is true. - final double? discountPrice; - - /// Quantity for the product. - int quantity; - - /// The description of the product. - final String description; -} diff --git a/packages/flutter_shopping/lib/src/routes.dart b/packages/flutter_shopping/lib/src/routes.dart deleted file mode 100644 index e3730ca..0000000 --- a/packages/flutter_shopping/lib/src/routes.dart +++ /dev/null @@ -1,35 +0,0 @@ -/// All the name routes used in the user-story. -mixin FlutterShoppingNameRoutes { - /// The shop name route. - static const String shop = "shop"; - - /// The shopping cart name route. - static const String shoppingCart = "shoppingcart"; - - /// The order details name route. - static const String orderDetails = "orderdetails"; - - /// The order success name route. - static const String orderSuccess = "ordersuccess"; - - /// The order failed name route. - static const String orderFailed = "orderfailed"; -} - -/// All the path routes used in the user-story. -mixin FlutterShoppingPathRoutes { - /// The shop page route. - static const String shop = "/shop"; - - /// The shopping cart page route. - static const String shoppingCart = "/shopping-cart"; - - /// The order details page route. - static const String orderDetails = "/order-details"; - - /// The order success page route. - static const String orderSuccess = "/order-success"; - - /// The order failed page route. - static const String orderFailed = "/order-failed"; -} diff --git a/packages/flutter_shopping/lib/src/user_stores/flutter_shopping_userstory_go_router.dart b/packages/flutter_shopping/lib/src/user_stores/flutter_shopping_userstory_go_router.dart deleted file mode 100644 index 1e8b165..0000000 --- a/packages/flutter_shopping/lib/src/user_stores/flutter_shopping_userstory_go_router.dart +++ /dev/null @@ -1,52 +0,0 @@ -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:flutter_shopping/src/widgets/default_order_failed_widget.dart"; -import "package:flutter_shopping/src/widgets/default_order_succes_widget.dart"; -import "package:go_router/go_router.dart"; - -/// All the routes for the shopping story. -List getShoppingStoryRoutes({ - required FlutterShoppingConfiguration configuration, -}) => - [ - GoRoute( - name: FlutterShoppingNameRoutes.shop, - path: FlutterShoppingPathRoutes.shop, - builder: (context, state) => configuration.shopBuilder( - context, - state.uri.queryParameters["id"], - state.uri.queryParameters["street"], - ), - ), - GoRoute( - name: FlutterShoppingNameRoutes.shoppingCart, - path: FlutterShoppingPathRoutes.shoppingCart, - builder: (context, state) => configuration.shoppingCartBuilder(context), - ), - GoRoute( - name: FlutterShoppingNameRoutes.orderDetails, - path: FlutterShoppingPathRoutes.orderDetails, - builder: (context, state) => configuration.orderDetailsBuilder != null - ? configuration.orderDetailsBuilder!(context) - : OrderDetailScreen( - configuration: OrderDetailConfiguration( - onCompleted: (result) { - context.go(FlutterShoppingPathRoutes.orderSuccess); - }, - ), - ), - ), - GoRoute( - name: FlutterShoppingNameRoutes.orderSuccess, - path: FlutterShoppingPathRoutes.orderSuccess, - builder: (context, state) => configuration.orderSuccessBuilder != null - ? configuration.orderSuccessBuilder!(context) - : DefaultOrderSucces(configuration: configuration), - ), - GoRoute( - name: FlutterShoppingNameRoutes.orderFailed, - path: FlutterShoppingPathRoutes.orderFailed, - builder: (context, state) => configuration.orderFailedBuilder != null - ? configuration.orderFailedBuilder!(context) - : DefaultOrderFailed(configuration: configuration), - ), - ]; diff --git a/packages/flutter_shopping/lib/src/user_stores/flutter_shopping_userstory_navigation.dart b/packages/flutter_shopping/lib/src/user_stores/flutter_shopping_userstory_navigation.dart deleted file mode 100644 index 0926a0f..0000000 --- a/packages/flutter_shopping/lib/src/user_stores/flutter_shopping_userstory_navigation.dart +++ /dev/null @@ -1,52 +0,0 @@ -import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; -import "package:go_router/go_router.dart"; - -/// Default on complete order details function. -/// This function will navigate to the order success or order failed page. -/// -/// You can create your own implementation if you decide to use a different -/// approach. -Future onCompleteOrderDetails( - BuildContext context, - FlutterShoppingConfiguration configuration, - OrderResult result, -) async { - var go = context.go; - var succesful = true; - - if (configuration.onCompleteOrderDetails != null) { - var executionResult = - await configuration.onCompleteOrderDetails?.call(context, result); - - if (executionResult == null || !executionResult) { - succesful = false; - } - } - - if (succesful) { - go(FlutterShoppingPathRoutes.orderSuccess); - } else { - go(FlutterShoppingPathRoutes.orderFailed); - } -} - -/// Default on complete shopping cart function. -/// -/// You can create your own implementation if you decide to use a different -/// approach. -Future onCompleteShoppingCart( - BuildContext context, -) async { - await context.push(FlutterShoppingPathRoutes.orderDetails); -} - -/// Default on complete product page function. -/// -/// You can create your own implementation if you decide to use a different -/// approach. -Future onCompleteProductPage( - BuildContext context, -) async { - await context.push(FlutterShoppingPathRoutes.shoppingCart); -} diff --git a/packages/flutter_shopping/pubspec.yaml b/packages/flutter_shopping/pubspec.yaml index ffbd981..309d6c7 100644 --- a/packages/flutter_shopping/pubspec.yaml +++ b/packages/flutter_shopping/pubspec.yaml @@ -1,10 +1,10 @@ name: flutter_shopping description: "A new Flutter project." -publish_to: 'none' +publish_to: "none" version: 2.0.0 environment: - sdk: '>=3.3.4 <4.0.0' + sdk: ">=3.3.4 <4.0.0" dependencies: flutter: @@ -25,6 +25,16 @@ dependencies: url: https://github.com/Iconica-Development/flutter_shopping ref: 2.0.0 path: packages/flutter_order_details + flutter_shopping_interface: + git: + url: https://github.com/Iconica-Development/flutter_shopping + ref: 2.0.0 + path: packages/flutter_shopping_interface + flutter_shopping_local: + git: + url: https://github.com/Iconica-Development/flutter_shopping + ref: 2.0.0 + path: packages/flutter_shopping_local dev_dependencies: flutter_test: @@ -35,4 +45,3 @@ dev_dependencies: ref: 7.0.0 flutter: - diff --git a/packages/flutter_shopping_cart/lib/src/config/shopping_cart_config.dart b/packages/flutter_shopping_cart/lib/src/config/shopping_cart_config.dart index f3d3cac..3af3240 100644 --- a/packages/flutter_shopping_cart/lib/src/config/shopping_cart_config.dart +++ b/packages/flutter_shopping_cart/lib/src/config/shopping_cart_config.dart @@ -11,17 +11,27 @@ class ShoppingCartConfig { ShoppingCartConfig({ required this.service, required this.onConfirmOrder, - this.productItemBuilder = _defaultProductItemBuilder, - this.confirmOrderButtonBuilder = _defaultConfirmOrderButton, - this.confirmOrderButtonHeight = 100, - this.sumBottomSheetBuilder = _defaultSumBottomSheetBuilder, - this.sumBottomSheetHeight = 100, + this.productItemBuilder, + this.confirmOrderButtonBuilder, + this.confirmOrderButtonHeight, + this.sumBottomSheetBuilder, + this.sumBottomSheetHeight, this.titleBuilder, - this.translations = const ShoppingCartTranslations(), - this.pagePadding = const EdgeInsets.symmetric(horizontal: 32), - this.bottomPadding = const EdgeInsets.fromLTRB(44, 0, 44, 32), - this.appBar = _defaultAppBar, - }); + this.translations, + this.pagePadding, + this.bottomPadding, + this.appBar, + }) { + productItemBuilder ??= _defaultProductItemBuilder; + confirmOrderButtonBuilder ??= _defaultConfirmOrderButton; + sumBottomSheetBuilder ??= _defaultSumBottomSheetBuilder; + appBar ??= _defaultAppBar; + translations ??= const ShoppingCartTranslations(); + pagePadding ??= const EdgeInsets.symmetric(horizontal: 32); + bottomPadding ??= const EdgeInsets.fromLTRB(44, 0, 44, 32); + confirmOrderButtonHeight ??= 100; + sumBottomSheetHeight ??= 100; + } /// Product service. The product service is used to manage the products in the /// shopping cart. @@ -29,26 +39,26 @@ class ShoppingCartConfig { /// Product item builder. This builder is used to build the product item /// that will be displayed in the shopping cart. - final Widget Function( + Widget Function( BuildContext context, Product product, ShoppingCartConfig configuration, - ) productItemBuilder; + )? productItemBuilder; /// Confirm order button builder. This builder is used to build the confirm /// order button that will be displayed in the shopping cart. /// If you override this builder, you cannot use the [onConfirmOrder] callback - final Widget Function( + Widget Function( BuildContext context, ShoppingCartConfig configuration, Function(List products) onConfirmOrder, - ) confirmOrderButtonBuilder; + )? confirmOrderButtonBuilder; /// Confirm order button height. The height of the confirm order button. /// This height is used to calculate the bottom padding of the shopping cart. /// If you override the confirm order button builder, you must provide a /// height. - final double confirmOrderButtonHeight; + double? confirmOrderButtonHeight; /// Confirm order callback. This callback is called when the confirm order /// button is pressed. The callback will not be called if you override the @@ -58,22 +68,22 @@ class ShoppingCartConfig { /// Sum bottom sheet builder. This builder is used to build the sum bottom /// sheet that will be displayed in the shopping cart. The sum bottom sheet /// can be used to display the total sum of the products in the shopping cart. - final Widget Function(BuildContext context, ShoppingCartConfig configuration) + Widget Function(BuildContext context, ShoppingCartConfig configuration)? sumBottomSheetBuilder; /// Sum bottom sheet height. The height of the sum bottom sheet. /// This height is used to calculate the bottom padding of the shopping cart. /// If you override the sum bottom sheet builder, you must provide a height. - final double sumBottomSheetHeight; + double? sumBottomSheetHeight; /// Padding around the shopping cart. The padding is used to create space /// around the shopping cart. - final EdgeInsets pagePadding; + EdgeInsets? pagePadding; /// Bottom padding of the shopping cart. The bottom padding is used to create /// a padding around the bottom sheet. This padding is ignored when the /// [sumBottomSheetBuilder] is overridden. - final EdgeInsets bottomPadding; + EdgeInsets? bottomPadding; /// Title builder. This builder is used to /// build the title of the shopping cart. @@ -83,10 +93,10 @@ class ShoppingCartConfig { )? titleBuilder; /// Shopping cart translations. The translations for the shopping cart. - final ShoppingCartTranslations translations; + ShoppingCartTranslations? translations; /// Appbar for the shopping cart screen. - final AppBar Function(BuildContext context) appBar; + AppBar Function(BuildContext context)? appBar; } Widget _defaultProductItemBuilder( @@ -217,11 +227,11 @@ Widget _defaultSumBottomSheetBuilder( ); return Padding( - padding: configuration.bottomPadding, + padding: configuration.bottomPadding!, child: Row( children: [ Text( - configuration.translations.sum, + configuration.translations!.sum, style: theme.textTheme.titleMedium, ), const Spacer(), @@ -261,7 +271,7 @@ Widget _defaultConfirmOrderButton( vertical: 12, ), child: Text( - configuration.translations.placeOrder, + configuration.translations!.placeOrder, style: theme.textTheme.displayLarge, ), ), diff --git a/packages/flutter_shopping_cart/lib/src/widgets/product_item_popup.dart b/packages/flutter_shopping_cart/lib/src/widgets/product_item_popup.dart index ebe32c0..8b55643 100644 --- a/packages/flutter_shopping_cart/lib/src/widgets/product_item_popup.dart +++ b/packages/flutter_shopping_cart/lib/src/widgets/product_item_popup.dart @@ -50,7 +50,7 @@ class ProductItemPopup extends StatelessWidget { vertical: 8.0, ), child: Text( - configuration.translations.close, + configuration.translations!.close, style: theme.textTheme.displayLarge, ), ), diff --git a/packages/flutter_shopping_cart/lib/src/widgets/shopping_cart_screen.dart b/packages/flutter_shopping_cart/lib/src/widgets/shopping_cart_screen.dart index 4e8db4d..09db475 100644 --- a/packages/flutter_shopping_cart/lib/src/widgets/shopping_cart_screen.dart +++ b/packages/flutter_shopping_cart/lib/src/widgets/shopping_cart_screen.dart @@ -17,20 +17,20 @@ class ShoppingCartScreen extends StatelessWidget { var theme = Theme.of(context); return Scaffold( - appBar: configuration.appBar.call(context), + appBar: configuration.appBar?.call(context), body: SafeArea( child: Stack( fit: StackFit.expand, children: [ Padding( - padding: configuration.pagePadding, + padding: configuration.pagePadding!, child: SingleChildScrollView( child: Column( children: [ if (configuration.titleBuilder != null) ...{ configuration.titleBuilder!( context, - configuration.translations.cartTitle, + configuration.translations!.cartTitle, ), } else ...{ Padding( @@ -40,7 +40,7 @@ class ShoppingCartScreen extends StatelessWidget { child: Row( children: [ Text( - configuration.translations.cartTitle, + configuration.translations!.cartTitle, style: theme.textTheme.titleLarge, textAlign: TextAlign.start, ), @@ -53,7 +53,7 @@ class ShoppingCartScreen extends StatelessWidget { builder: (context, _) => Column( children: [ for (var product in configuration.service.products) - configuration.productItemBuilder( + configuration.productItemBuilder!( context, product, configuration, @@ -63,8 +63,8 @@ class ShoppingCartScreen extends StatelessWidget { // the bottom to make sure the last // product(s) are not hidden by the bottom sheet. SizedBox( - height: configuration.confirmOrderButtonHeight + - configuration.sumBottomSheetHeight, + height: configuration.confirmOrderButtonHeight! + + configuration.sumBottomSheetHeight!, ), ], ), @@ -100,11 +100,11 @@ class _BottomSheet extends StatelessWidget { ListenableBuilder( listenable: configuration.service, builder: (BuildContext context, Widget? child) => - configuration.sumBottomSheetBuilder(context, configuration), + configuration.sumBottomSheetBuilder!(context, configuration), ), ListenableBuilder( listenable: configuration.service, - builder: (context, _) => configuration.confirmOrderButtonBuilder( + builder: (context, _) => configuration.confirmOrderButtonBuilder!( context, configuration, configuration.onConfirmOrder, diff --git a/packages/flutter_shopping_cart/pubspec.yaml b/packages/flutter_shopping_cart/pubspec.yaml index a96628c..d8860e9 100644 --- a/packages/flutter_shopping_cart/pubspec.yaml +++ b/packages/flutter_shopping_cart/pubspec.yaml @@ -15,9 +15,6 @@ dependencies: url: https://github.com/Iconica-Development/flutter_shopping path: packages/flutter_shopping_interface ref: 2.0.0 -dependency_overrides: - flutter_shopping_interface: - path: ../flutter_shopping_interface dev_dependencies: flutter_test: