From 2426416c4254a784a13790170b5772e64ace605b Mon Sep 17 00:00:00 2001 From: mike doornenbal Date: Wed, 3 Jul 2024 15:40:52 +0200 Subject: [PATCH] feat: add interface to flutter_order_details --- .../lib/flutter_order_details.dart | 7 +- .../order_detail_configuration.dart | 56 +++++++++++++--- .../order_detail_title_style.dart | 14 ---- ...on.dart => order_detail_translations.dart} | 4 +- .../lib/src/models/order_result.dart | 14 ---- .../{widgets => }/order_detail_screen.dart | 26 +++++--- .../lib/src/widgets/order_succes.dart} | 59 +++++++++++------ packages/flutter_order_details/pubspec.yaml | 15 ++++- .../widgets/default_order_failed_widget.dart | 65 ------------------- .../lib/src/service/order_service.dart | 4 +- .../lib/src/service/product_service.dart | 3 + .../lib/service/local_order_service.dart | 10 +-- .../lib/service/local_product_service.dart | 3 + .../lib/service/service.dart | 4 ++ 14 files changed, 139 insertions(+), 145 deletions(-) delete mode 100644 packages/flutter_order_details/lib/src/configuration/order_detail_title_style.dart rename packages/flutter_order_details/lib/src/configuration/{order_detail_localization.dart => order_detail_translations.dart} (86%) delete mode 100644 packages/flutter_order_details/lib/src/models/order_result.dart rename packages/flutter_order_details/lib/src/{widgets => }/order_detail_screen.dart (58%) rename packages/{flutter_shopping/lib/src/widgets/default_order_succes_widget.dart => flutter_order_details/lib/src/widgets/order_succes.dart} (74%) delete mode 100644 packages/flutter_shopping/lib/src/widgets/default_order_failed_widget.dart diff --git a/packages/flutter_order_details/lib/flutter_order_details.dart b/packages/flutter_order_details/lib/flutter_order_details.dart index 9bc1b8b..3e879d7 100644 --- a/packages/flutter_order_details/lib/flutter_order_details.dart +++ b/packages/flutter_order_details/lib/flutter_order_details.dart @@ -2,7 +2,6 @@ library flutter_order_details; export "src/configuration/order_detail_configuration.dart"; -export "src/configuration/order_detail_localization.dart"; -export "src/configuration/order_detail_title_style.dart"; -export "src/models/order_result.dart"; -export "src/widgets/order_detail_screen.dart"; +export "src/configuration/order_detail_translations.dart"; +export "src/order_detail_screen.dart"; +export "src/widgets/order_succes.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 ab0d019..6e98263 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 @@ -4,54 +4,82 @@ 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"; /// Configuration for the order detail screen. class OrderDetailConfiguration { /// Constructor for the order detail configuration. OrderDetailConfiguration({ - required this.onCompleted, + required this.shoppingService, + required this.onNextStep, + required this.onStepsCompleted, + required this.onCompleteOrderDetails, this.pages = _defaultPages, - this.localization = const OrderDetailLocalization(), + this.translations = const OrderDetailTranslations(), this.appBar = _defaultAppBar, this.nextbuttonBuilder = _defaultNextButtonBuilder, + this.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; /// 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. - final Function(dynamic value) onCompleted; + final Function( + String shopId, + List products, + Map> value, + OrderDetailConfiguration configuration, + ) onStepsCompleted; + + /// Callback function that is called when the user has completed a step. + final Function(int currentStep, Map data) onNextStep; /// Localization for the order detail screen. - final OrderDetailLocalization localization; + final OrderDetailTranslations translations; /// Optional app bar that you can pass to the order detail screen. final AppBar Function( BuildContext context, - OrderDetailLocalization localizations, + String title, ) appBar; /// Optional next button builder that you can pass to the order detail screen. final Widget Function( - int a, + int currentStep, // ignore: avoid_positional_boolean_parameters - bool b, + bool checkingPages, BuildContext context, OrderDetailConfiguration configuration, FlutterFormController controller, ) nextbuttonBuilder; + + /// Optional builder for the order success screen. + final Widget Function( + BuildContext context, + OrderDetailConfiguration, + Map> orderDetails, + ) orderSuccessBuilder; + + /// This function is called after the order has been completed and + /// the success screen has been shown. + final Function(BuildContext context, OrderDetailConfiguration configuration) + onCompleteOrderDetails; } AppBar _defaultAppBar( BuildContext context, - OrderDetailLocalization localizations, + String title, ) { var theme = Theme.of(context); return AppBar( title: Text( - localizations.orderDetailsTitle, + title, style: theme.textTheme.headlineLarge, ), ); @@ -535,3 +563,13 @@ List _defaultPages(BuildContext context) { ), ]; } + +Widget _defaultOrderSuccess( + BuildContext context, + OrderDetailConfiguration configuration, + Map> orderDetails, +) => + DefaultOrderSucces( + configuration: configuration, + orderDetails: orderDetails, + ); diff --git a/packages/flutter_order_details/lib/src/configuration/order_detail_title_style.dart b/packages/flutter_order_details/lib/src/configuration/order_detail_title_style.dart deleted file mode 100644 index 8cc7896..0000000 --- a/packages/flutter_order_details/lib/src/configuration/order_detail_title_style.dart +++ /dev/null @@ -1,14 +0,0 @@ -/// An enum to define the style of the title in the order detail. -enum OrderDetailTitleStyle { - /// The title displayed as a textlabel above the field. - text, - - /// The title displayed as a label inside the field. - /// NOTE: Not all fields support this. Such as, but not limited to: - /// - Dropdown - /// - Time Picker - label, - - /// Does not display any form of title. - none, -} diff --git a/packages/flutter_order_details/lib/src/configuration/order_detail_localization.dart b/packages/flutter_order_details/lib/src/configuration/order_detail_translations.dart similarity index 86% rename from packages/flutter_order_details/lib/src/configuration/order_detail_localization.dart rename to packages/flutter_order_details/lib/src/configuration/order_detail_translations.dart index df8c48c..55a306a 100644 --- a/packages/flutter_order_details/lib/src/configuration/order_detail_localization.dart +++ b/packages/flutter_order_details/lib/src/configuration/order_detail_translations.dart @@ -1,7 +1,7 @@ /// Localizations for the order detail page. -class OrderDetailLocalization { +class OrderDetailTranslations { /// Constructor for the order detail localization. - const OrderDetailLocalization({ + const OrderDetailTranslations({ this.nextButton = "Order", this.completeButton = "Complete", this.orderDetailsTitle = "Information", diff --git a/packages/flutter_order_details/lib/src/models/order_result.dart b/packages/flutter_order_details/lib/src/models/order_result.dart deleted file mode 100644 index 20a4c00..0000000 --- a/packages/flutter_order_details/lib/src/models/order_result.dart +++ /dev/null @@ -1,14 +0,0 @@ -/// OrderResult model. -/// When an user completes the field and presses the complete button, -/// the `onComplete` method returns an instance of this class that contains -/// all the developer-specified `outputKey`s and the value that was provided -/// by the user. -class OrderResult { - /// Constructor of the order result class. - OrderResult({ - required this.order, - }); - - /// Map of `outputKey`s and their respected values. - final Map order; -} diff --git a/packages/flutter_order_details/lib/src/widgets/order_detail_screen.dart b/packages/flutter_order_details/lib/src/order_detail_screen.dart similarity index 58% rename from packages/flutter_order_details/lib/src/widgets/order_detail_screen.dart rename to packages/flutter_order_details/lib/src/order_detail_screen.dart index d24cd2a..5914c44 100644 --- a/packages/flutter_order_details/lib/src/widgets/order_detail_screen.dart +++ b/packages/flutter_order_details/lib/src/order_detail_screen.dart @@ -22,23 +22,33 @@ class _OrderDetailScreenState extends State { Widget build(BuildContext context) { var controller = FlutterFormController(); return Scaffold( - appBar: widget.configuration.appBar - .call(context, widget.configuration.localization), + appBar: widget.configuration.appBar.call( + context, + widget.configuration.translations.orderDetailsTitle, + ), body: FlutterForm( formController: controller, options: FlutterFormOptions( - nextButton: (a, b) => widget.configuration.nextbuttonBuilder( - a, - b, + nextButton: (pageNumber, checkingPages) => + widget.configuration.nextbuttonBuilder( + pageNumber, + checkingPages, context, widget.configuration, controller, ), pages: widget.configuration.pages.call(context), - onFinished: (data) { - widget.configuration.onCompleted.call(data); + onFinished: (data) async { + widget.configuration.onStepsCompleted.call( + widget.configuration.shoppingService.shopService.selectedShop!.id, + widget.configuration.shoppingService.shoppingCartService.products, + data, + widget.configuration, + ); + }, + onNext: (step, data) { + widget.configuration.onNextStep.call(step, data); }, - onNext: (step, data) {}, ), ), ); diff --git a/packages/flutter_shopping/lib/src/widgets/default_order_succes_widget.dart b/packages/flutter_order_details/lib/src/widgets/order_succes.dart similarity index 74% rename from packages/flutter_shopping/lib/src/widgets/default_order_succes_widget.dart rename to packages/flutter_order_details/lib/src/widgets/order_succes.dart index d0b3cb2..6abfd00 100644 --- a/packages/flutter_shopping/lib/src/widgets/default_order_succes_widget.dart +++ b/packages/flutter_order_details/lib/src/widgets/order_succes.dart @@ -1,21 +1,31 @@ import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; +import "package:flutter_order_details/flutter_order_details.dart"; +import "package:flutter_shopping_interface/flutter_shopping_interface.dart"; /// Default order success widget. class DefaultOrderSucces extends StatelessWidget { /// Constructor for the DefaultOrderSucces. const DefaultOrderSucces({ required this.configuration, + required this.orderDetails, super.key, }); - /// Configuration for the user-story. - final FlutterShoppingConfiguration configuration; + /// Configuration for the user-stor + final OrderDetailConfiguration configuration; + + /// Order details. + final Map> orderDetails; @override Widget build(BuildContext context) { var theme = Theme.of(context); + var discountedProducts = configuration + .shoppingService.productService.products + .where((product) => product.hasDiscount) + .toList(); + return Scaffold( appBar: AppBar( title: Text( @@ -42,16 +52,19 @@ class DefaultOrderSucces extends StatelessWidget { height: 4, ), Text( - "Thank you Peter for your order!", + "Thank you ${orderDetails[0]!['name']} for your order!", style: theme.textTheme.bodyMedium, ), const SizedBox( height: 16, ), Text( - "The order was placed at Bakkerij de Goudkorst." + "The order was placed" + // ignore: lines_longer_than_80_chars + " at ${configuration.shoppingService.shopService.selectedShop?.name}." " You can pick this" - " up on Monday, February 7 at 1:00 PM.", + " up ${orderDetails[1]!['date']} at" + " ${orderDetails[1]!['multipleChoice']}.", style: theme.textTheme.bodyMedium, textAlign: TextAlign.center, ), @@ -84,9 +97,19 @@ class DefaultOrderSucces extends StatelessWidget { scrollDirection: Axis.horizontal, children: [ const SizedBox(width: 32), - _discount(context), - const SizedBox(width: 8), - _discount(context), + // _discount(context), + // const SizedBox(width: 8), + // _discount(context), + for (var product in discountedProducts) ...[ + _discount( + context, + product, + configuration.shoppingService.shopService.selectedShop!, + ), + const SizedBox( + width: 8, + ), + ], const SizedBox(width: 32), ], ), @@ -98,7 +121,8 @@ class DefaultOrderSucces extends StatelessWidget { width: double.infinity, child: FilledButton( onPressed: () async { - configuration.onCompleteUserStory.call(context); + configuration.onCompleteOrderDetails + .call(context, configuration); }, style: theme.filledButtonTheme.style?.copyWith( backgroundColor: WidgetStateProperty.all( @@ -125,7 +149,7 @@ class DefaultOrderSucces extends StatelessWidget { } } -Widget _discount(BuildContext context) { +Widget _discount(BuildContext context, Product product, Shop shop) { var theme = Theme.of(context); return Container( decoration: BoxDecoration( @@ -139,14 +163,11 @@ Widget _discount(BuildContext context) { child: Stack( children: [ ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(10), - topRight: Radius.circular(10), - bottomLeft: Radius.circular(10), - bottomRight: Radius.circular(10), + borderRadius: BorderRadius.circular( + 10, ), child: Image.network( - "https://picsum.photos/150", + product.imageUrl, width: double.infinity, height: double.infinity, fit: BoxFit.cover, @@ -166,7 +187,7 @@ Widget _discount(BuildContext context) { child: Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( - "Butcher Puurvlees", + shop.name, style: theme.textTheme.headlineSmall?.copyWith( color: Colors.white, ), @@ -189,7 +210,7 @@ Widget _discount(BuildContext context) { child: Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( - "Chicken legs, now for 4,99", + "${product.name}, now for ${product.price.toStringAsFixed(2)}", style: theme.textTheme.bodyMedium, ), ), diff --git a/packages/flutter_order_details/pubspec.yaml b/packages/flutter_order_details/pubspec.yaml index 20721cb..9b0e18b 100644 --- a/packages/flutter_order_details/pubspec.yaml +++ b/packages/flutter_order_details/pubspec.yaml @@ -1,10 +1,10 @@ name: flutter_order_details description: "A Flutter module for order details." version: 2.0.0 -publish_to: 'none' +publish_to: "none" environment: - sdk: '>=3.3.0 <4.0.0' + sdk: ">=3.3.0 <4.0.0" dependencies: flutter: @@ -17,6 +17,16 @@ dependencies: git: url: https://github.com/Iconica-Development/flutter_form_wizard ref: 6.5.0 + flutter_shopping_interface: + git: + url: https://github.com/Iconica-Development/flutter_shopping + path: packages/flutter_shopping_interface + ref: 2.0.0 + collection: ^1.18.0 + +dependency_overrides: + flutter_shopping_interface: + path: ../flutter_shopping_interface dev_dependencies: flutter_test: @@ -27,4 +37,3 @@ dev_dependencies: ref: 7.0.0 flutter: - diff --git a/packages/flutter_shopping/lib/src/widgets/default_order_failed_widget.dart b/packages/flutter_shopping/lib/src/widgets/default_order_failed_widget.dart deleted file mode 100644 index 24debae..0000000 --- a/packages/flutter_shopping/lib/src/widgets/default_order_failed_widget.dart +++ /dev/null @@ -1,65 +0,0 @@ -import "package:flutter/material.dart"; -import "package:flutter_shopping/flutter_shopping.dart"; - -/// Default order failed widget. -class DefaultOrderFailed extends StatelessWidget { - /// Constructor for the DefaultOrderFailed. - const DefaultOrderFailed({ - required this.configuration, - super.key, - }); - - /// Configuration for the user-story. - final FlutterShoppingConfiguration configuration; - - @override - Widget build(BuildContext context) { - var theme = Theme.of(context); - - var finishOrderButton = FilledButton( - onPressed: () => configuration.onCompleteUserStory(context), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 32.0, - vertical: 8.0, - ), - child: Text("Go back".toUpperCase()), - ), - ); - - var content = Column( - children: [ - const Spacer(), - const Icon( - Icons.error, - size: 100, - color: Colors.red, - ), - const SizedBox(height: 16), - Text( - "Uh oh.", - style: theme.textTheme.titleLarge, - ), - const SizedBox(height: 32), - Text( - "It seems that something went wrong.", - style: theme.textTheme.bodyMedium, - ), - Text( - "Please try again later.", - style: theme.textTheme.bodyMedium, - ), - const Spacer(), - finishOrderButton, - ], - ); - - return Scaffold( - body: SafeArea( - child: Center( - child: content, - ), - ), - ); - } -} diff --git a/packages/flutter_shopping_interface/lib/src/service/order_service.dart b/packages/flutter_shopping_interface/lib/src/service/order_service.dart index b3a1dab..2904d0d 100644 --- a/packages/flutter_shopping_interface/lib/src/service/order_service.dart +++ b/packages/flutter_shopping_interface/lib/src/service/order_service.dart @@ -5,8 +5,8 @@ import "package:flutter_shopping_interface/src/model/product.dart"; abstract class OrderService { /// Create an order Future createOrder( - int shopId, + String shopId, List products, - Map clientInformation, + Map> clientInformation, ); } diff --git a/packages/flutter_shopping_interface/lib/src/service/product_service.dart b/packages/flutter_shopping_interface/lib/src/service/product_service.dart index 80bc20f..fbb7aec 100644 --- a/packages/flutter_shopping_interface/lib/src/service/product_service.dart +++ b/packages/flutter_shopping_interface/lib/src/service/product_service.dart @@ -11,4 +11,7 @@ abstract class ProductService with ChangeNotifier { /// Retrieve a list of categories List getCategories(); + + /// Get current Products + List get products; } diff --git a/packages/flutter_shopping_local/lib/service/local_order_service.dart b/packages/flutter_shopping_local/lib/service/local_order_service.dart index 190e74f..3f84868 100644 --- a/packages/flutter_shopping_local/lib/service/local_order_service.dart +++ b/packages/flutter_shopping_local/lib/service/local_order_service.dart @@ -5,11 +5,11 @@ import "package:flutter_shopping_interface/flutter_shopping_interface.dart"; class LocalOrderService with ChangeNotifier implements OrderService { @override Future createOrder( - int shopId, + String shopId, List products, - Map clientInformation, - ) { - // No use case for this method yet - throw UnimplementedError(); + Map> clientInformation, + ) async { + // Create the order + notifyListeners(); } } diff --git a/packages/flutter_shopping_local/lib/service/local_product_service.dart b/packages/flutter_shopping_local/lib/service/local_product_service.dart index e276743..c79d7f7 100644 --- a/packages/flutter_shopping_local/lib/service/local_product_service.dart +++ b/packages/flutter_shopping_local/lib/service/local_product_service.dart @@ -62,4 +62,7 @@ class LocalProductService with ChangeNotifier implements ProductService { ]; return Future.value(_products); } + + @override + List get products => _products; } diff --git a/packages/flutter_shopping_local/lib/service/service.dart b/packages/flutter_shopping_local/lib/service/service.dart index e974132..de7f343 100644 --- a/packages/flutter_shopping_local/lib/service/service.dart +++ b/packages/flutter_shopping_local/lib/service/service.dart @@ -1 +1,5 @@ +export "local_order_service.dart"; +export "local_product_service.dart"; export "local_shop_service.dart"; +export "local_shopping_cart_service.dart"; +export "local_shopping_service.dart";