v6.6.1 updates

This commit is contained in:
Anthony 2023-05-28 22:36:39 +01:00
parent 54f7689e40
commit adc32e730d
36 changed files with 574 additions and 638 deletions

View File

@ -1,3 +1,9 @@
## [6.6.1] - 2023-05-28
* Refactor widgets + bug fixes
* Refactor extensions.dart
* Pubspec.yaml dependency updates.
## [6.6.0] - 2023-05-18 ## [6.6.0] - 2023-05-18
* Nylo v5.0.0 migration * Nylo v5.0.0 migration

View File

@ -4,7 +4,7 @@
# WooCommerce App: Label StoreMax # WooCommerce App: Label StoreMax
### Label StoreMax - v6.6.0 ### Label StoreMax - v6.6.1
[Official WooSignal WooCommerce App](https://woosignal.com) [Official WooSignal WooCommerce App](https://woosignal.com)

View File

@ -10,7 +10,7 @@
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductCategorySearchLoaderController class ProductCategorySearchLoaderController
extends WooSignalApiLoaderController<Product> { extends WooSignalApiLoaderController<Product> {

View File

@ -14,7 +14,7 @@ import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart'; import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/product_variation.dart' import 'package:woosignal/models/response/product_variation.dart'
as ws_product_variation; as ws_product_variation;

View File

@ -9,7 +9,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductLoaderController extends WooSignalApiLoaderController<Product> { class ProductLoaderController extends WooSignalApiLoaderController<Product> {
ProductLoaderController(); ProductLoaderController();

View File

@ -10,7 +10,7 @@
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/product_review.dart'; import 'package:woosignal/models/response/product_review.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductReviewsLoaderController class ProductReviewsLoaderController
extends WooSignalApiLoaderController<ProductReview> { extends WooSignalApiLoaderController<ProductReview> {

View File

@ -9,7 +9,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductSearchLoaderController class ProductSearchLoaderController
extends WooSignalApiLoaderController<Product> { extends WooSignalApiLoaderController<Product> {

View File

@ -11,7 +11,7 @@
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/product_variation.dart'; import 'package:woosignal/models/response/product_variation.dart';
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
class CartLineItem { class CartLineItem {
String? name; String? name;

View File

@ -0,0 +1,81 @@
//
// LabelCore
// Label StoreMAX
//
// Created by Anthony Gordon.
// 2023, WooSignal Ltd. All rights reserved.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
import 'package:flutter/widgets.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/order.dart';
razorPay(context,
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
Razorpay razorpay = Razorpay();
razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS,
(PaymentSuccessResponse response) async {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
Order? order = await appWooSignal((api) => api.createOrder(orderWC));
if (order != null) {
Cart.getInstance.clear();
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showToastNotification(
context,
title: "Error".tr(),
description: trans("Something went wrong, please contact our store"),
);
state.reloadState(showLoader: false);
}
});
razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) {
showToastNotification(context,
title: trans("Error"),
description: response.message ?? "",
style: ToastNotificationStyleType.WARNING);
state.reloadState(showLoader: false);
});
razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
// CHECKOUT HELPER
await checkout(taxRate, (total, billingDetails, cart) async {
var options = {
'key': getEnv('RAZORPAY_API_KEY'),
'amount': (double.parse(total) * 100).toInt(),
'name': getEnv('APP_NAME'),
'description': await cart.cartShortDesc(),
'prefill': {
"name": [
billingDetails!.billingAddress?.firstName,
billingDetails.billingAddress?.lastName
].where((t) => t != null || t != "").toList().join(" "),
"method": "card",
'email': billingDetails.billingAddress?.emailAddress ?? ""
}
};
state.reloadState(showLoader: true);
razorpay.open(options);
});
}
void _handleExternalWallet(ExternalWalletResponse response) {}

View File

@ -1,81 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/themes/styles/color_styles.dart'; import 'package:flutter_app/resources/themes/styles/color_styles.dart';
import 'package:nylo_framework/nylo_framework.dart';
extension NyText on Text { extension NyText on Text {
/// Set the Style to use [displayLarge].
Text displayLarge(BuildContext context) {
return setStyle(Theme.of(context).textTheme.displayLarge);
}
/// Set the Style to use [displayMedium].
Text displayMedium(BuildContext context) {
return setStyle(Theme.of(context).textTheme.displayMedium);
}
/// Set the Style to use [displaySmall].
Text displaySmall(BuildContext context) {
return setStyle(Theme.of(context).textTheme.displaySmall);
}
/// Set the Style to use [headlineLarge].
Text headingLarge(BuildContext context) {
return setStyle(Theme.of(context).textTheme.headlineLarge);
}
/// Set the Style to use [headlineMedium].
Text headingMedium(BuildContext context) {
return setStyle(Theme.of(context).textTheme.headlineMedium);
}
/// Set the Style to use [headlineSmall].
Text headingSmall(BuildContext context) {
return setStyle(Theme.of(context).textTheme.headlineSmall);
}
/// Set the Style to use [titleLarge].
Text titleLarge(BuildContext context) {
return setStyle(Theme.of(context).textTheme.titleLarge);
}
/// Set the Style to use [titleMedium].
Text titleMedium(BuildContext context) {
return setStyle(Theme.of(context).textTheme.titleMedium);
}
/// Set the Style to use [titleSmall].
Text titleSmall(BuildContext context) {
return setStyle(Theme.of(context).textTheme.titleSmall);
}
/// Set the Style to use [bodyLarge].
Text large(BuildContext context) {
return setStyle(Theme.of(context).textTheme.bodyLarge);
}
/// Set the Style to use [bodyMedium].
Text medium(BuildContext context) {
return setStyle(Theme.of(context).textTheme.bodyMedium);
}
/// Set the Style to use [bodySmall].
Text small(BuildContext context) {
return setStyle(Theme.of(context).textTheme.bodySmall);
}
/// Make the font bold.
Text fontWeightBold() {
return copyWith(style: TextStyle(fontWeight: FontWeight.bold));
}
/// Make the font light.
Text fontWeightLight() {
return copyWith(style: TextStyle(fontWeight: FontWeight.w300));
}
/// Change the [style].
Text setStyle(TextStyle? style) => copyWith(style: style);
/// Sets the color from your [ColorStyles] or [Color]. /// Sets the color from your [ColorStyles] or [Color].
Text setColor( Text setColor(
BuildContext context, Color Function(ColorStyles color) newColor, BuildContext context, Color Function(ColorStyles color) newColor,
@ -84,59 +12,6 @@ extension NyText on Text {
style: TextStyle( style: TextStyle(
color: newColor(ThemeColor.get(context, themeId: themeId)))); color: newColor(ThemeColor.get(context, themeId: themeId))));
} }
/// Aligns text to the left.
Text alignLeft() {
return copyWith(textAlign: TextAlign.left);
}
/// Aligns text to the right.
Text alignRight() {
return copyWith(textAlign: TextAlign.right);
}
/// Aligns text to the center.
Text alignCenter() {
return copyWith(textAlign: TextAlign.center);
}
/// Aligns text to the center.
Text setMaxLines(int maxLines) {
return copyWith(maxLines: maxLines);
}
/// Change the [fontFamily].
Text setFontFamily(String fontFamily) =>
copyWith(style: TextStyle(fontFamily: fontFamily));
/// Helper to apply changes.
Text copyWith(
{Key? key,
StrutStyle? strutStyle,
TextAlign? textAlign,
TextDirection? textDirection = TextDirection.ltr,
Locale? locale,
bool? softWrap,
TextOverflow? overflow,
double? textScaleFactor,
int? maxLines,
String? semanticsLabel,
TextWidthBasis? textWidthBasis,
TextStyle? style}) {
return Text(data ?? "",
key: key ?? this.key,
strutStyle: strutStyle ?? this.strutStyle,
textAlign: textAlign ?? this.textAlign,
textDirection: textDirection ?? this.textDirection,
locale: locale ?? this.locale,
softWrap: softWrap ?? this.softWrap,
overflow: overflow ?? this.overflow,
textScaleFactor: textScaleFactor ?? this.textScaleFactor,
maxLines: maxLines ?? this.maxLines,
semanticsLabel: semanticsLabel ?? this.semanticsLabel,
textWidthBasis: textWidthBasis ?? this.textWidthBasis,
style: style != null ? this.style?.merge(style) ?? style : this.style);
}
} }
/// Check if the [Product] is new. /// Check if the [Product] is new.

View File

@ -38,7 +38,7 @@ import 'package:money_formatter/money_formatter.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:status_alert/status_alert.dart'; import 'package:status_alert/status_alert.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/woosignal.dart'; import 'package:woosignal/woosignal.dart';
import 'package:wp_json_api/models/responses/wp_user_info_response.dart'; import 'package:wp_json_api/models/responses/wp_user_info_response.dart';

View File

@ -1,6 +1,7 @@
import 'package:flutter_app/app/models/payment_type.dart'; import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart'; import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart';
import 'package:flutter_app/app/providers/payments/paypal_pay.dart'; import 'package:flutter_app/app/providers/payments/paypal_pay.dart';
import 'package:flutter_app/app/providers/payments/razorpay_pay.dart';
import 'package:flutter_app/app/providers/payments/stripe_pay.dart'; import 'package:flutter_app/app/providers/payments/stripe_pay.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
@ -43,6 +44,14 @@ List<PaymentType> paymentTypeList = [
pay: payPalPay, pay: payPalPay,
), ),
addPayment(
id: 5,
name: "RazorPay",
description: trans("Debit or Credit Card"),
assetImage: "razorpay.png",
pay: razorPay,
),
// e.g. add more here // e.g. add more here
// addPayment( // addPayment(

View File

@ -1,4 +1,3 @@
import 'package:nylo_framework/nylo_framework.dart';
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -20,7 +20,7 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
class BrowseCategoryPage extends NyStatefulWidget { class BrowseCategoryPage extends NyStatefulWidget {
final BrowseCategoryController controller = BrowseCategoryController(); final BrowseCategoryController controller = BrowseCategoryController();

View File

@ -16,7 +16,7 @@ import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart'; import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
class BrowseSearchPage extends NyStatefulWidget { class BrowseSearchPage extends NyStatefulWidget {
final BrowseSearchController controller = BrowseSearchController(); final BrowseSearchController controller = BrowseSearchController();

View File

@ -16,7 +16,6 @@ import 'package:flutter_app/app/models/customer_address.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart'; import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/buttons.dart'; import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart'; import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_app/resources/widgets/text_row_widget.dart'; import 'package:flutter_app/resources/widgets/text_row_widget.dart';
@ -30,26 +29,19 @@ class CartPage extends StatefulWidget {
_CartPageState createState() => _CartPageState(); _CartPageState createState() => _CartPageState();
} }
class _CartPageState extends State<CartPage> { class _CartPageState extends NyState<CartPage> {
_CartPageState(); _CartPageState();
bool _isLoading = true, _isCartEmpty = false;
List<CartLineItem> _cartLines = []; List<CartLineItem> _cartLines = [];
@override boot() async {
void initState() { await _cartCheck();
super.initState();
_cartCheck();
CheckoutSession.getInstance.coupon = null; CheckoutSession.getInstance.coupon = null;
} }
_cartCheck() async { _cartCheck() async {
List<CartLineItem> cart = await Cart.getInstance.getCart(); List<CartLineItem> cart = await Cart.getInstance.getCart();
if (cart.isEmpty) { if (cart.isEmpty) {
setState(() {
_isLoading = false;
_isCartEmpty = true;
});
return; return;
} }
@ -59,25 +51,18 @@ class _CartPageState extends State<CartPage> {
await (appWooSignal((api) => api.cartCheck(cartJSON))); await (appWooSignal((api) => api.cartCheck(cartJSON)));
if (cartRes.isEmpty) { if (cartRes.isEmpty) {
Cart.getInstance.saveCartToPref(cartLineItems: []); Cart.getInstance.saveCartToPref(cartLineItems: []);
setState(() {
_isCartEmpty = true;
_isLoading = false;
});
return; return;
} }
_cartLines = cartRes.map((json) => CartLineItem.fromJson(json)).toList(); _cartLines = cartRes.map((json) => CartLineItem.fromJson(json)).toList();
if (_cartLines.isNotEmpty) { if (_cartLines.isNotEmpty) {
Cart.getInstance.saveCartToPref(cartLineItems: _cartLines); Cart.getInstance.saveCartToPref(cartLineItems: _cartLines);
} }
setState(() {
_isLoading = false;
});
} }
void _actionProceedToCheckout() async { void _actionProceedToCheckout() async {
List<CartLineItem> cartLineItems = await Cart.getInstance.getCart(); List<CartLineItem> cartLineItems = await Cart.getInstance.getCart();
if (_isLoading == true) { if (isLoading()) {
return; return;
} }
@ -163,9 +148,6 @@ class _CartPageState extends State<CartPage> {
style: ToastNotificationStyleType.WARNING, style: ToastNotificationStyleType.WARNING,
icon: Icons.remove_shopping_cart, icon: Icons.remove_shopping_cart,
); );
if (_cartLines.isEmpty) {
_isCartEmpty = true;
}
setState(() {}); setState(() {});
} }
@ -177,7 +159,6 @@ class _CartPageState extends State<CartPage> {
description: trans("Cart cleared"), description: trans("Cart cleared"),
style: ToastNotificationStyleType.SUCCESS, style: ToastNotificationStyleType.SUCCESS,
icon: Icons.delete_outline); icon: Icons.delete_outline);
_isCartEmpty = true;
setState(() {}); setState(() {});
} }
@ -214,55 +195,46 @@ class _CartPageState extends State<CartPage> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
_isCartEmpty Expanded(
? Expanded( child: afterLoad(child: () => _cartLines.isEmpty ? FractionallySizedBox(
child: FractionallySizedBox( child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
children: <Widget>[ Icon(
Icon( Icons.shopping_cart,
Icons.shopping_cart, size: 100,
size: 100, color: Colors.black45,
color: Colors.black45,
),
Padding(
child: Text(
trans("Empty Basket"),
style: Theme.of(context).textTheme.bodyMedium,
),
padding: EdgeInsets.only(top: 10),
)
],
),
heightFactor: 0.5,
widthFactor: 1,
), ),
) Padding(
: (_isLoading child: Text(
? Expanded( trans("Empty Basket"),
child: AppLoaderWidget(), style: Theme.of(context).textTheme.bodyMedium,
) ),
: Expanded( padding: EdgeInsets.only(top: 10),
child: ListView.builder( )
padding: const EdgeInsets.all(8), ],
itemCount: _cartLines.length, ),
itemBuilder: (BuildContext context, int index) { heightFactor: 0.5,
CartLineItem cartLineItem = _cartLines[index]; widthFactor: 1,
return CartItemContainer( ) : ListView.builder(
cartLineItem: cartLineItem, padding: const EdgeInsets.all(8),
actionIncrementQuantity: () => itemCount: _cartLines.length,
actionIncrementQuantity( itemBuilder: (BuildContext context, int index) {
cartLineItem: cartLineItem), CartLineItem cartLineItem = _cartLines[index];
actionDecrementQuantity: () => return CartItemContainer(
actionDecrementQuantity( cartLineItem: cartLineItem,
cartLineItem: cartLineItem), actionIncrementQuantity: () =>
actionRemoveItem: () => actionIncrementQuantity(
actionRemoveItem(index: index), cartLineItem: cartLineItem),
); actionDecrementQuantity: () =>
}), actionDecrementQuantity(
flex: 3, cartLineItem: cartLineItem),
)), actionRemoveItem: () =>
actionRemoveItem(index: index),
);
})),
),
Divider( Divider(
color: Colors.black45, color: Colors.black45,
), ),
@ -271,7 +243,7 @@ class _CartPageState extends State<CartPage> {
child: (BuildContext context, data) => Padding( child: (BuildContext context, data) => Padding(
child: TextRowWidget( child: TextRowWidget(
title: trans("Total"), title: trans("Total"),
text: (_isLoading ? "" : data), text: isLoading() ? '' : data,
), ),
padding: EdgeInsets.only(bottom: 15, top: 15), padding: EdgeInsets.only(bottom: 15, top: 15),
), ),

View File

@ -16,7 +16,6 @@ import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/app/models/customer_country.dart'; import 'package:flutter_app/app/models/customer_country.dart';
import 'package:flutter_app/app/models/payment_type.dart'; import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/extensions.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/buttons.dart'; import 'package:flutter_app/resources/widgets/buttons.dart';
@ -186,7 +185,7 @@ class CheckoutConfirmationPageState extends NyState<CheckoutConfirmationPage> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text(trans("Checkout")), Text(trans("Checkout")),
Text(_wooSignalApp?.appName ?? getEnv('APP_NAME')).small(context), Text(_wooSignalApp?.appName ?? getEnv('APP_NAME')).bodySmall(context),
], ],
), ),
centerTitle: false, centerTitle: false,

View File

@ -77,7 +77,7 @@ class _CheckoutStatusState extends NyState<CheckoutStatusPage> {
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
"${trans("Order Ref")}. #${_order!.id.toString()}", "${trans("Order Ref")}. #${_order?.id.toString()}",
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
@ -119,9 +119,9 @@ class _CheckoutStatusState extends NyState<CheckoutStatusPage> {
), ),
Expanded( Expanded(
child: ListView.builder( child: ListView.builder(
itemCount: _order!.lineItems == null itemCount: _order?.lineItems == null
? 0 ? 0
: _order!.lineItems!.length, : _order?.lineItems?.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
ws_order.LineItems lineItem = _order!.lineItems![index]; ws_order.LineItems lineItem = _order!.lineItems![index];
return Container( return Container(

View File

@ -14,7 +14,6 @@ import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart'; import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/buttons.dart'; import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/cart_icon_widget.dart'; import 'package:flutter_app/resources/widgets/cart_icon_widget.dart';
import 'package:flutter_app/resources/widgets/product_detail_body_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_body_widget.dart';
@ -23,7 +22,7 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/product_variation.dart' import 'package:woosignal/models/response/product_variation.dart'
as ws_product_variation; as ws_product_variation;
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
class ProductDetailPage extends NyStatefulWidget { class ProductDetailPage extends NyStatefulWidget {
@ -36,7 +35,6 @@ class ProductDetailPage extends NyStatefulWidget {
} }
class _ProductDetailState extends NyState<ProductDetailPage> { class _ProductDetailState extends NyState<ProductDetailPage> {
bool _isLoading = true;
ws_product.Product? _product; ws_product.Product? _product;
List<ws_product_variation.ProductVariation> _productVariations = []; List<ws_product_variation.ProductVariation> _productVariations = [];
@ -45,14 +43,15 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
@override @override
init() async { init() async {
super.init();
}
@override
boot() async {
_product = widget.controller.data(); _product = widget.controller.data();
if (_product!.type == "variable") { if (_product!.type == "variable") {
await _fetchProductVariations(); await _fetchProductVariations();
return;
} }
setState(() {
_isLoading = false;
});
} }
_fetchProductVariations() async { _fetchProductVariations() async {
@ -76,9 +75,6 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
} }
} }
_productVariations = tmpVariations; _productVariations = tmpVariations;
setState(() {
_isLoading = false;
});
} }
_modalBottomSheetOptionsForAttribute(int attributeIndex) { _modalBottomSheetOptionsForAttribute(int attributeIndex) {
@ -232,7 +228,7 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
actions: <Widget>[ actions: <Widget>[
if (_wooSignalApp!.wishlistEnabled!) if (_wooSignalApp!.wishlistEnabled!)
NyFutureBuilder( NyFutureBuilder(
future: hasAddedWishlistProduct(_product!.id), future: hasAddedWishlistProduct(_product?.id),
child: (context, dynamic isInFavourites) { child: (context, dynamic isInFavourites) {
return isInFavourites return isInFavourites
? IconButton( ? IconButton(
@ -256,32 +252,30 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
centerTitle: true, centerTitle: true,
), ),
body: SafeArea( body: SafeArea(
child: _isLoading child: afterLoad(child: () => Column(
? AppLoaderWidget() mainAxisAlignment: MainAxisAlignment.spaceBetween,
: Column( crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[
crossAxisAlignment: CrossAxisAlignment.center, Expanded(
children: <Widget>[ child: ProductDetailBodyWidget(
Expanded( wooSignalApp: _wooSignalApp,
child: ProductDetailBodyWidget( product: _product,
wooSignalApp: _wooSignalApp,
product: _product,
),
),
// </Product body>
ProductDetailFooterActionsWidget(
onAddToCart: _addItemToCart,
onViewExternalProduct:
widget.controller.viewExternalProduct,
onAddQuantity: () => widget.controller
.addQuantityTapped(onSuccess: () => setState(() {})),
onRemoveQuantity: () => widget.controller
.removeQuantityTapped(onSuccess: () => setState(() {})),
product: _product,
quantity: widget.controller.quantity,
)
],
), ),
),
// </Product body>
ProductDetailFooterActionsWidget(
onAddToCart: _addItemToCart,
onViewExternalProduct:
widget.controller.viewExternalProduct,
onAddQuantity: () => widget.controller
.addQuantityTapped(onSuccess: () => setState(() {})),
onRemoveQuantity: () => widget.controller
.removeQuantityTapped(onSuccess: () => setState(() {})),
product: _product,
quantity: widget.controller.quantity,
)
],
))
), ),
); );
} }

View File

@ -20,7 +20,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:woosignal/models/response/product_review.dart'; import 'package:woosignal/models/response/product_review.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import '../../app/controllers/product_reviews_controller.dart'; import '../../app/controllers/product_reviews_controller.dart';
class ProductReviewsPage extends NyStatefulWidget { class ProductReviewsPage extends NyStatefulWidget {

View File

@ -10,25 +10,21 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class WishListPageWidget extends StatefulWidget { class WishListPageWidget extends StatefulWidget {
@override @override
_WishListPageWidgetState createState() => _WishListPageWidgetState(); _WishListPageWidgetState createState() => _WishListPageWidgetState();
} }
class _WishListPageWidgetState extends State<WishListPageWidget> { class _WishListPageWidgetState extends NyState<WishListPageWidget> {
List<Product> _products = []; List<Product> _products = [];
bool? isLoading;
@override @override
void initState() { boot() async {
super.initState(); await loadProducts();
isLoading = true;
loadProducts();
} }
loadProducts() async { loadProducts() async {
@ -36,9 +32,6 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
List<int> productIds = List<int> productIds =
favouriteProducts.map((e) => e['id']).cast<int>().toList(); favouriteProducts.map((e) => e['id']).cast<int>().toList();
if (productIds.isEmpty) { if (productIds.isEmpty) {
setState(() {
isLoading = false;
});
return; return;
} }
_products = await (appWooSignal((api) => api.getProducts( _products = await (appWooSignal((api) => api.getProducts(
@ -47,9 +40,6 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
status: "publish", status: "publish",
stockStatus: "instock", stockStatus: "instock",
))); )));
setState(() {
isLoading = false;
});
} }
@override @override
@ -60,96 +50,96 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
title: Text(trans("Wishlist")), title: Text(trans("Wishlist")),
), ),
body: SafeArea( body: SafeArea(
child: isLoading! child: afterLoad(
? AppLoaderWidget() child: () => _products.isEmpty
: _products.isEmpty && isLoading == false ? Center(
? Center( child: Column(
child: Column( crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, children: [
children: [ Icon(
Icon( Icons.favorite,
Icons.favorite, size: 40,
size: 40, ),
Padding(
padding: EdgeInsets.symmetric(vertical: 12),
),
Text(trans("No items found"),
style: Theme.of(context)
.textTheme
.titleLarge!
.setColor(context,
(color) => color!.primaryContent))
],
),
)
: ListView.separated(
padding: EdgeInsets.only(top: 10),
itemBuilder: (BuildContext context, int index) {
Product product = _products[index];
return InkWell(
onTap: () => Navigator.pushNamed(
context, "/product-detail",
arguments: product),
child: Container(
child: Row(
children: [
Container(
margin: EdgeInsets.only(left: 8),
child: CachedImageWidget(
image: (product.images.isNotEmpty
? product.images.first.src
: getEnv("PRODUCT_PLACEHOLDER_IMAGE")),
fit: BoxFit.contain,
width: double.infinity,
), ),
Padding( width: MediaQuery.of(context).size.width / 4,
padding: EdgeInsets.symmetric(vertical: 12), ),
), Expanded(
Text(trans("No items found"),
style: Theme.of(context)
.textTheme
.titleLarge!
.setColor(context,
(color) => color!.primaryContent))
],
),
)
: ListView.separated(
padding: EdgeInsets.only(top: 10),
itemBuilder: (BuildContext context, int index) {
Product product = _products[index];
return InkWell(
onTap: () => Navigator.pushNamed(
context, "/product-detail",
arguments: product),
child: Container( child: Container(
child: Row( child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.center,
children: [ children: [
Container( Text(
margin: EdgeInsets.only(left: 8), product.name!,
child: CachedImageWidget( style: TextStyle(
image: (product.images.isNotEmpty fontWeight: FontWeight.bold),
? product.images.first.src maxLines: 2,
: getEnv("PRODUCT_PLACEHOLDER_IMAGE")), overflow: TextOverflow.ellipsis,
fit: BoxFit.contain,
width: double.infinity,
),
width: MediaQuery.of(context).size.width / 4,
), ),
Expanded( Text(
child: Container( formatStringCurrency(
child: Column( total: product.price),
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
product.name!,
style: TextStyle(
fontWeight: FontWeight.bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
Text(
formatStringCurrency(
total: product.price),
),
],
),
),
), ),
Container(
width: MediaQuery.of(context).size.width / 5,
alignment: Alignment.center,
child: IconButton(
icon: Icon(
Icons.favorite,
color: Colors.red,
),
onPressed: () =>
_removeFromWishlist(product),
),
)
], ],
), ),
), ),
); ),
}, Container(
separatorBuilder: (BuildContext context, int index) { width: MediaQuery.of(context).size.width / 5,
return Divider(); alignment: Alignment.center,
}, child: IconButton(
itemCount: _products.length)), icon: Icon(
Icons.favorite,
color: Colors.red,
),
onPressed: () =>
_removeFromWishlist(product),
),
)
],
),
),
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
itemCount: _products.length)),
),
); );
} }

View File

@ -20,7 +20,7 @@ import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class CompoHomeWidget extends StatefulWidget { class CompoHomeWidget extends StatefulWidget {
CompoHomeWidget({Key? key, required this.wooSignalApp}) : super(key: key); CompoHomeWidget({Key? key, required this.wooSignalApp}) : super(key: key);

View File

@ -11,7 +11,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/app/controllers/product_loader_controller.dart'; import 'package:flutter_app/app/controllers/product_loader_controller.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/cart_icon_widget.dart'; import 'package:flutter_app/resources/widgets/cart_icon_widget.dart';
import 'package:flutter_app/resources/widgets/home_drawer_widget.dart'; import 'package:flutter_app/resources/widgets/home_drawer_widget.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart'; import 'package:flutter_app/resources/widgets/safearea_widget.dart';
@ -20,7 +19,7 @@ import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/models/response/product_category.dart' as ws_category; import 'package:woosignal/models/response/product_category.dart' as ws_category;
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
class MelloThemeWidget extends StatefulWidget { class MelloThemeWidget extends StatefulWidget {
MelloThemeWidget( MelloThemeWidget(
@ -33,7 +32,7 @@ class MelloThemeWidget extends StatefulWidget {
_MelloThemeWidgetState createState() => _MelloThemeWidgetState(); _MelloThemeWidgetState createState() => _MelloThemeWidgetState();
} }
class _MelloThemeWidgetState extends State<MelloThemeWidget> { class _MelloThemeWidgetState extends NyState<MelloThemeWidget> {
final RefreshController _refreshController = final RefreshController _refreshController =
RefreshController(initialRefresh: false); RefreshController(initialRefresh: false);
final ProductLoaderController _productLoaderController = final ProductLoaderController _productLoaderController =
@ -41,20 +40,21 @@ class _MelloThemeWidgetState extends State<MelloThemeWidget> {
List<ws_category.ProductCategory> _categories = []; List<ws_category.ProductCategory> _categories = [];
bool _shouldStopRequests = false, _isLoading = true; bool _shouldStopRequests = false;
@override @override
void initState() { void init() async {
super.initState(); super.init();
_home(); }
@override
boot() async {
await _home();
} }
_home() async { _home() async {
await fetchProducts(); await fetchProducts();
await _fetchCategories(); await _fetchCategories();
setState(() {
_isLoading = false;
});
} }
_fetchCategories() async { _fetchCategories() async {
@ -110,18 +110,16 @@ class _MelloThemeWidgetState extends State<MelloThemeWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: _isLoading child: afterLoad(child: () => RefreshableScrollContainer(
? AppLoaderWidget() controller: _refreshController,
: RefreshableScrollContainer( onRefresh: _onRefresh,
controller: _refreshController, onLoading: _onLoading,
onRefresh: _onRefresh, products: _productLoaderController.getResults(),
onLoading: _onLoading, onTap: _showProduct,
products: _productLoaderController.getResults(), bannerHeight: MediaQuery.of(context).size.height / 3.5,
onTap: _showProduct, bannerImages: bannerImages,
bannerHeight: MediaQuery.of(context).size.height / 3.5, modalBottomSheetMenu: _modalBottomSheetMenu,
bannerImages: bannerImages, )),
modalBottomSheetMenu: _modalBottomSheetMenu,
),
flex: 1, flex: 1,
), ),
], ],

View File

@ -12,7 +12,6 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/app/controllers/product_loader_controller.dart'; import 'package:flutter_app/app/controllers/product_loader_controller.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
import 'package:flutter_app/resources/widgets/home_drawer_widget.dart'; import 'package:flutter_app/resources/widgets/home_drawer_widget.dart';
import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart'; import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart';
@ -23,7 +22,7 @@ import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/models/response/product_category.dart' as ws_category; import 'package:woosignal/models/response/product_category.dart' as ws_category;
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
class NoticHomeWidget extends StatefulWidget { class NoticHomeWidget extends StatefulWidget {
NoticHomeWidget({Key? key, required this.wooSignalApp}) : super(key: key); NoticHomeWidget({Key? key, required this.wooSignalApp}) : super(key: key);
@ -34,7 +33,7 @@ class NoticHomeWidget extends StatefulWidget {
_NoticHomeWidgetState createState() => _NoticHomeWidgetState(); _NoticHomeWidgetState createState() => _NoticHomeWidgetState();
} }
class _NoticHomeWidgetState extends State<NoticHomeWidget> { class _NoticHomeWidgetState extends NyState<NoticHomeWidget> {
Widget? activeWidget; Widget? activeWidget;
final RefreshController _refreshController = final RefreshController _refreshController =
RefreshController(initialRefresh: false); RefreshController(initialRefresh: false);
@ -43,20 +42,16 @@ class _NoticHomeWidgetState extends State<NoticHomeWidget> {
ProductLoaderController(); ProductLoaderController();
List<ws_category.ProductCategory> _categories = []; List<ws_category.ProductCategory> _categories = [];
bool _shouldStopRequests = false, _isLoading = true; bool _shouldStopRequests = false;
@override @override
void initState() { boot() async {
super.initState(); await _home();
_home();
} }
_home() async { _home() async {
await fetchProducts(); await fetchProducts();
await _fetchCategories(); await _fetchCategories();
setState(() {
_isLoading = false;
});
} }
_fetchCategories() async { _fetchCategories() async {
@ -114,102 +109,98 @@ class _NoticHomeWidgetState extends State<NoticHomeWidget> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
(_isLoading Expanded(
? Expanded(child: AppLoaderWidget()) child: afterLoad(child: () => ListView(
: Expanded( shrinkWrap: true,
child: ListView( children: [
shrinkWrap: true, Container(
margin: EdgeInsets.only(bottom: 15),
child: Swiper(
itemBuilder: (BuildContext context, int index) {
return CachedImageWidget(
image:
widget.wooSignalApp!.bannerImages![index],
fit: BoxFit.cover,
);
},
itemCount:
widget.wooSignalApp!.bannerImages!.length,
viewportFraction: 0.8,
scale: 0.9,
),
height: MediaQuery.of(context).size.height / 2.5,
),
Container(
height: 75,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Container( Text(trans("Must have")),
margin: EdgeInsets.only(bottom: 15), Flexible(
child: Swiper( child: Text(
itemBuilder: (BuildContext context, int index) { trans("Our selection of new items"),
return CachedImageWidget( style: Theme.of(context)
image: .textTheme
widget.wooSignalApp!.bannerImages![index], .headlineMedium,
fit: BoxFit.cover, maxLines: 1,
); overflow: TextOverflow.ellipsis,
},
itemCount:
widget.wooSignalApp!.bannerImages!.length,
viewportFraction: 0.8,
scale: 0.9,
),
height: MediaQuery.of(context).size.height / 2.5,
),
Container(
height: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(trans("Must have")),
Flexible(
child: Text(
trans("Our selection of new items"),
style: Theme.of(context)
.textTheme
.headlineMedium,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
)
],
),
),
Container(
height: 250,
child: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
footer: CustomFooter(
builder:
(BuildContext context, LoadStatus? mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text(trans("pull up load"));
} else if (mode == LoadStatus.loading) {
body = CupertinoActivityIndicator();
} else if (mode == LoadStatus.failed) {
body =
Text(trans("Load Failed! Click retry!"));
} else if (mode == LoadStatus.canLoading) {
body = Text(trans("release to load more"));
} else {
return SizedBox.shrink();
}
return Container(
height: 55.0,
child: Center(child: body),
);
},
),
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
child: (products.isNotEmpty
? ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: false,
itemBuilder: (cxt, i) {
return Container(
// height: 200,
width:
MediaQuery.of(context).size.width /
2.5,
child: ProductItemContainer(
product: products[i],
onTap: _showProduct),
);
},
itemCount: products.length,
)
: NoResultsForProductsWidget()),
), ),
) )
], ],
), ),
flex: 1, ),
)), Container(
height: 380,
child: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
footer: CustomFooter(
builder:
(BuildContext context, LoadStatus? mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text(trans("pull up load"));
} else if (mode == LoadStatus.loading) {
body = CupertinoActivityIndicator();
} else if (mode == LoadStatus.failed) {
body =
Text(trans("Load Failed! Click retry!"));
} else if (mode == LoadStatus.canLoading) {
body = Text(trans("release to load more"));
} else {
return SizedBox.shrink();
}
return Container(
height: 55.0,
child: Center(child: body),
);
},
),
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
child: (products.isNotEmpty
? ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: false,
itemBuilder: (cxt, i) {
return Container(
width:
MediaQuery.of(context).size.width /
2.5,
child: ProductItemContainer(
product: products[i],
onTap: _showProduct),
);
},
itemCount: products.length,
)
: NoResultsForProductsWidget()),
),
)
],
),
),flex: 1,),
], ],
), ),
), ),

View File

@ -15,7 +15,7 @@ import 'package:flutter_app/resources/widgets/product_detail_image_swiper_widget
import 'package:flutter_app/resources/widgets/product_detail_related_products_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_related_products_widget.dart';
import 'package:flutter_app/resources/widgets/product_detail_reviews_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_reviews_widget.dart';
import 'package:flutter_app/resources/widgets/product_detail_upsell_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_upsell_widget.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
class ProductDetailBodyWidget extends StatelessWidget { class ProductDetailBodyWidget extends StatelessWidget {

View File

@ -13,7 +13,7 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductDetailDescriptionWidget extends StatelessWidget { class ProductDetailDescriptionWidget extends StatelessWidget {
const ProductDetailDescriptionWidget({Key? key, required this.product}) const ProductDetailDescriptionWidget({Key? key, required this.product})

View File

@ -13,7 +13,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/buttons.dart'; import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductDetailFooterActionsWidget extends StatelessWidget { class ProductDetailFooterActionsWidget extends StatelessWidget {
const ProductDetailFooterActionsWidget( const ProductDetailFooterActionsWidget(

View File

@ -10,7 +10,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductDetailHeaderWidget extends StatelessWidget { class ProductDetailHeaderWidget extends StatelessWidget {
const ProductDetailHeaderWidget({Key? key, required this.product}) const ProductDetailHeaderWidget({Key? key, required this.product})

View File

@ -12,7 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductDetailImageSwiperWidget extends StatelessWidget { class ProductDetailImageSwiperWidget extends StatelessWidget {
const ProductDetailImageSwiperWidget( const ProductDetailImageSwiperWidget(

View File

@ -12,7 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
class ProductDetailRelatedProductsWidget extends StatelessWidget { class ProductDetailRelatedProductsWidget extends StatelessWidget {
@ -55,7 +55,7 @@ class ProductDetailRelatedProductsWidget extends StatelessWidget {
child: NyFutureBuilder<List<Product>>( child: NyFutureBuilder<List<Product>>(
future: fetchRelated(), future: fetchRelated(),
child: (context, relatedProducts) { child: (context, relatedProducts) {
if (relatedProducts == null) { if (relatedProducts.isEmpty) {
return SizedBox.shrink(); return SizedBox.shrink();
} }
return ListView( return ListView(
@ -74,9 +74,7 @@ class ProductDetailRelatedProductsWidget extends StatelessWidget {
); );
} }
Future<List<Product>> fetchRelated() async { Future<List<Product>> fetchRelated() async => await (appWooSignal(
return await (appWooSignal( (api) => api.getProducts(perPage: 100, include: product!.relatedIds),
(api) => api.getProducts(perPage: 100, include: product!.relatedIds), ));
));
}
} }

View File

@ -16,7 +16,7 @@ import 'package:flutter_app/resources/widgets/product_detail_review_tile_widget.
import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/product_review.dart'; import 'package:woosignal/models/response/product_review.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
class ProductDetailReviewsWidget extends StatefulWidget { class ProductDetailReviewsWidget extends StatefulWidget {

View File

@ -13,7 +13,7 @@ import 'package:flutter_app/app/controllers/product_loader_controller.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
class ProductDetailUpsellWidget extends StatefulWidget { class ProductDetailUpsellWidget extends StatefulWidget {

View File

@ -23,7 +23,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_swiper_view/flutter_swiper_view.dart'; import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
class RefreshableScrollContainer extends StatelessWidget { class RefreshableScrollContainer extends StatelessWidget {
@ -108,7 +108,7 @@ class RefreshableScrollContainer extends StatelessWidget {
.map((product) => StaggeredGridTile.fit( .map((product) => StaggeredGridTile.fit(
crossAxisCellCount: 1, crossAxisCellCount: 1,
child: Container( child: Container(
height: 200, height: 300,
child: ProductItemContainer( child: ProductItemContainer(
product: product, product: product,
onTap: onTap, onTap: onTap,
@ -316,138 +316,134 @@ class ProductItemContainer extends StatelessWidget {
return SizedBox.shrink(); return SizedBox.shrink();
} }
return LayoutBuilder( double height = 280;
builder: (cxt, constraints) => InkWell( return InkWell(
child: Container( child: Container(
margin: EdgeInsets.all(4), margin: EdgeInsets.all(4),
child: Column( child: ListView(
crossAxisAlignment: CrossAxisAlignment.start, shrinkWrap: true,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, physics: NeverScrollableScrollPhysics(),
children: <Widget>[ children: <Widget>[
Container( Container(
height: constraints.maxHeight / 1.6, height: 180,
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(3.0), borderRadius: BorderRadius.circular(3.0),
child: Stack( child: Stack(
children: [ children: [
Container( Container(
color: Colors.grey[100], color: Colors.grey[100],
height: double.infinity, height: double.infinity,
width: double.infinity, width: double.infinity,
), ),
CachedImageWidget( CachedImageWidget(
image: (product!.images.isNotEmpty image: (product!.images.isNotEmpty
? product!.images.first.src ? product!.images.first.src
: getEnv("PRODUCT_PLACEHOLDER_IMAGE")), : getEnv("PRODUCT_PLACEHOLDER_IMAGE")),
fit: BoxFit.contain, fit: BoxFit.contain,
height: constraints.maxHeight / 1.6, height: height,
width: double.infinity, width: double.infinity,
), ),
if (isProductNew(product)) if (isProductNew(product))
Container(padding: EdgeInsets.all(4), child: Text("New", style: TextStyle(color: Colors.white),), decoration: BoxDecoration(color: Colors.black),), Container(padding: EdgeInsets.all(4), child: Text("New", style: TextStyle(color: Colors.white),), decoration: BoxDecoration(color: Colors.black),),
if (product!.onSale! && product!.type != "variable") if (product!.onSale! && product!.type != "variable")
Positioned( Positioned(
bottom: 0, bottom: 0,
left: 0, left: 0,
right: 0, right: 0,
child: Container( child: Container(
padding: EdgeInsets.all(3), padding: EdgeInsets.all(3),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white70, color: Colors.white70,
// borderRadius: BorderRadius.circular(4), ),
), child: RichText(
child: RichText( textAlign: TextAlign.center,
textAlign: TextAlign.center, text: TextSpan(
text: TextSpan( text: '',
text: '', style: Theme.of(context).textTheme.bodyLarge,
style: Theme.of(context).textTheme.bodyLarge, children: <TextSpan>[
children: <TextSpan>[ TextSpan(
TextSpan( text:
text: "${workoutSaleDiscount(salePrice: product!.salePrice, priceBefore: product!.regularPrice)}% ${trans("off")}",
"${workoutSaleDiscount(salePrice: product!.salePrice, priceBefore: product!.regularPrice)}% ${trans("off")}", style: Theme.of(context)
style: Theme.of(context) .textTheme
.textTheme .bodyLarge!
.bodyLarge! .copyWith(
.copyWith( color: Colors.black,
color: Colors.black, fontSize: 13,
fontSize: 13, ),
), ),
), ],
],
),
), ),
), ),
), ),
],
),
),
),
Container(
margin: const EdgeInsets.only(top: 2, bottom: 2),
child: Text(
product!.name!,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(fontSize: 15),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Flexible(
child: Container(
padding: EdgeInsets.only(top: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
AutoSizeText(
"${formatStringCurrency(total: product!.price)} ",
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(fontWeight: FontWeight.w800),
textAlign: TextAlign.left,
), ),
if (product!.onSale! && product!.type != "variable") ],
RichText(
text: TextSpan(children: [
TextSpan(
text: '${trans("Was")}: ',
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(
fontSize: 11,
),
),
TextSpan(
text: formatStringCurrency(
total: product!.regularPrice,
),
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(
decoration: TextDecoration.lineThrough,
color: Colors.grey,
fontSize: 11,
),
),
]),
),
].toList(),
),
), ),
), ),
], ),
), Container(
margin: const EdgeInsets.only(top: 2, bottom: 2),
child: Text(
product!.name!,
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(fontSize: 15),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
Container(
padding: EdgeInsets.only(top: 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
AutoSizeText(
"${formatStringCurrency(total: product!.price)} ",
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(fontWeight: FontWeight.w800),
textAlign: TextAlign.left,
),
if (product!.onSale! && product!.type != "variable")
RichText(
text: TextSpan(children: [
TextSpan(
text: '${trans("Was")}: ',
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(
fontSize: 11,
),
),
TextSpan(
text: formatStringCurrency(
total: product!.regularPrice,
),
style: Theme.of(context)
.textTheme
.bodyLarge!
.copyWith(
decoration: TextDecoration.lineThrough,
color: Colors.grey,
fontSize: 11,
),
),
]),
),
].toList(),
),
),
],
), ),
onTap: () => onTap != null
? onTap!(product)
: Navigator.pushNamed(context, "/product-detail",
arguments: product),
), ),
onTap: () => onTap != null
? onTap!(product)
: Navigator.pushNamed(context, "/product-detail",
arguments: product),
); );
} }
} }

View File

@ -189,10 +189,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: device_info_plus name: device_info_plus
sha256: "9b1a0c32b2a503f8fe9f8764fac7b5fcd4f6bd35d8f49de5350bccf9e2a33b8a" sha256: "499c61743e13909c13374a8c209075385858c614b9c0f2487b5f9995eeaf7369"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.0" version: "9.0.1"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -209,6 +209,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.2" version: "5.1.2"
eventify:
dependency: transitive
description:
name: eventify
sha256: b829429f08586cc2001c628e7499e3e3c2493a1d895fd73b00ecb23351aa5a66
url: "https://pub.dev"
source: hosted
version: "1.0.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -407,10 +415,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_stripe name: flutter_stripe
sha256: "95f3c4b907493ff5cdd6b3cdeda03bb59c2bc409d0c0bfb44db948374f9c3595" sha256: "51c3ab5f7a705d864d719eb13882abbb3964c4f61983a13af6dc56607537b1e4"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.1" version: "9.2.0"
flutter_styled_toast: flutter_styled_toast:
dependency: transitive dependency: transitive
description: description:
@ -453,6 +461,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.10.1" version: "0.10.1"
fluttertoast:
dependency: transitive
description:
name: fluttertoast
sha256: "474f7d506230897a3cd28c965ec21c5328ae5605fc9c400cd330e9e9d6ac175c"
url: "https://pub.dev"
source: hosted
version: "8.2.2"
freezed_annotation: freezed_annotation:
dependency: transitive dependency: transitive
description: description:
@ -481,10 +497,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: google_fonts name: google_fonts
sha256: "6b6f10f0ce3c42f6552d1c70d2c28d764cf22bb487f50f66cca31dcd5194f4d6" sha256: "2776c66b3e97c6cdd58d1bd3281548b074b64f1fd5c8f82391f7456e38849567"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.4" version: "4.0.5"
html: html:
dependency: "direct main" dependency: "direct main"
description: description:
@ -494,13 +510,13 @@ packages:
source: hosted source: hosted
version: "0.15.3" version: "0.15.3"
http: http:
dependency: transitive dependency: "direct overridden"
description: description:
name: http name: http
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" sha256: "4c3f04bfb64d3efd508d06b41b825542f08122d30bda4933fb95c069d22a4fa3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.6" version: "1.0.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
@ -601,18 +617,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: nylo_framework name: nylo_framework
sha256: "89cd06e70cd5e402e16174385bcbe24cb4954fc4ce2e6de30e774e5a19fd6b56" sha256: f9960dce938d1046166cc97f7ab613638d7e4f45e6e2a9b30e7d2b004d1d833d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "5.0.2"
nylo_support: nylo_support:
dependency: transitive dependency: transitive
description: description:
name: nylo_support name: nylo_support
sha256: "72228f50a1e37bc2e3c27dfe28ce72b7f72aa120829fb83b8c0d15f6f15c074b" sha256: "011a1614b2440ffcbac821e6624ca25355e304af6c8b5c298203bbbe547da00e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "5.1.2"
octo_image: octo_image:
dependency: transitive dependency: transitive
description: description:
@ -633,10 +649,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: d39e8fbff4c5aef4592737e25ad6ac500df006ce7a7a8e1f838ce1256e167542 sha256: "28386bbe89ab5a7919a47cea99cdd1128e5a6e0bbd7eaafe20440ead84a15de3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.0.1"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -773,6 +789,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
razorpay_flutter:
dependency: "direct main"
description:
name: razorpay_flutter
sha256: d73a536032f6939f0a6706cff958904d471eb1acb3dc957c8cc4e1628f0fbc28
url: "https://pub.dev"
source: hosted
version: "1.3.5"
recase: recase:
dependency: transitive dependency: transitive
description: description:
@ -918,10 +942,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: stripe_ios name: stripe_ios
sha256: "1ce3922c9e9fd2e3ced6b9d349966fa19074794eec1c9bac3cec1bca53e98c85" sha256: e397609a5083b79706814342b40a2a58f1b97ecab2b9d6cae8d8e9f59646fc8c
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.0" version: "9.2.1"
stripe_platform_interface: stripe_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -1118,10 +1142,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: woosignal name: woosignal
sha256: "67d6962b9b38e0da217bc136ddfd76dea7f9e876905f8b196be49f0f6b83e922" sha256: "985313603ad26dbb48420ce1b9029ebec7b6681861bab094c5f89d1710281ac3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.0" version: "3.5.0"
wp_json_api: wp_json_api:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -1,7 +1,7 @@
# Official WooSignal App Template for WooCommerce # Official WooSignal App Template for WooCommerce
# Label StoreMax # Label StoreMax
# Version: 6.6.0 # Version: 6.6.1
# Author: Anthony Gordon # Author: Anthony Gordon
# Homepage: https://woosignal.com # Homepage: https://woosignal.com
# Documentation: https://woosignal.com/docs/app/label-storemax # Documentation: https://woosignal.com/docs/app/label-storemax
@ -26,14 +26,14 @@ environment:
flutter: ">=3.0.0" flutter: ">=3.0.0"
dependencies: dependencies:
google_fonts: ^4.0.3 google_fonts: ^4.0.5
analyzer: ^5.12.0 analyzer: ^5.12.0
intl: ^0.18.0 intl: ^0.18.0
nylo_framework: ^5.0.0 nylo_framework: ^5.0.2
woosignal: ^3.4.0 woosignal: ^3.5.0
wp_json_api: ^3.3.2 wp_json_api: ^3.3.2
cached_network_image: ^3.2.3 cached_network_image: ^3.2.3
package_info_plus: ^4.0.0 package_info_plus: ^4.0.1
money_formatter: ^0.0.3 money_formatter: ^0.0.3
flutter_web_browser: ^0.17.1 flutter_web_browser: ^0.17.1
webview_flutter: ^3.0.4 webview_flutter: ^3.0.4
@ -61,7 +61,11 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.5 cupertino_icons: ^1.0.5
collection: ^1.15.0 collection: ^1.15.0
flutter_stripe: ^9.1.1 flutter_stripe: ^9.2.0
razorpay_flutter: ^1.3.5
dependency_overrides:
http: ^1.0.0
dev_dependencies: dev_dependencies:
flutter_launcher_icons: ^0.13.1 flutter_launcher_icons: ^0.13.1

View File

@ -4,7 +4,7 @@
# WooCommerce App: Label StoreMax # WooCommerce App: Label StoreMax
### Label StoreMax - v6.6.0 ### Label StoreMax - v6.6.1
[Official WooSignal WooCommerce App](https://woosignal.com) [Official WooSignal WooCommerce App](https://woosignal.com)