mirror of
https://github.com/Iconica-Development/flutter_shopping.git
synced 2025-05-19 00:43:45 +02:00
feat: add interface to flutter_order_details
This commit is contained in:
parent
1b78b2c674
commit
2426416c42
14 changed files with 139 additions and 145 deletions
|
@ -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";
|
||||
|
|
|
@ -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<FlutterFormPage> 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<Product> products,
|
||||
Map<int, Map<String, dynamic>> value,
|
||||
OrderDetailConfiguration configuration,
|
||||
) onStepsCompleted;
|
||||
|
||||
/// Callback function that is called when the user has completed a step.
|
||||
final Function(int currentStep, Map<String, dynamic> 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<int, Map<String, dynamic>> 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<FlutterFormPage> _defaultPages(BuildContext context) {
|
|||
),
|
||||
];
|
||||
}
|
||||
|
||||
Widget _defaultOrderSuccess(
|
||||
BuildContext context,
|
||||
OrderDetailConfiguration configuration,
|
||||
Map<int, Map<String, dynamic>> orderDetails,
|
||||
) =>
|
||||
DefaultOrderSucces(
|
||||
configuration: configuration,
|
||||
orderDetails: orderDetails,
|
||||
);
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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",
|
|
@ -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<String, dynamic> order;
|
||||
}
|
|
@ -22,23 +22,33 @@ class _OrderDetailScreenState extends State<OrderDetailScreen> {
|
|||
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) {},
|
||||
),
|
||||
),
|
||||
);
|
|
@ -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<int, Map<String, dynamic>> 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,
|
||||
),
|
||||
),
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,8 +5,8 @@ import "package:flutter_shopping_interface/src/model/product.dart";
|
|||
abstract class OrderService {
|
||||
/// Create an order
|
||||
Future<void> createOrder(
|
||||
int shopId,
|
||||
String shopId,
|
||||
List<Product> products,
|
||||
Map<String, dynamic> clientInformation,
|
||||
Map<int, Map<String, dynamic>> clientInformation,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -11,4 +11,7 @@ abstract class ProductService with ChangeNotifier {
|
|||
|
||||
/// Retrieve a list of categories
|
||||
List<String> getCategories();
|
||||
|
||||
/// Get current Products
|
||||
List<Product> get products;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import "package:flutter_shopping_interface/flutter_shopping_interface.dart";
|
|||
class LocalOrderService with ChangeNotifier implements OrderService {
|
||||
@override
|
||||
Future<void> createOrder(
|
||||
int shopId,
|
||||
String shopId,
|
||||
List<Product> products,
|
||||
Map<String, dynamic> clientInformation,
|
||||
) {
|
||||
// No use case for this method yet
|
||||
throw UnimplementedError();
|
||||
Map<int, Map<String, dynamic>> clientInformation,
|
||||
) async {
|
||||
// Create the order
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,4 +62,7 @@ class LocalProductService with ChangeNotifier implements ProductService {
|
|||
];
|
||||
return Future.value(_products);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Product> get products => _products;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in a new issue