Merge pull request #35 from woosignal/master

v6.0.0 updates
This commit is contained in:
Anthony Gordon 2022-05-19 21:53:02 +01:00 committed by GitHub
commit 7a77a0cb16
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
127 changed files with 2238 additions and 2130 deletions

View File

@ -1,3 +1,11 @@
## [6.0.0] - 2022-05-19
* Migrate to Nylo 3.x
* Null safety
* Min dart version 2.17
* Refactor product detail screen
* Pubspec.yaml dependency updates
## [5.8.0] - 2022-03-29
* Add phone number to customer input form

View File

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

View File

@ -61,5 +61,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
</dict>
</plist>

View File

@ -8,7 +8,7 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:nylo_support/controllers/controller.dart';
import 'package:nylo_framework/nylo_framework.dart';
/// Base Controller for the Nylo
/// See more on controllers here - https://nylo.dev/docs/2.x/controllers

View File

@ -7,8 +7,6 @@
// 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/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/order.dart';
@ -17,9 +15,9 @@ class CustomerOrdersLoaderController
CustomerOrdersLoaderController();
Future<void> loadOrders(
{@required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish,
@required String userId}) async {
{required bool Function(bool hasProducts) hasResults,
required void Function() didFinish,
required String userId}) async {
await load(
hasResults: hasResults,
didFinish: didFinish,

View File

@ -12,10 +12,8 @@ import 'controller.dart';
import 'package:flutter/widgets.dart';
class LeaveReviewController extends Controller {
@override
construct(BuildContext context) {
super.construct(context);
}
}
}

View File

@ -8,7 +8,6 @@
// 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/cupertino.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/products.dart';
@ -18,19 +17,19 @@ class ProductCategorySearchLoaderController
ProductCategorySearchLoaderController();
Future<void> loadProducts(
{@required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish,
@required ProductCategory productCategory}) async {
{required bool Function(bool hasProducts) hasResults,
required void Function() didFinish,
required ProductCategory? productCategory}) async {
await load(
hasResults: hasResults,
didFinish: didFinish,
apiQuery: (api) => api.getProducts(
perPage: 50,
category: productCategory.id.toString(),
page: page,
status: "publish",
stockStatus: "instock",
),
hasResults: hasResults,
didFinish: didFinish,
apiQuery: (api) => api.getProducts(
perPage: 50,
category: productCategory!.id.toString(),
page: page,
status: "publish",
stockStatus: "instock",
),
);
}
}

View File

@ -16,44 +16,46 @@ import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart';
import 'package:woosignal/models/response/product_variation.dart'
as ws_product_variation;
as ws_product_variation;
import 'controller.dart';
class ProductDetailController extends Controller {
int quantity = 1;
Product product;
Product? product;
@override
construct(BuildContext context) {
super.construct(context);
product = data() as Product;
product = data() as Product?;
}
viewExternalProduct() {
if (product.externalUrl != null && product.externalUrl.isNotEmpty) {
openBrowserTab(url: product.externalUrl);
if (product!.externalUrl != null && product!.externalUrl!.isNotEmpty) {
openBrowserTab(url: product!.externalUrl!);
}
}
itemAddToCart({@required CartLineItem cartLineItem, @required Function onSuccess}) async {
itemAddToCart(
{required CartLineItem cartLineItem, required Function onSuccess}) async {
await Cart.getInstance.addToCart(cartLineItem: cartLineItem);
showStatusAlert(context,
title: trans("Success"),
subtitle: trans("Added to cart"),
duration: 1,
icon: Icons.add_shopping_cart,
showStatusAlert(
context,
title: trans("Success"),
subtitle: trans("Added to cart"),
duration: 1,
icon: Icons.add_shopping_cart,
);
onSuccess();
}
addQuantityTapped({@required Function onSuccess}) {
if (product.manageStock != null && product.manageStock == true) {
if (quantity >= product.stockQuantity) {
showToastNotification(context,
addQuantityTapped({required Function onSuccess}) {
if (product!.manageStock != null && product!.manageStock == true) {
if (quantity >= product!.stockQuantity!) {
showToastNotification(context!,
title: trans("Maximum quantity reached"),
description:
"${trans("Sorry, only")} ${product.stockQuantity} ${trans("left")}",
"${trans("Sorry, only")} ${product!.stockQuantity} ${trans("left")}",
style: ToastNotificationStyleType.INFO);
return;
}
@ -64,14 +66,16 @@ class ProductDetailController extends Controller {
}
}
removeQuantityTapped({@required Function onSuccess}) {
removeQuantityTapped({required Function onSuccess}) {
if ((quantity - 1) >= 1) {
quantity--;
onSuccess();
}
}
toggleWishList({@required Function onSuccess, @required WishlistAction wishlistAction}) async {
toggleWishList(
{required Function onSuccess,
required WishlistAction wishlistAction}) async {
String subtitleMsg;
if (wishlistAction == WishlistAction.remove) {
await removeWishlistProduct(product: product);
@ -80,7 +84,8 @@ class ProductDetailController extends Controller {
await saveWishlistProduct(product: product);
subtitleMsg = trans("This product has been added to your wishlist");
}
showStatusAlert(context,
showStatusAlert(
context,
title: trans("Success"),
subtitle: subtitleMsg,
icon: Icons.favorite,
@ -90,18 +95,18 @@ class ProductDetailController extends Controller {
onSuccess();
}
ws_product_variation.ProductVariation findProductVariation(
{@required Map<int, dynamic> tmpAttributeObj,
@required List<ws_product_variation.ProductVariation> productVariations}) {
ws_product_variation.ProductVariation tmpProductVariation;
ws_product_variation.ProductVariation? findProductVariation(
{required Map<int, dynamic> tmpAttributeObj,
required List<ws_product_variation.ProductVariation> productVariations}) {
ws_product_variation.ProductVariation? tmpProductVariation;
Map<String, dynamic> tmpSelectedObj = {};
Map<String?, dynamic> tmpSelectedObj = {};
for (var attributeObj in tmpAttributeObj.values) {
tmpSelectedObj[attributeObj["name"]] = attributeObj["value"];
}
for (var productVariation in productVariations) {
Map<String, dynamic> tmpVariations = {};
Map<String?, dynamic> tmpVariations = {};
for (var attr in productVariation.attributes) {
tmpVariations[attr.name] = attr.option;
@ -114,4 +119,4 @@ class ProductDetailController extends Controller {
return tmpProductVariation;
}
}
}

View File

@ -8,18 +8,16 @@
// 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/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/products.dart';
class ProductLoaderController extends WooSignalApiLoaderController<Product> {
ProductLoaderController();
Future<void> loadProducts({
@required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish,
List<int> productIds = const []
}) async {
Future<void> loadProducts(
{required bool Function(bool hasProducts) hasResults,
required void Function() didFinish,
List<int>? productIds = const []}) async {
await load(
hasResults: hasResults,
didFinish: didFinish,

View File

@ -12,11 +12,8 @@ import 'controller.dart';
import 'package:flutter/widgets.dart';
class ProductReviewsController extends Controller {
@override
construct(BuildContext context) {
super.construct(context);
}
}
}

View File

@ -8,27 +8,27 @@
// 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/cupertino.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/products.dart';
class ProductReviewsLoaderController extends WooSignalApiLoaderController<ProductReview> {
class ProductReviewsLoaderController
extends WooSignalApiLoaderController<ProductReview> {
ProductReviewsLoaderController();
Future<void> loadProductReviews({
@required Product product,
@required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish,
required Product? product,
required bool Function(bool hasProducts) hasResults,
required void Function() didFinish,
}) async {
await load(
hasResults: hasResults,
didFinish: didFinish,
apiQuery: (api) => api.getProductReviews(
product: [product.id],
perPage: 50,
page: page,
status: "approved",
));
product: [product!.id!],
perPage: 50,
page: page,
status: "approved",
));
}
}

View File

@ -8,7 +8,6 @@
// 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/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/products.dart';
@ -17,9 +16,9 @@ class ProductSearchLoaderController
ProductSearchLoaderController();
Future<void> loadProducts(
{@required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish,
@required String search}) async {
{required bool Function(bool hasProducts) hasResults,
required void Function() didFinish,
required String? search}) async {
await load(
hasResults: hasResults,
didFinish: didFinish,

View File

@ -8,7 +8,6 @@
// 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/cupertino.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:woosignal/woosignal.dart';
@ -20,15 +19,15 @@ class WooSignalApiLoaderController<T> {
WooSignalApiLoaderController();
Future<void> load(
{@required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish,
@required Future<List<T>> Function(WooSignal query) apiQuery}) async {
{required bool Function(bool hasProducts) hasResults,
required void Function() didFinish,
required Future<List<T>> Function(WooSignal query) apiQuery}) async {
if (_waitForNextRequest) {
return;
}
_waitForNextRequest = true;
List<T> apiResults = await appWooSignal((api) => apiQuery(api));
List<T> apiResults = await (appWooSignal((api) => apiQuery(api)));
if (!hasResults(apiResults.isNotEmpty)) {
return;
@ -41,9 +40,7 @@ class WooSignalApiLoaderController<T> {
didFinish();
}
List<T> getResults() {
return _results;
}
List<T> getResults() => _results;
void clear() {
_results = [];

View File

@ -0,0 +1,15 @@
import 'package:nylo_framework/nylo_framework.dart';
class LoginEvent implements NyEvent {
@override
final listeners = {
DefaultListener: DefaultListener(),
};
}
class DefaultListener extends NyListener {
@override
handle(dynamic event) async {
// handle the payload from event
}
}

View File

@ -0,0 +1,13 @@
import 'package:nylo_framework/nylo_framework.dart';
class LogoutEvent implements NyEvent {
@override
final listeners = {DefaultListener: DefaultListener()};
}
class DefaultListener extends NyListener {
@override
handle(dynamic event) async {
// handle the payload from event
}
}

View File

@ -11,9 +11,9 @@
import 'package:flutter_app/app/models/customer_address.dart';
class BillingDetails {
CustomerAddress billingAddress;
CustomerAddress shippingAddress;
bool rememberDetails;
CustomerAddress? billingAddress;
CustomerAddress? shippingAddress;
bool? rememberDetails;
void initSession() {
billingAddress = CustomerAddress();

View File

@ -15,5 +15,8 @@ class BottomNavItem {
BottomNavigationBarItem bottomNavigationBarItem;
Widget tabWidget;
BottomNavItem({this.id, this.bottomNavigationBarItem, this.tabWidget});
BottomNavItem(
{required this.id,
required this.bottomNavigationBarItem,
required this.tabWidget});
}

View File

@ -10,14 +10,14 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/app/models/shipping_type.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/shipping_method.dart';
import 'package:woosignal/models/response/tax_rate.dart';
@ -27,7 +27,7 @@ class Cart {
Future<List<CartLineItem>> getCart() async {
List<CartLineItem> cartLineItems = [];
String currentCartArrJSON = await NyStorage.read(SharedKey.cart);
String? currentCartArrJSON = await (NyStorage.read(SharedKey.cart));
if (currentCartArrJSON != null) {
cartLineItems = (jsonDecode(currentCartArrJSON) as List<dynamic>)
@ -38,15 +38,14 @@ class Cart {
return cartLineItems;
}
Future addToCart({@required CartLineItem cartLineItem}) async {
Future addToCart({required CartLineItem cartLineItem}) async {
List<CartLineItem> cartLineItems = await getCart();
if (cartLineItem.variationId != null &&
cartLineItems.firstWhere(
(i) => (i.productId == cartLineItem.productId &&
cartLineItems.firstWhereOrNull((i) =>
(i.productId == cartLineItem.productId &&
i.variationId == cartLineItem.variationId &&
i.variationOptions == cartLineItem.variationOptions),
orElse: () => null) !=
i.variationOptions == cartLineItem.variationOptions)) !=
null) {
cartLineItems.removeWhere((item) =>
item.productId == cartLineItem.productId &&
@ -55,8 +54,8 @@ class Cart {
}
if (cartLineItem.variationId == null &&
cartLineItems.firstWhere((i) => i.productId == cartLineItem.productId,
orElse: () => null) !=
cartLineItems.firstWhereOrNull(
(i) => i.productId == cartLineItem.productId) !=
null) {
cartLineItems
.removeWhere((item) => item.productId == cartLineItem.productId);
@ -80,7 +79,7 @@ class Cart {
total = total - double.parse(discountAmount);
}
if (withFormat != null && withFormat == true) {
if (withFormat == true) {
return formatDoubleCurrency(total: total);
}
return total.toStringAsFixed(2);
@ -92,15 +91,15 @@ class Cart {
for (var cartItem in cartLineItems) {
subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity);
}
if (withFormat != null && withFormat == true) {
if (withFormat == true) {
return formatDoubleCurrency(total: subtotal);
}
return subtotal.toStringAsFixed(2);
}
updateQuantity(
{@required CartLineItem cartLineItem,
@required int incrementQuantity}) async {
{required CartLineItem cartLineItem,
required int incrementQuantity}) async {
List<CartLineItem> cartLineItems = await getCart();
List<CartLineItem> tmpCartItem = [];
for (var cartItem in cartLineItems) {
@ -124,7 +123,7 @@ class Cart {
.join(",");
}
removeCartItemForIndex({@required int index}) async {
removeCartItemForIndex({required int index}) async {
List<CartLineItem> cartLineItems = await getCart();
cartLineItems.removeAt(index);
await saveCartToPref(cartLineItems: cartLineItems);
@ -132,12 +131,12 @@ class Cart {
clear() async => NyStorage.delete(SharedKey.cart);
saveCartToPref({@required List<CartLineItem> cartLineItems}) async {
saveCartToPref({required List<CartLineItem> cartLineItems}) async {
String json = jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
await NyStorage.store(SharedKey.cart, json);
}
Future<String> taxAmount(TaxRate taxRate) async {
Future<String> taxAmount(TaxRate? taxRate) async {
double subtotal = 0;
double shippingTotal = 0;
@ -150,7 +149,7 @@ class Cart {
cartItems.where((c) => c.taxStatus == 'taxable').toList();
double cartSubtotal = 0;
if (AppHelper.instance.appConfig.productPricesIncludeTax == 1 &&
if (AppHelper.instance.appConfig!.productPricesIncludeTax == 1 &&
taxableCartLines.isNotEmpty) {
cartSubtotal = taxableCartLines
.map<double>((m) => parseWcPrice(m.subtotal) * m.quantity)
@ -163,22 +162,20 @@ class Cart {
subtotal = cartSubtotal;
ShippingType shippingType = CheckoutSession.getInstance.shippingType;
ShippingType? shippingType = CheckoutSession.getInstance.shippingType;
if (shippingType != null) {
switch (shippingType.methodId) {
case "flat_rate":
FlatRate flatRate = (shippingType.object as FlatRate);
if (flatRate.taxable != null && flatRate.taxable) {
shippingTotal += parseWcPrice(
shippingType.cost == null || shippingType.cost == ""
? "0"
: shippingType.cost);
if (flatRate.taxable != null && flatRate.taxable!) {
shippingTotal +=
parseWcPrice(shippingType.cost == "" ? "0" : shippingType.cost);
}
break;
case "local_pickup":
LocalPickup localPickup = (shippingType.object as LocalPickup);
if (localPickup.taxable != null && localPickup.taxable) {
if (localPickup.taxable != null && localPickup.taxable!) {
shippingTotal += parseWcPrice(
(localPickup.cost == null || localPickup.cost == ""
? "0"
@ -192,10 +189,10 @@ class Cart {
double total = 0;
if (subtotal != 0) {
total += ((parseWcPrice(taxRate.rate) * subtotal) / 100);
total += ((parseWcPrice(taxRate!.rate) * subtotal) / 100);
}
if (shippingTotal != 0) {
total += ((parseWcPrice(taxRate.rate) * shippingTotal) / 100);
total += ((parseWcPrice(taxRate!.rate) * shippingTotal) / 100);
}
return (total).toStringAsFixed(2);
}
@ -213,10 +210,10 @@ class Cart {
for (var cartItem in cartLineItems) {
bool canContinue = true;
if (checkoutSession.coupon.excludedProductCategories.isNotEmpty) {
if (checkoutSession.coupon!.excludedProductCategories!.isNotEmpty) {
for (var excludedProductCategory
in checkoutSession.coupon.excludedProductCategories) {
if (cartItem.categories
in checkoutSession.coupon!.excludedProductCategories!) {
if (cartItem.categories!
.map((category) => category.id)
.contains(excludedProductCategory)) {
canContinue = false;
@ -225,10 +222,10 @@ class Cart {
}
}
if (checkoutSession.coupon.productCategories.isNotEmpty) {
if (checkoutSession.coupon!.productCategories!.isNotEmpty) {
for (var productCategories
in checkoutSession.coupon.productCategories) {
if (cartItem.categories
in checkoutSession.coupon!.productCategories!) {
if (cartItem.categories!
.map((category) => category.id)
.contains(productCategories) ==
false) {
@ -242,41 +239,41 @@ class Cart {
continue;
}
if (checkoutSession.coupon.excludeSaleItems == true &&
if (checkoutSession.coupon!.excludeSaleItems == true &&
cartItem.onSale == true) {
continue;
}
if (checkoutSession.coupon.excludedProductIds.isNotEmpty &&
checkoutSession.coupon.excludedProductIds
if (checkoutSession.coupon!.excludedProductIds!.isNotEmpty &&
checkoutSession.coupon!.excludedProductIds!
.contains(cartItem.productId)) {
continue;
}
if (checkoutSession.coupon.productIds.isNotEmpty &&
!checkoutSession.coupon.productIds.contains(cartItem.productId)) {
if (checkoutSession.coupon!.productIds!.isNotEmpty &&
!checkoutSession.coupon!.productIds!.contains(cartItem.productId)) {
continue;
}
subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity);
eligibleCartLineItems.add(cartItem);
}
String discountType = checkoutSession.coupon.discountType;
String amount = checkoutSession.coupon.amount;
String? discountType = checkoutSession.coupon!.discountType;
String? amount = checkoutSession.coupon!.amount;
// Percentage
if (discountType == 'percent') {
return ((subtotal * double.parse(amount)) / 100).toStringAsFixed(2);
return ((subtotal * double.parse(amount!)) / 100).toStringAsFixed(2);
}
// Fixed cart
if (discountType == 'fixed_cart') {
return (double.parse(amount)).toStringAsFixed(2);
return (double.parse(amount!)).toStringAsFixed(2);
}
// Fixed product
if (discountType == 'fixed_product') {
return (eligibleCartLineItems.length * double.parse(amount))
return (eligibleCartLineItems.length * double.parse(amount!))
.toStringAsFixed(2);
}
return "0";

View File

@ -14,24 +14,24 @@ import 'package:woosignal/models/response/product_variation.dart';
import 'package:woosignal/models/response/products.dart' as ws_product;
class CartLineItem {
String name;
int productId;
int variationId;
int quantity;
bool isManagedStock;
int stockQuantity;
String shippingClassId;
String taxStatus;
String taxClass;
bool shippingIsTaxable;
String subtotal;
String total;
String imageSrc;
String variationOptions;
List<ws_product.Category> categories;
bool onSale;
String stockStatus;
Object metaData = {};
String? name;
int? productId;
int? variationId;
int quantity = 0;
bool? isManagedStock;
int? stockQuantity;
String? shippingClassId;
String? taxStatus;
String? taxClass;
bool? shippingIsTaxable;
String? subtotal;
String? total;
String? imageSrc;
String? variationOptions;
List<ws_product.Category>? categories;
bool? onSale;
String? stockStatus;
Object? metaData = {};
CartLineItem(
{this.name,
@ -39,7 +39,7 @@ class CartLineItem {
this.variationId,
this.isManagedStock,
this.stockQuantity,
this.quantity,
this.quantity = 1,
this.stockStatus,
this.shippingClassId,
this.taxStatus,
@ -57,10 +57,11 @@ class CartLineItem {
return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2);
}
CartLineItem.fromProduct({int quantityAmount, ws_product.Product product}) {
CartLineItem.fromProduct(
{int? quantityAmount, required ws_product.Product product}) {
name = product.name;
productId = product.id;
quantity = quantityAmount;
quantity = quantityAmount ?? 1;
taxStatus = product.taxStatus;
shippingClassId = product.shippingClassId.toString();
subtotal = product.price;
@ -76,21 +77,21 @@ class CartLineItem {
}
CartLineItem.fromProductVariation(
{int quantityAmount,
List<String> options,
ws_product.Product product,
ProductVariation productVariation}) {
String imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE");
{int? quantityAmount,
required List<String> options,
required ws_product.Product product,
required ProductVariation productVariation}) {
String? imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE");
if (product.images.isNotEmpty) {
imageSrc = product.images.first.src;
}
if (productVariation.image != null) {
imageSrc = productVariation.image.src;
imageSrc = productVariation.image!.src;
}
name = product.name;
productId = product.id;
variationId = productVariation.id;
quantity = quantityAmount;
quantity = quantityAmount ?? 1;
taxStatus = productVariation.taxStatus;
shippingClassId = productVariation.shippingClassId.toString();
subtotal = productVariation.price;
@ -145,7 +146,7 @@ class CartLineItem {
'shipping_is_taxable': shippingIsTaxable,
'image_src': imageSrc,
'categories': categories != null
? categories.map((e) => e.toJson()).toList()
? categories!.map((e) => e.toJson()).toList()
: [],
'variation_options': variationOptions,
'subtotal': subtotal,

View File

@ -16,21 +16,21 @@ import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/models/shipping_type.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/coupon.dart';
import 'package:woosignal/models/response/tax_rate.dart';
class CheckoutSession {
bool shipToDifferentAddress = false;
bool? shipToDifferentAddress = false;
CheckoutSession._privateConstructor();
static final CheckoutSession getInstance =
CheckoutSession._privateConstructor();
BillingDetails billingDetails;
ShippingType shippingType;
PaymentType paymentType;
Coupon coupon;
BillingDetails? billingDetails;
ShippingType? shippingType;
PaymentType? paymentType;
Coupon? coupon;
void initSession() {
billingDetails = BillingDetails();
@ -45,8 +45,8 @@ class CheckoutSession {
}
saveBillingAddress() async {
CustomerAddress customerAddress =
CheckoutSession.getInstance.billingDetails.billingAddress;
CustomerAddress? customerAddress =
CheckoutSession.getInstance.billingDetails!.billingAddress;
if (customerAddress == null) {
return;
@ -56,9 +56,9 @@ class CheckoutSession {
await NyStorage.store(SharedKey.customerBillingDetails, billingAddress);
}
Future<CustomerAddress> getBillingAddress() async {
String strCheckoutDetails =
await NyStorage.read(SharedKey.customerBillingDetails);
Future<CustomerAddress?> getBillingAddress() async {
String? strCheckoutDetails =
await (NyStorage.read(SharedKey.customerBillingDetails));
if (strCheckoutDetails != null && strCheckoutDetails != "") {
return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails));
@ -70,8 +70,8 @@ class CheckoutSession {
await NyStorage.delete(SharedKey.customerBillingDetails);
saveShippingAddress() async {
CustomerAddress customerAddress =
CheckoutSession.getInstance.billingDetails.shippingAddress;
CustomerAddress? customerAddress =
CheckoutSession.getInstance.billingDetails!.shippingAddress;
if (customerAddress == null) {
return;
}
@ -79,9 +79,9 @@ class CheckoutSession {
await NyStorage.store(SharedKey.customerShippingDetails, shippingAddress);
}
Future<CustomerAddress> getShippingAddress() async {
String strCheckoutDetails =
await NyStorage.read(SharedKey.customerShippingDetails);
Future<CustomerAddress?> getShippingAddress() async {
String? strCheckoutDetails =
await (NyStorage.read(SharedKey.customerShippingDetails));
if (strCheckoutDetails != null && strCheckoutDetails != "") {
return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails));
}
@ -91,19 +91,19 @@ class CheckoutSession {
clearShippingAddress() async =>
await NyStorage.delete(SharedKey.customerShippingDetails);
Future<String> total({bool withFormat = false, TaxRate taxRate}) async {
Future<String> total({bool withFormat = false, TaxRate? taxRate}) async {
double totalCart = parseWcPrice(await Cart.getInstance.getTotal());
double totalShipping = 0;
if (shippingType != null && shippingType.object != null) {
switch (shippingType.methodId) {
if (shippingType != null && shippingType!.object != null) {
switch (shippingType!.methodId) {
case "flat_rate":
totalShipping = parseWcPrice(shippingType.cost);
totalShipping = parseWcPrice(shippingType!.cost);
break;
case "free_shipping":
totalShipping = parseWcPrice(shippingType.cost);
totalShipping = parseWcPrice(shippingType!.cost);
break;
case "local_pickup":
totalShipping = parseWcPrice(shippingType.cost);
totalShipping = parseWcPrice(shippingType!.cost);
break;
default:
break;

View File

@ -11,14 +11,14 @@
import 'package:flutter_app/app/models/customer_country.dart';
class CustomerAddress {
String firstName;
String lastName;
String addressLine;
String city;
String postalCode;
String emailAddress;
String phoneNumber;
CustomerCountry customerCountry;
String? firstName;
String? lastName;
String? addressLine;
String? city;
String? postalCode;
String? emailAddress;
String? phoneNumber;
CustomerCountry? customerCountry;
CustomerAddress(
{this.firstName,
@ -27,7 +27,7 @@ class CustomerAddress {
this.city,
this.postalCode,
this.emailAddress,
this.phoneNumber,
this.phoneNumber,
this.customerCountry});
void initAddress() {
@ -42,17 +42,17 @@ class CustomerAddress {
}
bool hasMissingFields() =>
(firstName.isEmpty ||
lastName.isEmpty ||
addressLine.isEmpty ||
city.isEmpty ||
postalCode.isEmpty) ||
(customerCountry.hasState() == true
(firstName!.isEmpty ||
lastName!.isEmpty ||
addressLine!.isEmpty ||
city!.isEmpty ||
postalCode!.isEmpty) ||
(customerCountry!.hasState() == true
? (customerCountry?.state?.name ?? "").isEmpty
: false);
String addressFull() {
List<String> tmpArrAddress = [];
List<String?> tmpArrAddress = [];
if (addressLine != null && addressLine != "") {
tmpArrAddress.add(addressLine);
}
@ -66,13 +66,13 @@ class CustomerAddress {
tmpArrAddress.add(customerCountry?.state?.name);
}
if (customerCountry != null && customerCountry?.name != null) {
tmpArrAddress.add(customerCountry.name);
tmpArrAddress.add(customerCountry!.name);
}
return tmpArrAddress.join(", ");
}
String nameFull() {
List<String> tmpArrName = [];
List<String?> tmpArrName = [];
if (firstName != "") {
tmpArrName.add(firstName);
}
@ -102,15 +102,15 @@ class CustomerAddress {
data['address_line'] = addressLine;
data['city'] = city;
data['postal_code'] = postalCode;
data['state'] = customerCountry.state;
data['country'] = customerCountry.name;
data['state'] = customerCountry!.state;
data['country'] = customerCountry!.name;
if (phoneNumber != null && phoneNumber != "") {
data['phone_number'] = phoneNumber;
}
data['email_address'] = emailAddress;
data['customer_country'] = null;
if (customerCountry != null) {
data['customer_country'] = customerCountry.toJson();
data['customer_country'] = customerCountry!.toJson();
}
return data;
}

View File

@ -11,21 +11,22 @@
import 'package:flutter_app/app/models/default_shipping.dart';
class CustomerCountry {
String countryCode;
String name;
DefaultShippingState state;
String? countryCode;
String? name;
DefaultShippingState? state;
CustomerCountry({this.countryCode, this.name, this.state});
CustomerCountry.fromDefaultShipping({DefaultShipping defaultShipping}) {
CustomerCountry.fromDefaultShipping(
{required DefaultShipping defaultShipping}) {
countryCode = defaultShipping.code;
name = defaultShipping.country;
if ((defaultShipping.states?.length ?? 0) == 1) {
if ((defaultShipping.states.length) == 1) {
state = defaultShipping.states.first;
}
}
CustomerCountry.fromJson(Map<String, dynamic> json) {
CustomerCountry.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return;
}
@ -40,7 +41,7 @@ class CustomerCountry {
}
}
bool hasState() => (state != null && state.name != null ? true : false);
bool hasState() => (state != null && state!.name != null ? true : false);
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
@ -48,7 +49,7 @@ class CustomerCountry {
data['name'] = name;
data['state'] = null;
if (state != null) {
data['state'] = state.toJson();
data['state'] = state!.toJson();
}
return data;
}

View File

@ -7,22 +7,19 @@
// 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/cupertino.dart';
class DefaultShipping {
String code;
String country;
String? country;
List<DefaultShippingState> states;
DefaultShipping(
{@required this.code, @required this.country, @required this.states});
{required this.code, required this.country, required this.states});
}
class DefaultShippingState {
String code;
String name;
String? code;
String? name;
DefaultShippingState({@required this.code, @required this.name});
DefaultShippingState({required this.code, required this.name});
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};

View File

@ -8,8 +8,6 @@
// 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/cupertino.dart';
class PaymentType {
int id;
String name;
@ -18,9 +16,9 @@ class PaymentType {
Function pay;
PaymentType(
{@required this.id,
@required this.name,
@required this.desc,
@required this.assetImage,
@required this.pay});
{required this.id,
required this.name,
required this.desc,
required this.assetImage,
required this.pay});
}

View File

@ -7,22 +7,20 @@
// 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/cupertino.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:woosignal/models/response/shipping_method.dart';
class ShippingType {
String methodId;
String? methodId;
String cost;
String minimumValue;
String? minimumValue;
dynamic object;
ShippingType(
{@required this.methodId,
{required this.methodId,
this.object,
@required this.cost,
@required this.minimumValue});
required this.cost,
required this.minimumValue});
Map<String, dynamic> toJson() => {
'methodId': methodId,
@ -31,24 +29,24 @@ class ShippingType {
'minimumValue': minimumValue
};
String getTotal({bool withFormatting = false}) {
String? getTotal({bool withFormatting = false}) {
if (object != null) {
switch (methodId) {
case "flat_rate":
FlatRate flatRate = (object as FlatRate);
FlatRate? flatRate = (object as FlatRate?);
return (withFormatting == true
? formatStringCurrency(total: cost)
: flatRate.cost);
: flatRate!.cost);
case "free_shipping":
FreeShipping freeShipping = (object as FreeShipping);
FreeShipping? freeShipping = (object as FreeShipping?);
return (withFormatting == true
? formatStringCurrency(total: cost)
: freeShipping.cost);
: freeShipping!.cost);
case "local_pickup":
LocalPickup localPickup = (object as LocalPickup);
LocalPickup? localPickup = (object as LocalPickup?);
return (withFormatting == true
? formatStringCurrency(total: cost)
: localPickup.cost);
: localPickup!.cost);
default:
return "0";
}
@ -56,7 +54,7 @@ class ShippingType {
return "0";
}
String getTitle() {
String? getTitle() {
if (object != null) {
switch (methodId) {
case "flat_rate":
@ -75,7 +73,7 @@ class ShippingType {
return "";
}
Map<String, dynamic> toShippingLineFee() {
Map<String, dynamic>? toShippingLineFee() {
if (object != null) {
Map<String, dynamic> tmpShippingLinesObj = {};

View File

@ -8,11 +8,11 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
class User extends Storable {
String userId;
String token;
String? userId;
String? token;
User();
User.fromUserAuthResponse({this.userId, this.token});

View File

@ -1,11 +1,29 @@
// Label StoreMax
//
// Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved.
//
import 'package:flutter/material.dart';
import 'package:flutter_app/app/networking/dio/base_api_service.dart';
import 'package:flutter_app/app/networking/dio/interceptors/logging_interceptor.dart';
import 'package:nylo_framework/nylo_framework.dart';
// 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.
/*
|--------------------------------------------------------------------------
| ApiService
| -------------------------------------------------------------------------
| Define your API endpoints
| Learn more https://nylo.dev/docs/3.x/networking
|--------------------------------------------------------------------------
*/
class ApiService {}
class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext);
@override
String get baseUrl => getEnv('API_BASE_URL');
@override
final interceptors = {LoggingInterceptor: LoggingInterceptor()};
Future<dynamic> fetchTestData() async {
return await network(
request: (request) => request.get("/endpoint-path"),
);
}
}

View File

@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/app/networking/dio/interceptors/logging_interceptor.dart';
import 'package:flutter_app/config/decoders.dart';
import 'package:nylo_framework/networking/ny_base_networking.dart';
class BaseApiService extends NyBaseApiService {
BaseApiService(BuildContext? context) : super(context);
/// Map decoders to modelDecoders
@override
final Map<Type, dynamic> decoders = modelDecoders;
/// Default interceptors
@override
final interceptors = {LoggingInterceptor: LoggingInterceptor()};
}

View File

@ -0,0 +1,22 @@
import 'package:nylo_framework/nylo_framework.dart';
class BearerAuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
String? userToken = Backpack.instance.read('user_token');
if (userToken != null) {
options.headers.addAll({"Authorization": "Bearer $userToken"});
}
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
handler.next(response);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
handler.next(err);
}
}

View File

@ -0,0 +1,32 @@
import 'dart:developer';
import 'package:nylo_framework/nylo_framework.dart';
class LoggingInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (getEnv('APP_DEBUG') == true) {
print('REQUEST[${options.method}] => PATH: ${options.path}');
}
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
if (getEnv('APP_DEBUG') == true) {
print(
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
print('DATA: ${response.requestOptions.path}');
log(response.data.toString());
}
handler.next(response);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
if (getEnv('APP_DEBUG') == true) {
print(
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
}
handler.next(err);
}
}

View File

@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:flutter_app/config/localization.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/woosignal.dart';
import 'package:wp_json_api/wp_json_api.dart';
class AppProvider implements NyProvider {
boot(Nylo nylo) async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
await WooSignal.instance
.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG'));
// Notifications
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
///
/// FirebaseMessaging messaging = FirebaseMessaging.instance;
///
/// NotificationSettings settings = await messaging.requestPermission(
/// alert: true,
/// announcement: false,
/// badge: true,
/// carPlay: false,
/// criticalAlert: false,
/// provisional: false,
/// sound: true,
/// );
///
/// if (settings.authorizationStatus == AuthorizationStatus.authorized) {
/// String token = await messaging.getToken();
/// WooSignal.instance.setFcmToken(token);
/// }
AppHelper.instance.appConfig = WooSignalApp();
AppHelper.instance.appConfig!.themeFont = "Poppins";
AppHelper.instance.appConfig!.themeColors = {
'light': {
'background': '0xFFFFFFFF',
'primary_text': '0xFF000000',
'button_background': '0xFF529cda',
'button_text': '0xFFFFFFFF',
'app_bar_background': '0xFFFFFFFF',
'app_bar_text': '0xFF3a3d40',
},
'dark': {
'background': '0xFF212121',
'primary_text': '0xFFE1E1E1',
'button_background': '0xFFFFFFFF',
'button_text': '0xFF232c33',
'app_bar_background': '0xFF2C2C2C',
'app_bar_text': '0xFFFFFFFF',
}
};
// WooSignal Setup
WooSignalApp? wooSignalApp = await (appWooSignal((api) => api.getApp()));
Locale locale = Locale('en');
if (wooSignalApp != null) {
AppHelper.instance.appConfig = wooSignalApp;
if (wooSignalApp.wpLoginEnabled == 1) {
WPJsonAPI.instance.initWith(
baseUrl: wooSignalApp.wpLoginBaseUrl!,
shouldDebug: getEnv('APP_DEBUG'),
wpJsonPath: wooSignalApp.wpLoginWpApiPath!,
);
}
if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null &&
wooSignalApp.locale != null) {
locale = Locale(wooSignalApp.locale!);
} else {
locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en'));
}
}
/// NyLocalization
await NyLocalization.instance.init(
localeType: localeType,
languageCode: locale.languageCode,
languagesList: languagesList,
assetsDirectory: assetsDirectory,
valuesAsMap: valuesAsMap);
return nylo;
}
}

View File

@ -21,11 +21,11 @@ import 'package:woosignal/models/response/order.dart';
import 'package:woosignal/models/response/tax_rate.dart';
cashOnDeliveryPay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
try {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: false);
Order order = await appWooSignal((api) => api.createOrder(orderWC));
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
if (order != null) {
Navigator.pushNamed(context, "/checkout-status", arguments: order);

View File

@ -0,0 +1,11 @@
import 'package:flutter_app/config/events.dart';
import 'package:nylo_framework/nylo_framework.dart';
class EventProvider implements NyProvider {
@override
boot(Nylo nylo) async {
nylo.addEvents(events);
return nylo;
}
}

View File

@ -33,7 +33,7 @@ import 'package:woosignal/models/response/tax_rate.dart';
// AS THE PAY METHOD
examplePay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
// HANDLE YOUR PAYMENT INTEGRATION HERE
// ...
// ...
@ -44,7 +44,7 @@ examplePay(context,
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true);
// CREATES ORDER IN WOOCOMMERCE
Order order = await appWooSignal((api) => api.createOrder(orderWC));
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
// CHECK IF ORDER IS NULL
if (order != null) {

View File

@ -23,7 +23,7 @@ import 'package:woosignal/models/response/order.dart';
import 'package:woosignal/models/response/tax_rate.dart';
payPalPay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
await checkout(taxRate, (total, billingDetails, cart) async {
List<CartLineItem> cartLineItems = await cart.getCart();
String description = await cart.cartShortDesc();
@ -35,7 +35,7 @@ payPalPay(context,
description: description,
amount: total,
cartLineItems: cartLineItems))).then((value) async {
if (!(value is Map<String, dynamic>)) {
if (value is! Map<String, dynamic>) {
showToastNotification(
context,
title: trans("Payment Cancelled"),
@ -48,7 +48,7 @@ payPalPay(context,
state.reloadState(showLoader: true);
if (value.containsKey("status") && value["status"] == "success") {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true);
Order order = await appWooSignal((api) => api.createOrder(orderWC));
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
if (order == null) {
showToastNotification(

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,10 @@
import 'package:flutter_app/routes/router.dart';
import 'package:nylo_framework/nylo_framework.dart';
class RouteProvider implements NyProvider {
boot(Nylo nylo) async {
nylo.addRouter(appRouter());
return nylo;
}
}

View File

@ -24,16 +24,16 @@ import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
stripePay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
WooSignalApp wooSignalApp = AppHelper.instance.appConfig;
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
WooSignalApp? wooSignalApp = AppHelper.instance.appConfig;
bool liveMode = getEnv('STRIPE_LIVE_MODE') == null
? !wooSignalApp.stripeLiveMode
? !wooSignalApp!.stripeLiveMode!
: getEnv('STRIPE_LIVE_MODE', defaultValue: false);
// CONFIGURE STRIPE
Stripe.stripeAccountId =
getEnv('STRIPE_ACCOUNT') ?? wooSignalApp.stripeAccount;
getEnv('STRIPE_ACCOUNT') ?? wooSignalApp!.stripeAccount;
Stripe.publishableKey = liveMode
? "pk_live_IyS4Vt86L49jITSfaUShumzi"
@ -51,10 +51,10 @@ stripePay(context,
// // CHECKOUT HELPER
await checkout(taxRate, (total, billingDetails, cart) async {
Map<String, dynamic> address = {
"name": billingDetails.billingAddress.nameFull(),
"line1": billingDetails.shippingAddress.addressLine,
"city": billingDetails.shippingAddress.city,
"postal_code": billingDetails.shippingAddress.postalCode,
"name": billingDetails!.billingAddress!.nameFull(),
"line1": billingDetails.shippingAddress!.addressLine,
"city": billingDetails.shippingAddress!.city,
"postal_code": billingDetails.shippingAddress!.postalCode,
"country": (billingDetails.shippingAddress?.customerCountry?.name ?? "")
};
@ -62,7 +62,7 @@ stripePay(context,
rsp = await appWooSignal((api) => api.stripePaymentIntent(
amount: total,
email: billingDetails.billingAddress.emailAddress,
email: billingDetails.billingAddress!.emailAddress,
desc: cartShortDesc,
shipping: address,
));
@ -87,7 +87,7 @@ stripePay(context,
: ThemeMode.dark,
testEnv: liveMode,
merchantCountryCode: envVal('STRIPE_COUNTRY_CODE',
defaultValue: wooSignalApp.stripeCountryCode),
defaultValue: wooSignalApp!.stripeCountryCode),
merchantDisplayName:
envVal('APP_NAME', defaultValue: wooSignalApp.appName),
paymentIntentClientSecret: rsp['client_secret'],
@ -98,7 +98,7 @@ stripePay(context,
state.reloadState(showLoader: true);
OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
Order order = await appWooSignal((api) => api.createOrder(orderWC));
Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
if (order == null) {
showToastNotification(
@ -113,12 +113,12 @@ stripePay(context,
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} on StripeException catch (e) {
if (getEnv('APP_DEBUG', defaultValue: true)) {
NyLogger.error(e.error.message);
NyLogger.error(e.error.message!);
}
showToastNotification(
context,
title: trans("Oops!"),
description: e.error.localizedMessage,
description: e.error.localizedMessage!,
icon: Icons.payment,
style: ToastNotificationStyleType.WARNING,
);

View File

@ -1,42 +1,42 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/config/app_theme.dart';
import 'package:flutter_app/config/theme.dart';
import 'package:nylo_framework/nylo_framework.dart';
// ignore: must_be_immutable
class AppBuild extends StatelessWidget {
String initialRoute;
ThemeData themeData;
ThemeData darkTheme;
ThemeData lightTheme;
Locale locale;
String title;
String? initialRoute;
ThemeData? themeData;
ThemeData? darkTheme;
ThemeData? lightTheme;
Locale? locale;
String? title;
bool debugShowCheckedModeBanner;
bool debugShowMaterialGrid;
bool showPerformanceOverlay;
bool checkerboardRasterCacheImages;
bool checkerboardOffscreenLayers;
bool showSemanticsDebugger;
Map<LogicalKeySet, Intent> shortcuts;
Map<Type, Action<Intent>> actions;
Map<LogicalKeySet, Intent>? shortcuts;
Map<Type, Action<Intent>>? actions;
List<Locale> supportedLocales;
ThemeMode themeMode;
Color color;
GenerateAppTitle onGenerateTitle;
TransitionBuilder builder;
Color? color;
GenerateAppTitle? onGenerateTitle;
TransitionBuilder? builder;
List<NavigatorObserver> navigatorObservers;
RouteFactory onUnknownRoute;
InitialRouteListFactory onGenerateInitialRoutes;
GlobalKey<NavigatorState> navigatorKey;
RouteFactory? onUnknownRoute;
InitialRouteListFactory? onGenerateInitialRoutes;
GlobalKey<NavigatorState>? navigatorKey;
Route<dynamic> Function(RouteSettings settings) onGenerateRoute;
Route<dynamic>? Function(RouteSettings settings) onGenerateRoute;
AppBuild({
Key key,
Key? key,
this.initialRoute,
this.title,
this.locale,
this.themeData,
@required this.onGenerateRoute,
required this.onGenerateRoute,
this.navigatorKey,
this.onGenerateInitialRoutes,
this.onUnknownRoute,
@ -64,7 +64,7 @@ class AppBuild extends StatelessWidget {
child: ThemeProvider(
themes: appThemes
.map((appTheme) => appTheme.toAppTheme(
defaultTheme: appTheme.theme.brightness == Brightness.light
defaultTheme: appTheme.theme!.brightness == Brightness.light
? lightTheme
: darkTheme))
.toList(),
@ -96,13 +96,12 @@ class AppBuild extends StatelessWidget {
darkTheme: darkTheme ?? ThemeConfig.dark().theme,
theme: themeData ?? ThemeProvider.themeOf(context).data,
localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) {
(Locale? locale, Iterable<Locale> supportedLocales) {
return locale;
},
localizationsDelegates: NyLocalization.instance.delegates,
locale: NyLocalization.instance.locale,
supportedLocales:
supportedLocales ?? NyLocalization.instance.locals(),
supportedLocales: supportedLocales,
),
),
),

View File

@ -15,5 +15,5 @@ class AppHelper {
static final AppHelper instance = AppHelper._privateConstructor();
WooSignalApp appConfig;
WooSignalApp? appConfig;
}

View File

@ -3,10 +3,10 @@ import 'package:flutter_app/resources/themes/styles/base_styles.dart';
import 'package:nylo_framework/nylo_framework.dart';
class BaseThemeConfig {
final String id;
final String description;
final ThemeData theme;
final BaseColorStyles colors;
final String? id;
final String? description;
final ThemeData? theme;
final BaseColorStyles? colors;
final dynamic meta;
BaseThemeConfig(
@ -16,9 +16,9 @@ class BaseThemeConfig {
this.colors,
this.meta = const {}});
AppTheme toAppTheme({ThemeData defaultTheme}) => AppTheme(
id: id,
data: defaultTheme ?? theme,
description: description,
AppTheme toAppTheme({ThemeData? defaultTheme}) => AppTheme(
id: id!,
data: defaultTheme ?? theme!,
description: description!,
);
}

View File

@ -1,96 +1,12 @@
// import 'package:firebase_core/firebase_core.dart';
// import 'package:firebase_messaging/firebase_messaging.dart';
// import 'package:flutter_app/firebase_options.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/config/app_localization.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/woosignal.dart';
import 'package:wp_json_api/wp_json_api.dart';
/// boot application
Future<void> boot() async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
import 'package:flutter_app/config/providers.dart';
import 'package:nylo_framework/nylo_framework.dart';
await WooSignal.instance
.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG'));
// Notifications
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
///
/// FirebaseMessaging messaging = FirebaseMessaging.instance;
///
/// NotificationSettings settings = await messaging.requestPermission(
/// alert: true,
/// announcement: false,
/// badge: true,
/// carPlay: false,
/// criticalAlert: false,
/// provisional: false,
/// sound: true,
/// );
///
/// if (settings.authorizationStatus == AuthorizationStatus.authorized) {
/// String token = await messaging.getToken();
/// WooSignal.instance.setFcmToken(token);
/// }
AppHelper?.instance?.appConfig = WooSignalApp();
AppHelper.instance.appConfig.themeFont = "Poppins";
AppHelper.instance.appConfig.themeColors = {
'light': {
'background': '0xFFFFFFFF',
'primary_text': '0xFF000000',
'button_background': '0xFF529cda',
'button_text': '0xFFFFFFFF',
'app_bar_background': '0xFFFFFFFF',
'app_bar_text': '0xFF3a3d40',
},
'dark': {
'background': '0xFF212121',
'primary_text': '0xFFE1E1E1',
'button_background': '0xFFFFFFFF',
'button_text': '0xFF232c33',
'app_bar_background': '0xFF2C2C2C',
'app_bar_text': '0xFFFFFFFF',
}
};
// WooSignal Setup
WooSignalApp wooSignalApp = await appWooSignal((api) => api.getApp());
Locale locale = Locale('en');
if (wooSignalApp != null) {
AppHelper.instance.appConfig = wooSignalApp;
if (wooSignalApp.wpLoginEnabled == 1) {
WPJsonAPI.instance.initWith(
baseUrl: wooSignalApp.wpLoginBaseUrl,
shouldDebug: getEnv('APP_DEBUG'),
wpJsonPath: wooSignalApp.wpLoginWpApiPath,
);
}
if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null &&
wooSignalApp.locale != null) {
locale = Locale(wooSignalApp.locale);
} else {
locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en'));
}
}
/// NyLocalization
await NyLocalization.instance.init(
localeType: localeType,
languageCode: locale.languageCode,
languagesList: languagesList,
assetsDirectory: assetsDirectory,
valuesAsMap: valuesAsMap);
class Boot {
static Future<Nylo> nylo() async => await bootApplication(providers);
static Future<void> finished(Nylo nylo) async => await bootFinished(nylo);
}

View File

@ -20,12 +20,12 @@ import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
Future<OrderWC> buildOrderWC({TaxRate? taxRate, bool markPaid = true}) async {
CheckoutSession checkoutSession = CheckoutSession.getInstance;
OrderWC orderWC = OrderWC();
WooSignalApp wooSignalApp = AppHelper.instance.appConfig;
WooSignalApp wooSignalApp = AppHelper.instance.appConfig!;
String paymentMethodName = checkoutSession.paymentType.name ?? "";
String paymentMethodName = checkoutSession.paymentType!.name;
orderWC.paymentMethod = Platform.isAndroid
? "$paymentMethodName - Android App"
@ -35,9 +35,10 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
orderWC.setPaid = markPaid;
orderWC.status = "pending";
orderWC.currency = wooSignalApp.currencyMeta.code.toUpperCase();
orderWC.customerId =
(wooSignalApp.wpLoginEnabled == 1) ? int.parse(await readUserId()) : 0;
orderWC.currency = wooSignalApp.currencyMeta!.code!.toUpperCase();
orderWC.customerId = (wooSignalApp.wpLoginEnabled == 1)
? int.parse(await (readUserId()) ?? "0")
: 0;
List<LineItems> lineItems = [];
List<CartLineItem> cartItems = await Cart.getInstance.getCart();
@ -56,49 +57,50 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
orderWC.lineItems = lineItems;
BillingDetails billingDetails = checkoutSession.billingDetails;
BillingDetails billingDetails = checkoutSession.billingDetails!;
Billing billing = Billing();
billing.firstName = billingDetails.billingAddress.firstName;
billing.lastName = billingDetails.billingAddress.lastName;
billing.address1 = billingDetails.billingAddress.addressLine;
billing.city = billingDetails.billingAddress.city;
billing.postcode = billingDetails.billingAddress.postalCode;
billing.email = billingDetails.billingAddress.emailAddress;
if (billingDetails.billingAddress.phoneNumber != "") {
billing.phone = billingDetails.billingAddress.phoneNumber;
billing.firstName = billingDetails.billingAddress!.firstName;
billing.lastName = billingDetails.billingAddress!.lastName;
billing.address1 = billingDetails.billingAddress!.addressLine;
billing.city = billingDetails.billingAddress!.city;
billing.postcode = billingDetails.billingAddress!.postalCode;
billing.email = billingDetails.billingAddress!.emailAddress;
if (billingDetails.billingAddress!.phoneNumber != "") {
billing.phone = billingDetails.billingAddress!.phoneNumber;
}
if (billingDetails.billingAddress.customerCountry.hasState()) {
billing.state = billingDetails.billingAddress.customerCountry.state.name;
if (billingDetails.billingAddress!.customerCountry!.hasState()) {
billing.state = billingDetails.billingAddress!.customerCountry!.state!.name;
}
billing.country = billingDetails.billingAddress.customerCountry.name;
billing.country = billingDetails.billingAddress!.customerCountry!.name;
orderWC.billing = billing;
Shipping shipping = Shipping();
shipping.firstName = billingDetails.shippingAddress.firstName;
shipping.lastName = billingDetails.shippingAddress.lastName;
shipping.address1 = billingDetails.shippingAddress.addressLine;
shipping.city = billingDetails.shippingAddress.city;
shipping.postcode = billingDetails.shippingAddress.postalCode;
if (billingDetails.shippingAddress.customerCountry.hasState()) {
billing.state = billingDetails.shippingAddress.customerCountry.state.name;
shipping.firstName = billingDetails.shippingAddress!.firstName;
shipping.lastName = billingDetails.shippingAddress!.lastName;
shipping.address1 = billingDetails.shippingAddress!.addressLine;
shipping.city = billingDetails.shippingAddress!.city;
shipping.postcode = billingDetails.shippingAddress!.postalCode;
if (billingDetails.shippingAddress!.customerCountry!.hasState()) {
billing.state =
billingDetails.shippingAddress!.customerCountry!.state!.name;
}
billing.country = billingDetails.shippingAddress.customerCountry.name;
billing.country = billingDetails.shippingAddress!.customerCountry!.name;
orderWC.shipping = shipping;
orderWC.shippingLines = [];
if (wooSignalApp.disableShipping != 1) {
Map<String, dynamic> shippingLineFeeObj =
checkoutSession.shippingType.toShippingLineFee();
Map<String, dynamic>? shippingLineFeeObj =
checkoutSession.shippingType!.toShippingLineFee();
if (shippingLineFeeObj != null) {
ShippingLines shippingLine = ShippingLines();
shippingLine.methodId = shippingLineFeeObj['method_id'];
shippingLine.methodTitle = shippingLineFeeObj['method_title'];
shippingLine.total = shippingLineFeeObj['total'];
orderWC.shippingLines.add(shippingLine);
orderWC.shippingLines!.add(shippingLine);
}
}
@ -109,13 +111,13 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
feeLines.total = await Cart.getInstance.taxAmount(taxRate);
feeLines.taxClass = "";
feeLines.taxStatus = "taxable";
orderWC.feeLines.add(feeLines);
orderWC.feeLines!.add(feeLines);
}
if (checkoutSession.coupon != null) {
orderWC.couponLines = [];
CouponLines couponLine = CouponLines(code: checkoutSession.coupon.code);
orderWC.couponLines.add(couponLine);
CouponLines couponLine = CouponLines(code: checkoutSession.coupon!.code);
orderWC.couponLines!.add(couponLine);
}
return orderWC;

View File

@ -8,8 +8,4 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
enum WishlistAction {
add,
remove
}
enum WishlistAction { add, remove }

View File

@ -9,6 +9,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'dart:convert';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/cupertino.dart';
import 'package:flutter_app/app/models/billing_details.dart';
import 'package:flutter_app/app/models/cart.dart';
@ -20,9 +21,11 @@ import 'package:flutter_app/app/models/user.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:flutter_app/config/app_currency.dart';
import 'package:flutter_app/config/app_payment_gateways.dart';
import 'package:flutter_app/config/app_theme.dart';
import 'package:flutter_app/config/currency.dart';
import 'package:flutter_app/config/decoders.dart';
import 'package:flutter_app/config/events.dart';
import 'package:flutter_app/config/payment_gateways.dart';
import 'package:flutter_app/config/theme.dart';
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
@ -34,15 +37,14 @@ import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:math_expressions/math_expressions.dart';
import 'package:money_formatter/money_formatter.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:platform_alert_dialog/platform_alert_dialog.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:status_alert/status_alert.dart';
import 'package:woosignal/models/response/products.dart';
import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/woosignal.dart';
Future<User> getUser() async =>
(await NyStorage.read<User>(SharedKey.authUser, model: User()));
Future<User?> getUser() async =>
(await (NyStorage.read<User>(SharedKey.authUser, model: User())));
Future appWooSignal(Function(WooSignal) api) async {
return await api(WooSignal.instance);
@ -50,7 +52,7 @@ Future appWooSignal(Function(WooSignal) api) async {
/// helper to find correct color from the [context].
class ThemeColor {
static BaseColorStyles get(BuildContext context) {
static BaseColorStyles? get(BuildContext context) {
return ((Theme.of(context).brightness == Brightness.light)
? ThemeConfig.light().colors
: ThemeConfig.dark().colors);
@ -60,39 +62,37 @@ class ThemeColor {
/// helper to set colors on TextStyle
extension ColorsHelper on TextStyle {
TextStyle setColor(
BuildContext context, Color Function(BaseColorStyles color) newColor) {
BuildContext context, Color Function(BaseColorStyles? color) newColor) {
return copyWith(color: newColor(ThemeColor.get(context)));
}
}
List<PaymentType> getPaymentTypes() {
List<PaymentType> paymentTypes = [];
for (var appPaymentGateway in app_payment_gateways) {
List<PaymentType?> getPaymentTypes() {
List<PaymentType?> paymentTypes = [];
for (var appPaymentGateway in appPaymentGateways) {
if (paymentTypes.firstWhere(
(paymentType) => paymentType.name != appPaymentGateway,
(paymentType) => paymentType!.name != appPaymentGateway,
orElse: () => null) ==
null) {
paymentTypes.add(paymentTypeList.firstWhere(
(paymentTypeList) => paymentTypeList.name == appPaymentGateway,
orElse: () => null));
paymentTypes.add(paymentTypeList.firstWhereOrNull(
(paymentTypeList) => paymentTypeList.name == appPaymentGateway));
}
}
if (!app_payment_gateways.contains('Stripe') &&
AppHelper.instance.appConfig.stripeEnabled == true) {
if (!appPaymentGateways.contains('Stripe') &&
AppHelper.instance.appConfig!.stripeEnabled == true) {
paymentTypes.add(paymentTypeList
.firstWhere((element) => element.name == "Stripe", orElse: () => null));
.firstWhereOrNull((element) => element.name == "Stripe"));
}
if (!app_payment_gateways.contains('PayPal') &&
AppHelper.instance.appConfig.paypalEnabled == true) {
if (!appPaymentGateways.contains('PayPal') &&
AppHelper.instance.appConfig!.paypalEnabled == true) {
paymentTypes.add(paymentTypeList
.firstWhere((element) => element.name == "PayPal", orElse: () => null));
.firstWhereOrNull((element) => element.name == "PayPal"));
}
if (!app_payment_gateways.contains('CashOnDelivery') &&
AppHelper.instance.appConfig.codEnabled == true) {
paymentTypes.add(paymentTypeList.firstWhere(
(element) => element.name == "CashOnDelivery",
orElse: () => null));
if (!appPaymentGateways.contains('CashOnDelivery') &&
AppHelper.instance.appConfig!.codEnabled == true) {
paymentTypes.add(paymentTypeList
.firstWhereOrNull((element) => element.name == "CashOnDelivery"));
}
return paymentTypes.where((v) => v != null).toList();
@ -102,11 +102,11 @@ dynamic envVal(String envVal, {dynamic defaultValue}) =>
(getEnv(envVal) ?? defaultValue);
PaymentType addPayment(
{@required int id,
@required String name,
@required String desc,
@required String assetImage,
@required Function pay}) =>
{required int id,
required String name,
required String desc,
required String assetImage,
required Function pay}) =>
PaymentType(
id: id,
name: name,
@ -116,7 +116,10 @@ PaymentType addPayment(
);
showStatusAlert(context,
{@required String title, String subtitle, IconData icon, int duration}) {
{required String title,
required String subtitle,
IconData? icon,
int? duration}) {
StatusAlert.show(
context,
duration: Duration(seconds: duration ?? 2),
@ -126,31 +129,31 @@ showStatusAlert(context,
);
}
String parseHtmlString(String htmlString) {
String parseHtmlString(String? htmlString) {
var document = parse(htmlString);
return parse(document.body.text).documentElement.text;
return parse(document.body!.text).documentElement!.text;
}
String moneyFormatter(double amount) {
MoneyFormatter fmf = MoneyFormatter(
amount: amount,
settings: MoneyFormatterSettings(
symbol: AppHelper.instance.appConfig.currencyMeta.symbolNative,
symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative,
),
);
if (app_currency_symbol_position == SymbolPositionType.left) {
if (appCurrencySymbolPosition == SymbolPositionType.left) {
return fmf.output.symbolOnLeft;
} else if (app_currency_symbol_position == SymbolPositionType.right) {
} else if (appCurrencySymbolPosition == SymbolPositionType.right) {
return fmf.output.symbolOnRight;
}
return fmf.output.symbolOnLeft;
}
String formatDoubleCurrency({@required double total}) {
String formatDoubleCurrency({required double total}) {
return moneyFormatter(total);
}
String formatStringCurrency({@required String total}) {
String formatStringCurrency({required String? total}) {
double tmpVal = 0;
if (total != null && total != "") {
tmpVal = parseWcPrice(total);
@ -159,20 +162,24 @@ String formatStringCurrency({@required String total}) {
}
String workoutSaleDiscount(
{@required String salePrice, @required String priceBefore}) {
{required String? salePrice, required String? priceBefore}) {
double dSalePrice = parseWcPrice(salePrice);
double dPriceBefore = parseWcPrice(priceBefore);
return ((dPriceBefore - dSalePrice) * (100 / dPriceBefore))
.toStringAsFixed(0);
}
openBrowserTab({@required String url}) async {
openBrowserTab({required String url}) async {
await FlutterWebBrowser.openWebPage(
url: url,
customTabsOptions: CustomTabsOptions(toolbarColor: Colors.white70));
url: url,
customTabsOptions: CustomTabsOptions(
defaultColorSchemeParams:
CustomTabsColorSchemeParams(toolbarColor: Colors.white70),
),
);
}
bool isNumeric(String str) {
bool isNumeric(String? str) {
if (str == null) {
return false;
}
@ -180,18 +187,18 @@ bool isNumeric(String str) {
}
checkout(
TaxRate taxRate,
Function(String total, BillingDetails billingDetails, Cart cart)
TaxRate? taxRate,
Function(String total, BillingDetails? billingDetails, Cart cart)
completeCheckout) async {
String cartTotal = await CheckoutSession.getInstance
.total(withFormat: false, taxRate: taxRate);
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails;
BillingDetails? billingDetails = CheckoutSession.getInstance.billingDetails;
Cart cart = Cart.getInstance;
return await completeCheckout(cartTotal, billingDetails, cart);
}
double strCal({@required String sum}) {
if (sum == null || sum == "") {
double? strCal({required String sum}) {
if (sum == "") {
return 0;
}
Parser p = Parser();
@ -200,7 +207,7 @@ double strCal({@required String sum}) {
return exp.evaluate(EvaluationType.REAL, cm);
}
Future<double> workoutShippingCostWC({@required String sum}) async {
Future<double?> workoutShippingCostWC({required String? sum}) async {
if (sum == null || sum == "") {
return 0;
}
@ -219,27 +226,27 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
if (replace.groupCount < 1) {
return "()";
}
String newSum = replace.group(1);
String newSum = replace.group(1)!;
// PERCENT
String percentVal = newSum.replaceAllMapped(
defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) {
if (replacePercent != null && replacePercent.groupCount >= 1) {
if (replacePercent.groupCount >= 1) {
String strPercentage = "( (" +
orderTotal.toString() +
" * " +
replacePercent.group(1).toString() +
") / 100 )";
double calPercentage = strCal(sum: strPercentage);
double? calPercentage = strCal(sum: strPercentage);
// MIN
String strRegexMinFee = r'min_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMinFee).hasMatch(newSum)) {
String strMinFee =
defaultRegex(strRegexMinFee).firstMatch(newSum).group(1) ?? "0";
defaultRegex(strRegexMinFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMinFee = double.parse(strMinFee);
if (calPercentage < doubleMinFee) {
if (calPercentage! < doubleMinFee) {
return "(" + doubleMinFee.toString() + ")";
}
newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), "");
@ -249,10 +256,10 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
String strRegexMaxFee = r'max_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) {
String strMaxFee =
defaultRegex(strRegexMaxFee).firstMatch(newSum).group(1) ?? "0";
defaultRegex(strRegexMaxFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMaxFee = double.parse(strMaxFee);
if (calPercentage > doubleMaxFee) {
if (calPercentage! > doubleMaxFee) {
return "(" + doubleMaxFee.toString() + ")";
}
newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), "");
@ -273,13 +280,13 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
return strCal(sum: sum);
}
Future<double> workoutShippingClassCostWC(
{@required String sum, List<CartLineItem> cartLineItem}) async {
Future<double?> workoutShippingClassCostWC(
{required String? sum, List<CartLineItem>? cartLineItem}) async {
if (sum == null || sum == "") {
return 0;
}
sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) {
return cartLineItem
return cartLineItem!
.map((f) => f.quantity)
.toList()
.reduce((i, d) => i + d)
@ -292,27 +299,27 @@ Future<double> workoutShippingClassCostWC(
if (replace.groupCount < 1) {
return "()";
}
String newSum = replace.group(1);
String newSum = replace.group(1)!;
// PERCENT
String percentVal = newSum.replaceAllMapped(
defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) {
if (replacePercent != null && replacePercent.groupCount >= 1) {
if (replacePercent.groupCount >= 1) {
String strPercentage = "( (" +
orderTotal.toString() +
" * " +
replacePercent.group(1).toString() +
") / 100 )";
double calPercentage = strCal(sum: strPercentage);
double? calPercentage = strCal(sum: strPercentage);
// MIN
String strRegexMinFee = r'min_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMinFee).hasMatch(newSum)) {
String strMinFee =
defaultRegex(strRegexMinFee).firstMatch(newSum).group(1) ?? "0";
defaultRegex(strRegexMinFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMinFee = double.parse(strMinFee);
if (calPercentage < doubleMinFee) {
if (calPercentage! < doubleMinFee) {
return "(" + doubleMinFee.toString() + ")";
}
newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), "");
@ -322,10 +329,10 @@ Future<double> workoutShippingClassCostWC(
String strRegexMaxFee = r'max_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) {
String strMaxFee =
defaultRegex(strRegexMaxFee).firstMatch(newSum).group(1) ?? "0";
defaultRegex(strRegexMaxFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMaxFee = double.parse(strMaxFee);
if (calPercentage > doubleMaxFee) {
if (calPercentage! > doubleMaxFee) {
return "(" + doubleMaxFee.toString() + ")";
}
newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), "");
@ -348,7 +355,7 @@ Future<double> workoutShippingClassCostWC(
RegExp defaultRegex(
String pattern, {
bool strict,
bool? strict,
}) {
return RegExp(
pattern,
@ -365,10 +372,10 @@ bool isEmail(String em) {
}
navigatorPush(BuildContext context,
{@required String routeName,
Object arguments,
{required String routeName,
Object? arguments,
bool forgetAll = false,
int forgetLast}) {
int? forgetLast}) {
if (forgetAll) {
Navigator.of(context).pushNamedAndRemoveUntil(
routeName, (Route<dynamic> route) => false,
@ -383,51 +390,11 @@ navigatorPush(BuildContext context,
Navigator.of(context).pushNamed(routeName, arguments: arguments);
}
PlatformDialogAction dialogAction(BuildContext context,
{@required title, ActionType actionType, Function() action}) {
return PlatformDialogAction(
actionType: actionType ?? ActionType.Default,
child: Text(title ?? ""),
onPressed: action ??
() {
Navigator.of(context).pop();
},
);
}
showPlatformAlertDialog(BuildContext context,
{String title,
String subtitle,
List<PlatformDialogAction> actions,
bool showDoneAction = true}) {
if (showDoneAction) {
actions.add(dialogAction(context, title: trans("Done"), action: () {
Navigator.of(context).pop();
}));
}
showDialog<void>(
context: context,
builder: (BuildContext context) {
return PlatformAlertDialog(
title: Text(title ?? ""),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(subtitle ?? ""),
],
),
),
actions: actions,
);
},
);
}
DateTime parseDateTime(String strDate) => DateTime.parse(strDate);
DateFormat formatDateTime(String format) => DateFormat(format);
String dateFormatted({@required String date, @required String formatType}) =>
String dateFormatted({required String date, required String formatType}) =>
formatDateTime(formatType).format(parseDateTime(date));
enum FormatType {
@ -457,20 +424,20 @@ String formatForDateTime(FormatType formatType) {
}
}
double parseWcPrice(String price) => (double.tryParse(price ?? "0") ?? 0);
double parseWcPrice(String? price) => (double.tryParse(price ?? "0") ?? 0);
Widget refreshableScroll(context,
{@required refreshController,
@required VoidCallback onRefresh,
@required VoidCallback onLoading,
@required List<Product> products,
@required onTap,
{required refreshController,
required VoidCallback onRefresh,
required VoidCallback onLoading,
required List<Product> products,
required onTap,
key}) {
return SmartRefresher(
enablePullDown: true,
enablePullUp: true,
footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) {
builder: (BuildContext context, LoadStatus? mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text(trans("pull up load"));
@ -492,24 +459,24 @@ Widget refreshableScroll(context,
controller: refreshController,
onRefresh: onRefresh,
onLoading: onLoading,
child: (products.length != null && products.isNotEmpty
? StaggeredGridView.countBuilder(
child: products.isEmpty
? NoResultsForProductsWidget()
: StaggeredGrid.count(
crossAxisCount: 2,
itemCount: products.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 200,
child: ProductItemContainer(
product: products[index],
onTap: onTap,
),
);
},
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
)
: NoResultsForProductsWidget()),
children: products.map((product) {
return StaggeredGridTile.fit(
crossAxisCellCount: 1,
child: Container(
height: 200,
child: ProductItemContainer(
product: product,
onTap: onTap,
),
),
);
}).toList()),
);
}
@ -546,38 +513,46 @@ String truncateString(String data, int length) {
Future<List<dynamic>> getWishlistProducts() async {
List<dynamic> favouriteProducts = [];
String currentProductsJSON = await NyStorage.read(SharedKey.wishlistProducts);
String? currentProductsJSON =
await (NyStorage.read(SharedKey.wishlistProducts));
if (currentProductsJSON != null) {
favouriteProducts =
(jsonDecode(currentProductsJSON) as List<dynamic>).toList();
favouriteProducts = (jsonDecode(currentProductsJSON)).toList();
}
return favouriteProducts;
}
hasAddedWishlistProduct(int productId) async {
hasAddedWishlistProduct(int? productId) async {
List<dynamic> favouriteProducts = await getWishlistProducts();
List<int> productIds =
favouriteProducts.map((e) => e['id']).cast<int>().toList();
favouriteProducts.map((e) => e['id']).cast<int>().toList();
if (productIds.isEmpty) {
return false;
return false;
}
return productIds.contains(productId);
}
saveWishlistProduct({@required Product product}) async {
saveWishlistProduct({required Product? product}) async {
List<dynamic> products = await getWishlistProducts();
if (products.any((wishListProduct) => wishListProduct['id'] == product.id) ==
if (products.any((wishListProduct) => wishListProduct['id'] == product!.id) ==
false) {
products.add({"id": product.id});
products.add({"id": product!.id});
}
String json = jsonEncode(products.map((i) => {"id": i['id']}).toList());
await NyStorage.store(SharedKey.wishlistProducts, json);
}
removeWishlistProduct({@required Product product}) async {
removeWishlistProduct({required Product? product}) async {
List<dynamic> products = await getWishlistProducts();
products.removeWhere((element) => element['id'] == product.id);
products.removeWhere((element) => element['id'] == product!.id);
String json = jsonEncode(products.map((i) => {"id": i['id']}).toList());
await NyStorage.store(SharedKey.wishlistProducts, json);
}
/// API helper
api<T>(dynamic Function(T) request, {BuildContext? context}) async =>
await nyApi<T>(
request: request, apiDecoders: apiDecoders, context: context);
/// Event helper
event<T>({Map? data}) async => nyEvent<T>(params: data, events: events);

View File

@ -12,13 +12,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
Future<bool> authCheck() async => ((await getUser()) != null);
Future<String> readAuthToken() async => (await getUser()).token;
Future<String?> readAuthToken() async => (await getUser())!.token;
Future<String> readUserId() async => (await getUser()).userId;
Future<String?> readUserId() async => (await getUser())!.userId;
authLogout(BuildContext context) async {
await NyStorage.delete(SharedKey.authUser);

View File

@ -18,7 +18,7 @@ import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
|--------------------------------------------------------------------------
*/
const SymbolPositionType app_currency_symbol_position = SymbolPositionType.left;
const SymbolPositionType appCurrencySymbolPosition = SymbolPositionType.left;
// currency_symbol_position example.
// left: $15
// right: 15

View File

@ -0,0 +1,30 @@
import 'package:flutter_app/app/networking/api_service.dart';
/*
|--------------------------------------------------------------------------
| Model Decoders
| -------------------------------------------------------------------------
| Model decoders are used in 'app/networking/' for morphing json payloads
| into Models. Learn more https://nylo.dev/docs/3.x/decoders#model-decoders
|--------------------------------------------------------------------------
*/
final Map<Type, dynamic> modelDecoders = {
// ...
};
/*
|--------------------------------------------------------------------------
| API Decoders
| -------------------------------------------------------------------------
| API decoders are used when you need to access an API service using the
| 'api' helper. E.g. api<MyApiService>((request) => request.fetchData());
| Learn more https://nylo.dev/docs/3.x/decoders#api-decoders
|--------------------------------------------------------------------------
*/
final Map<Type, dynamic> apiDecoders = {
ApiService: ApiService(),
// ...
};

View File

@ -0,0 +1,18 @@
import 'package:flutter_app/app/events/login_event.dart';
import 'package:flutter_app/app/events/logout_event.dart';
import 'package:nylo_framework/nylo_framework.dart';
/*
|--------------------------------------------------------------------------
| Events
| Add your "app/events" here.
| Events can be fired using: event<MyEvent>();
|
| Learn more: https://nylo.dev/docs/3.x/events
|--------------------------------------------------------------------------
*/
final Map<Type, NyEvent> events = {
LoginEvent: LoginEvent(),
LogoutEvent: LogoutEvent(),
};

View File

@ -18,7 +18,7 @@ final LocaleType localeType = LocaleType.asDefined; // device, asDefined
| The language code should match the name of the file i.e /lang/es.json
|--------------------------------------------------------------------------
*/
final String languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en");
final String? languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en");
/*
|--------------------------------------------------------------------------

View File

@ -13,7 +13,7 @@ import 'package:flutter_app/bootstrap/helpers.dart';
|--------------------------------------------------------------------------
*/
const app_payment_gateways = [];
const appPaymentGateways = [];
// Available: "Stripe", "CashOnDelivery", "PayPal"
// e.g. app_payment_gateways = ["Stripe", "CashOnDelivery"]; will only use Stripe and Cash on Delivery.

View File

@ -0,0 +1,19 @@
import 'package:flutter_app/app/providers/app_provider.dart';
import 'package:flutter_app/app/providers/event_provider.dart';
import 'package:flutter_app/app/providers/route_provider.dart';
/*
|--------------------------------------------------------------------------
| Providers
| Add your "app/providers" here.
| Providers are booted when your application start.
|
| Learn more: https://nylo.dev/docs/3.x/providers
|--------------------------------------------------------------------------
*/
final providers = {
AppProvider: AppProvider(),
RouteProvider: RouteProvider(),
EventProvider: EventProvider(),
};

View File

@ -1,20 +0,0 @@
//
// Generated file. Do not edit.
//
// ignore_for_file: directives_ordering
// ignore_for_file: lines_longer_than_80_chars
import 'package:flutter_secure_storage_web/flutter_secure_storage_web.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
import 'package:url_launcher_web/url_launcher_web.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
FlutterSecureStorageWeb.registerWith(registrar);
SharedPreferencesPlugin.registerWith(registrar);
UrlLauncherPlugin.registerWith(registrar);
registrar.registerMessageHandler();
}

View File

@ -2,21 +2,20 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/boot.dart';
import 'package:flutter_app/routes/router.dart';
import 'package:nylo_framework/nylo_framework.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Nylo nylo = await Nylo.init(router: appRouter(), setup: boot);
Nylo nylo = await Nylo.init(setup: Boot.nylo, setupFinished: Boot.finished);
String initialRoute = AppHelper.instance.appConfig.appStatus != null
String initialRoute = AppHelper.instance.appConfig!.appStatus != null
? '/home'
: '/no-connection';
runApp(
AppBuild(
navigatorKey: nylo.router.navigatorKey,
onGenerateRoute: nylo.router.generator(),
navigatorKey: NyNavigator.instance.router.navigatorKey,
onGenerateRoute: nylo.router!.generator(),
initialRoute: initialRoute,
debugShowCheckedModeBanner: false,
),

View File

@ -51,18 +51,18 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
_fetchUserDetails() async {
WCCustomerInfoResponse wcCustomerInfoResponse =
await WPJsonAPI.instance.api((request) async {
return request.wcCustomerInfo(await readAuthToken());
return request.wcCustomerInfo((await readAuthToken())!);
});
Billing billing = wcCustomerInfoResponse.data.billing;
_txtShippingFirstName.text = billing.firstName;
_txtShippingLastName.text = billing.lastName;
Billing billing = wcCustomerInfoResponse.data!.billing!;
_txtShippingFirstName.text = billing.firstName!;
_txtShippingLastName.text = billing.lastName!;
_txtShippingAddressLine.text = billing.address1;
_txtShippingCity.text = billing.city;
_txtShippingState.text = billing.state;
_txtShippingPostalCode.text = billing.postcode;
_txtShippingCountry.text = billing.country;
_txtShippingAddressLine.text = billing.address1!;
_txtShippingCity.text = billing.city!;
_txtShippingState.text = billing.state!;
_txtShippingPostalCode.text = billing.postcode!;
_txtShippingCountry.text = billing.country!;
setState(() {
_isLoading = false;
@ -155,7 +155,7 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
],
),
decoration: BoxDecoration(
color: ThemeColor.get(context).surfaceBackground,
color: ThemeColor.get(context)!.surfaceBackground,
borderRadius: BorderRadius.circular(10),
boxShadow: (Theme.of(context).brightness ==
Brightness.light)
@ -171,9 +171,9 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
Column(
children: <Widget>[
PrimaryButton(
title: trans("UPDATE DETAILS"),
isLoading: _isUpdating,
action: _updateBillingDetails,
title: trans("UPDATE DETAILS"),
isLoading: _isUpdating,
action: _updateBillingDetails,
),
],
),
@ -194,13 +194,13 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
String postalCode = _txtShippingPostalCode.text;
String country = _txtShippingCountry.text;
String userToken = await readAuthToken();
String? userToken = await readAuthToken();
setState(() {
_isUpdating = true;
});
WCCustomerUpdatedResponse wcCustomerUpdatedResponse;
WCCustomerUpdatedResponse? wcCustomerUpdatedResponse;
try {
wcCustomerUpdatedResponse = await WPJsonAPI.instance.api((request) =>
request.wcUpdateCustomerInfo(userToken,

View File

@ -31,10 +31,10 @@ class AccountDetailPage extends StatefulWidget {
class _AccountDetailPageState extends State<AccountDetailPage>
with SingleTickerProviderStateMixin {
TabController _tabController;
TabController? _tabController;
bool _isLoading = true;
int _currentTabIndex = 0;
WCCustomerInfoResponse _wcCustomerInfoResponse;
WCCustomerInfoResponse? _wcCustomerInfoResponse;
@override
void initState() {
@ -44,12 +44,12 @@ class _AccountDetailPageState extends State<AccountDetailPage>
}
_fetchWpUserData() async {
String userToken = await readAuthToken();
String? userToken = await readAuthToken();
WCCustomerInfoResponse wcCustomerInfoResponse;
WCCustomerInfoResponse? wcCustomerInfoResponse;
try {
wcCustomerInfoResponse = await WPJsonAPI.instance
.api((request) => request.wcCustomerInfo(userToken));
.api((request) => request.wcCustomerInfo(userToken!));
} on InvalidUserTokenException catch (_) {
showToastNotification(
context,
@ -81,7 +81,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
@override
Widget build(BuildContext context) {
Widget activeBody;
Widget? activeBody;
if (_currentTabIndex == 0) {
activeBody = AccountDetailOrdersWidget();
} else if (_currentTabIndex == 1) {
@ -98,16 +98,15 @@ class _AccountDetailPageState extends State<AccountDetailPage>
if (activeBody == null) {
return SizedBox.shrink();
}
String userAvatar;
String userFirstName = "";
String userLastName = "";
if (_wcCustomerInfoResponse != null && _wcCustomerInfoResponse.data != null) {
userAvatar = _wcCustomerInfoResponse.data.avatar;
String? userAvatar;
String? userFirstName = "";
String? userLastName = "";
if (_wcCustomerInfoResponse != null &&
_wcCustomerInfoResponse!.data != null) {
userAvatar = _wcCustomerInfoResponse!.data!.avatar;
userFirstName = _wcCustomerInfoResponse
.data.firstName;
userLastName = _wcCustomerInfoResponse
.data.lastName;
userFirstName = _wcCustomerInfoResponse!.data!.firstName;
userLastName = _wcCustomerInfoResponse!.data!.lastName;
}
return Scaffold(
appBar: AppBar(
@ -142,9 +141,14 @@ class _AccountDetailPageState extends State<AccountDetailPage>
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 10),
child: userAvatar != null ? CircleAvatar(
backgroundImage: NetworkImage(userAvatar),
) : Icon(Icons.account_circle_rounded, size: 65,),
child: userAvatar != null
? CircleAvatar(
backgroundImage: NetworkImage(userAvatar),
)
: Icon(
Icons.account_circle_rounded,
size: 65,
),
height: 90,
width: 90,
),
@ -161,11 +165,9 @@ class _AccountDetailPageState extends State<AccountDetailPage>
MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
[
userFirstName,
userLastName
].where((t) =>
(t != null || t != ""))
[userFirstName, userLastName]
.where(
(t) => (t != null || t != ""))
.toList()
.join(" "),
style: TextStyle(
@ -210,7 +212,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
(Theme.of(context).brightness == Brightness.light)
? wsBoxShadow()
: null,
color: ThemeColor.get(context).backgroundContainer,
color: ThemeColor.get(context)!.backgroundContainer,
),
),
Expanded(child: activeBody),
@ -222,7 +224,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
@override
void dispose() {
_tabController.dispose();
_tabController!.dispose();
super.dispose();
}

View File

@ -65,7 +65,7 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
child: Text(
trans("Login"),
textAlign: TextAlign.left,
style: Theme.of(context).textTheme.headline4.copyWith(
style: Theme.of(context).textTheme.headline4!.copyWith(
fontSize: 24,
fontWeight: FontWeight.w700,
),
@ -79,7 +79,7 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
(Theme.of(context).brightness == Brightness.light)
? wsBoxShadow()
: null,
color: ThemeColor.get(context).backgroundContainer,
color: ThemeColor.get(context)!.backgroundContainer,
),
padding: EdgeInsets.symmetric(vertical: 18, horizontal: 8),
margin: EdgeInsets.symmetric(horizontal: 16),
@ -133,8 +133,8 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
LinkButton(
title: trans("Forgot Password"),
action: () {
String forgotPasswordUrl =
AppHelper.instance.appConfig.wpLoginForgotPasswordUrl;
String? forgotPasswordUrl =
AppHelper.instance.appConfig!.wpLoginForgotPasswordUrl;
if (forgotPasswordUrl != null) {
openBrowserTab(url: forgotPasswordUrl);
} else {
@ -155,7 +155,7 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
: Padding(
padding: EdgeInsets.only(bottom: 20),
)
].where((element) => element != null).toList(),
],
),
),
);
@ -190,7 +190,7 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
_hasTappedLogin = true;
});
WPUserLoginResponse wpUserLoginResponse;
WPUserLoginResponse? wpUserLoginResponse;
try {
wpUserLoginResponse = await WPJsonAPI.instance.api(
(request) => request.wpLogin(email: email, password: password));
@ -228,8 +228,8 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
}
if (wpUserLoginResponse != null && wpUserLoginResponse.status == 200) {
String token = wpUserLoginResponse.data.userToken;
String userId = wpUserLoginResponse.data.userId.toString();
String? token = wpUserLoginResponse.data!.userToken;
String userId = wpUserLoginResponse.data!.userId.toString();
User user = User.fromUserAuthResponse(token: token, userId: userId);
user.save(SharedKey.authUser);

View File

@ -14,28 +14,25 @@ import 'package:flutter_app/bootstrap/helpers.dart';
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/woosignal_ui.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_support/widgets/ny_state.dart';
import 'package:nylo_support/widgets/ny_stateful_widget.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/order.dart';
class AccountOrderDetailPage extends NyStatefulWidget {
final AccountOrderDetailController controller =
AccountOrderDetailController();
AccountOrderDetailPage({Key key}) : super(key: key);
AccountOrderDetailPage({Key? key}) : super(key: key);
@override
_AccountOrderDetailPageState createState() => _AccountOrderDetailPageState();
}
class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
int _orderId;
Order _order;
int? _orderId;
Order? _order;
bool _isLoading = true;
@override
widgetDidLoad() async {
super.widgetDidLoad();
init() async {
_orderId = widget.controller.data();
await _fetchOrder();
}
@ -67,7 +64,7 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
child: Text(
"${trans("Date Ordered").capitalize()}: " +
dateFormatted(
date: _order.dateCreated,
date: _order!.dateCreated!,
formatType: formatForDateTime(FormatType.date),
),
),
@ -86,15 +83,15 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
child: Text(
[
[
_order.shipping.firstName,
_order.shipping.lastName
_order!.shipping!.firstName,
_order!.shipping!.lastName
].where((t) => t != null).toList().join(" "),
_order.shipping.address1,
_order.shipping.address2,
_order.shipping.city,
_order.shipping.state,
_order.shipping.postcode,
_order.shipping.country,
_order!.shipping!.address1,
_order!.shipping!.address2,
_order!.shipping!.city,
_order!.shipping!.state,
_order!.shipping!.postcode,
_order!.shipping!.country,
]
.where((t) => (t != "" && t != null))
.toList()
@ -118,7 +115,7 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
Expanded(
child: ListView.builder(
itemBuilder: (cxt, i) {
LineItems lineItem = _order.lineItems[i];
LineItems lineItem = _order!.lineItems![i];
return Card(
child: ListTile(
contentPadding: EdgeInsets.only(
@ -137,7 +134,7 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
children: <Widget>[
Flexible(
child: Text(
lineItem.name,
lineItem.name!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@ -169,7 +166,7 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
),
style: Theme.of(context)
.textTheme
.bodyText2
.bodyText2!
.copyWith(
fontWeight: FontWeight.w600,
),
@ -190,7 +187,7 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
),
);
},
itemCount: _order.lineItems.length,
itemCount: _order!.lineItems!.length,
),
),
],
@ -205,9 +202,9 @@ class _AccountOrderDetailPageState extends NyState<AccountOrderDetailPage> {
}
_fetchOrder() async {
_order = await appWooSignal((api) {
return api.retrieveOrder(_orderId);
});
_order = await (appWooSignal((api) {
return api.retrieveOrder(_orderId!);
}));
if (_order != null) {
setState(() {
_isLoading = false;

View File

@ -47,11 +47,11 @@ class _AccountProfileUpdatePageState extends State<AccountProfileUpdatePage> {
_fetchUserDetails() async {
WPUserInfoResponse wpUserInfoResponse =
await WPJsonAPI.instance.api((request) async {
return request.wpGetUserInfo(await readAuthToken());
return request.wpGetUserInfo((await readAuthToken()) ?? "0");
});
_tfFirstName.text = wpUserInfoResponse.data.firstName;
_tfLastName.text = wpUserInfoResponse.data.lastName;
_tfFirstName.text = wpUserInfoResponse.data!.firstName!;
_tfLastName.text = wpUserInfoResponse.data!.lastName!;
setState(() {
isLoading = false;
});
@ -108,9 +108,9 @@ class _AccountProfileUpdatePageState extends State<AccountProfileUpdatePage> {
padding: EdgeInsets.only(top: 10),
),
PrimaryButton(
title: trans("Update details"),
isLoading: isLoading,
action: _updateDetails,
title: trans("Update details"),
isLoading: isLoading,
action: _updateDetails,
)
],
),
@ -133,8 +133,8 @@ class _AccountProfileUpdatePageState extends State<AccountProfileUpdatePage> {
isLoading = true;
});
String userToken = await readAuthToken();
WPUserInfoUpdatedResponse wpUserInfoUpdatedResponse;
String? userToken = await readAuthToken();
WPUserInfoUpdatedResponse? wpUserInfoUpdatedResponse;
try {
wpUserInfoUpdatedResponse = await WPJsonAPI.instance.api((request) =>
request.wpUpdateUserInfo(userToken,

View File

@ -47,7 +47,7 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
_tfFirstNameController = TextEditingController(),
_tfLastNameController = TextEditingController();
final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
@override
void initState() {
@ -105,9 +105,9 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
),
Padding(
child: PrimaryButton(
title: trans("Sign up"),
isLoading: _hasTappedRegister,
action: _signUpTapped,
title: trans("Sign up"),
isLoading: _hasTappedRegister,
action: _signUpTapped,
),
padding: EdgeInsets.only(top: 10),
),
@ -116,7 +116,7 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
child: RichText(
text: TextSpan(
text: trans("By tapping \"Register\" you agree to ") +
AppHelper.instance.appConfig.appName +
AppHelper.instance.appConfig!.appName! +
'\'s ',
children: <TextSpan>[
TextSpan(
@ -179,7 +179,7 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
String username =
(email.replaceAll(RegExp(r'([@.])'), "")) + _randomStr(4);
WPUserRegisterResponse wpUserRegisterResponse;
WPUserRegisterResponse? wpUserRegisterResponse;
try {
wpUserRegisterResponse = await WPJsonAPI.instance.api(
(request) => request.wpRegister(
@ -232,8 +232,8 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
if (wpUserRegisterResponse != null &&
wpUserRegisterResponse.status == 200) {
String token = wpUserRegisterResponse.data.userToken;
String userId = wpUserRegisterResponse.data.userId.toString();
String? token = wpUserRegisterResponse.data!.userToken;
String userId = wpUserRegisterResponse.data!.userId.toString();
User user = User.fromUserAuthResponse(token: token, userId: userId);
user.save(SharedKey.authUser);
@ -251,17 +251,30 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
}
}
_viewTOSModal() {
showPlatformAlertDialog(
context,
title: trans("Actions"),
subtitle: trans("View Terms and Conditions or Privacy policy"),
actions: [
dialogAction(context,
title: trans("Terms and Conditions"), action: _viewTermsConditions),
dialogAction(context,
title: trans("Privacy Policy"), action: _viewPrivacyPolicy),
],
_viewTOSModal() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(trans("Actions")),
content: Text(trans("View Terms and Conditions or Privacy policy")),
actions: <Widget>[
MaterialButton(
onPressed: _viewTermsConditions,
child: Text(trans("Terms and Conditions")),
),
MaterialButton(
onPressed: _viewPrivacyPolicy,
child: Text(trans("Privacy Policy")),
),
Divider(),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('Close'),
),
],
),
);
}
@ -277,11 +290,11 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
void _viewTermsConditions() {
Navigator.pop(context);
openBrowserTab(url: _wooSignalApp.appTermsLink);
openBrowserTab(url: _wooSignalApp!.appTermsLink!);
}
void _viewPrivacyPolicy() {
Navigator.pop(context);
openBrowserTab(url: _wooSignalApp.appPrivacyLink);
openBrowserTab(url: _wooSignalApp!.appPrivacyLink!);
}
}

View File

@ -50,12 +50,12 @@ class _AccountShippingDetailsPageState
}
_fetchUserDetails() async {
String userToken = await readAuthToken();
String? userToken = await readAuthToken();
WCCustomerInfoResponse wcCustomerInfoResponse;
WCCustomerInfoResponse? wcCustomerInfoResponse;
try {
wcCustomerInfoResponse = await WPJsonAPI.instance
.api((request) => request.wcCustomerInfo(userToken));
.api((request) => request.wcCustomerInfo(userToken!));
} on Exception catch (_) {
showToastNotification(
context,
@ -73,15 +73,15 @@ class _AccountShippingDetailsPageState
if (wcCustomerInfoResponse != null &&
wcCustomerInfoResponse.status == 200) {
Shipping shipping = wcCustomerInfoResponse.data.shipping;
_txtShippingFirstName.text = shipping.firstName;
_txtShippingLastName.text = shipping.lastName;
Shipping shipping = wcCustomerInfoResponse.data!.shipping!;
_txtShippingFirstName.text = shipping.firstName!;
_txtShippingLastName.text = shipping.lastName!;
_txtShippingAddressLine.text = shipping.address1;
_txtShippingCity.text = shipping.city;
_txtShippingState.text = shipping.state;
_txtShippingPostalCode.text = shipping.postcode;
_txtShippingCountry.text = shipping.country;
_txtShippingAddressLine.text = shipping.address1!;
_txtShippingCity.text = shipping.city!;
_txtShippingState.text = shipping.state!;
_txtShippingPostalCode.text = shipping.postcode!;
_txtShippingCountry.text = shipping.country!;
}
}
@ -172,7 +172,7 @@ class _AccountShippingDetailsPageState
],
),
decoration: BoxDecoration(
color: ThemeColor.get(context).surfaceBackground,
color: ThemeColor.get(context)!.surfaceBackground,
borderRadius: BorderRadius.circular(10),
boxShadow: (Theme.of(context).brightness ==
Brightness.light)
@ -188,9 +188,9 @@ class _AccountShippingDetailsPageState
Column(
children: <Widget>[
PrimaryButton(
title: trans("UPDATE DETAILS"),
isLoading: _isUpdating,
action: _updateShippingDetails,
title: trans("UPDATE DETAILS"),
isLoading: _isUpdating,
action: _updateShippingDetails,
),
],
),
@ -211,7 +211,7 @@ class _AccountShippingDetailsPageState
String postalCode = _txtShippingPostalCode.text;
String country = _txtShippingCountry.text;
String userToken = await readAuthToken();
String? userToken = await readAuthToken();
if (_isUpdating == true) {
return;
@ -221,7 +221,7 @@ class _AccountShippingDetailsPageState
_isUpdating = true;
});
WCCustomerUpdatedResponse wcCustomerUpdatedResponse;
WCCustomerUpdatedResponse? wcCustomerUpdatedResponse;
try {
wcCustomerUpdatedResponse = await WPJsonAPI.instance.api(
(request) => request.wcUpdateCustomerInfo(

View File

@ -17,23 +17,21 @@ import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_support/widgets/ny_state.dart';
import 'package:nylo_support/widgets/ny_stateful_widget.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/products.dart' as ws_product;
class BrowseCategoryPage extends NyStatefulWidget {
final BrowseCategoryController controller = BrowseCategoryController();
BrowseCategoryPage({Key key}) : super(key: key);
BrowseCategoryPage({Key? key}) : super(key: key);
@override
_BrowseCategoryPageState createState() => _BrowseCategoryPageState();
}
class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
ProductCategory productCategory;
ProductCategory? productCategory;
_BrowseCategoryPageState();
final RefreshController _refreshController =
@ -46,8 +44,7 @@ class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
bool _isLoading = true;
@override
widgetDidLoad() async {
super.widgetDidLoad();
init() async {
productCategory = widget.controller.data();
await fetchProducts();
}
@ -66,7 +63,7 @@ class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(trans("Browse"), style: Theme.of(context).textTheme.subtitle1),
Text(parseHtmlString(productCategory.name))
Text(parseHtmlString(productCategory!.name))
],
),
centerTitle: true,
@ -115,7 +112,7 @@ class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
}
}
_sortProducts({@required SortByType by}) {
_sortProducts({required SortByType by}) {
List<ws_product.Product> products =
_productCategorySearchLoaderController.getResults();
switch (by) {
@ -133,12 +130,12 @@ class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
break;
case SortByType.nameAZ:
products.sort(
(product1, product2) => product1.name.compareTo(product2.name),
(product1, product2) => product1.name!.compareTo(product2.name!),
);
break;
case SortByType.nameZA:
products.sort(
(product1, product2) => product2.name.compareTo(product1.name),
(product1, product2) => product2.name!.compareTo(product1.name!),
);
break;
}

View File

@ -14,15 +14,13 @@ import 'package:flutter_app/app/controllers/product_search_loader_controller.dar
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_support/widgets/ny_state.dart';
import 'package:nylo_support/widgets/ny_stateful_widget.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/products.dart' as ws_product;
class BrowseSearchPage extends NyStatefulWidget {
final BrowseSearchController controller = BrowseSearchController();
BrowseSearchPage({Key key}) : super(key: key);
BrowseSearchPage({Key? key}) : super(key: key);
@override
_BrowseSearchState createState() => _BrowseSearchState();
@ -34,12 +32,11 @@ class _BrowseSearchState extends NyState<BrowseSearchPage> {
final ProductSearchLoaderController _productSearchLoaderController =
ProductSearchLoaderController();
String _search;
String? _search;
bool _shouldStopRequests = false, _isLoading = true;
@override
widgetDidLoad() async {
super.widgetDidLoad();
init() async {
_search = widget.controller.data();
await fetchProducts();
}
@ -59,7 +56,7 @@ class _BrowseSearchState extends NyState<BrowseSearchPage> {
children: <Widget>[
Text(trans("Search results for"),
style: Theme.of(context).textTheme.subtitle1),
Text("\"" + _search + "\"")
Text("\"" + _search! + "\"")
],
),
centerTitle: true,

View File

@ -56,7 +56,7 @@ class _CartPageState extends State<CartPage> {
List<Map<String, dynamic>> cartJSON = cart.map((c) => c.toJson()).toList();
List<dynamic> cartRes =
await appWooSignal((api) => api.cartCheck(cartJSON));
await (appWooSignal((api) => api.cartCheck(cartJSON)));
if (cartRes.isEmpty) {
Cart.getInstance.saveCartToPref(cartLineItems: []);
setState(() {
@ -105,17 +105,17 @@ class _CartPageState extends State<CartPage> {
}
CheckoutSession.getInstance.initSession();
CustomerAddress sfCustomerAddress =
CustomerAddress? sfCustomerAddress =
await CheckoutSession.getInstance.getBillingAddress();
if (sfCustomerAddress != null) {
CheckoutSession.getInstance.billingDetails.billingAddress =
CheckoutSession.getInstance.billingDetails!.billingAddress =
sfCustomerAddress;
CheckoutSession.getInstance.billingDetails.shippingAddress =
CheckoutSession.getInstance.billingDetails!.shippingAddress =
sfCustomerAddress;
}
if (AppHelper.instance.appConfig.wpLoginEnabled == 1 &&
if (AppHelper.instance.appConfig!.wpLoginEnabled == 1 &&
!(await authCheck())) {
UserAuth.instance.redirect = "/checkout";
Navigator.pushNamed(context, "/account-landing");
@ -125,9 +125,9 @@ class _CartPageState extends State<CartPage> {
Navigator.pushNamed(context, "/checkout");
}
actionIncrementQuantity({CartLineItem cartLineItem}) {
if (cartLineItem.isManagedStock &&
cartLineItem.quantity + 1 > cartLineItem.stockQuantity) {
actionIncrementQuantity({required CartLineItem cartLineItem}) {
if (cartLineItem.isManagedStock! &&
cartLineItem.quantity + 1 > cartLineItem.stockQuantity!) {
showToastNotification(
context,
title: trans("Cart"),
@ -143,7 +143,7 @@ class _CartPageState extends State<CartPage> {
setState(() {});
}
actionDecrementQuantity({CartLineItem cartLineItem}) {
actionDecrementQuantity({required CartLineItem cartLineItem}) {
if (cartLineItem.quantity - 1 <= 0) {
return;
}
@ -153,7 +153,7 @@ class _CartPageState extends State<CartPage> {
setState(() {});
}
actionRemoveItem({int index}) {
actionRemoveItem({required int index}) {
Cart.getInstance.removeCartItemForIndex(index: index);
_cartLines.removeAt(index);
showToastNotification(

View File

@ -8,6 +8,7 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/checkout_session.dart';
@ -30,7 +31,7 @@ import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
class CheckoutConfirmationPage extends StatefulWidget {
CheckoutConfirmationPage({Key key}) : super(key: key);
CheckoutConfirmationPage({Key? key}) : super(key: key);
@override
CheckoutConfirmationPageState createState() =>
@ -43,14 +44,14 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
bool _showFullLoader = true, _isProcessingPayment = false;
final List<TaxRate> _taxRates = [];
TaxRate _taxRate;
final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
TaxRate? _taxRate;
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
@override
void initState() {
super.initState();
CheckoutSession.getInstance.coupon = null;
List<PaymentType> paymentTypes = getPaymentTypes();
List<PaymentType?> paymentTypes = getPaymentTypes();
if (CheckoutSession.getInstance.paymentType == null &&
paymentTypes.isNotEmpty) {
CheckoutSession.getInstance.paymentType = paymentTypes.first;
@ -58,9 +59,9 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_getTaxes();
}
reloadState({@required bool showLoader}) {
reloadState({required bool showLoader}) {
setState(() {
_showFullLoader = showLoader ?? false;
_showFullLoader = showLoader;
});
}
@ -68,10 +69,10 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
int pageIndex = 1;
bool fetchMore = true;
while (fetchMore == true) {
List<TaxRate> tmpTaxRates = await appWooSignal(
(api) => api.getTaxRates(page: pageIndex, perPage: 100));
List<TaxRate> tmpTaxRates = await (appWooSignal(
(api) => api.getTaxRates(page: pageIndex, perPage: 100)));
if (tmpTaxRates != null && tmpTaxRates.isNotEmpty) {
if (tmpTaxRates.isNotEmpty) {
_taxRates.addAll(tmpTaxRates);
}
if (tmpTaxRates.length >= 100) {
@ -81,7 +82,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
}
}
if (_taxRates == null || _taxRates.isEmpty) {
if (_taxRates.isEmpty) {
setState(() {
_showFullLoader = false;
});
@ -89,16 +90,16 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
}
if (CheckoutSession.getInstance.billingDetails == null ||
CheckoutSession.getInstance.billingDetails.shippingAddress == null) {
CheckoutSession.getInstance.billingDetails!.shippingAddress == null) {
setState(() {
_showFullLoader = false;
});
return;
}
CustomerCountry shippingCountry = CheckoutSession
.getInstance.billingDetails.shippingAddress.customerCountry;
String postalCode =
CheckoutSession.getInstance.billingDetails.shippingAddress.postalCode;
CustomerCountry? shippingCountry = CheckoutSession
.getInstance.billingDetails!.shippingAddress!.customerCountry;
String? postalCode =
CheckoutSession.getInstance.billingDetails!.shippingAddress!.postalCode;
if (shippingCountry == null) {
_showFullLoader = false;
@ -106,15 +107,14 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
return;
}
TaxRate taxRate;
TaxRate? taxRate;
if (shippingCountry.hasState()) {
taxRate = _taxRates.firstWhere((t) {
if (shippingCountry == null ||
(shippingCountry?.state?.code ?? "") == "") {
taxRate = _taxRates.firstWhereOrNull((t) {
if ((shippingCountry.state?.code ?? "") == "") {
return false;
}
List<String> stateElements = shippingCountry.state.code.split(":");
List<String> stateElements = shippingCountry.state!.code!.split(":");
String state = stateElements.last;
if (t.country == shippingCountry.countryCode &&
@ -127,20 +127,18 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
return true;
}
return false;
}, orElse: () => null);
});
}
if (taxRate == null) {
taxRate = _taxRates.firstWhere(
taxRate = _taxRates.firstWhereOrNull(
(t) =>
t.country == shippingCountry.countryCode &&
t.postcode == postalCode,
orElse: () => null,
);
taxRate ??= _taxRates.firstWhere(
taxRate ??= _taxRates.firstWhereOrNull(
(t) => t.country == shippingCountry.countryCode,
orElse: () => null,
);
}
@ -157,19 +155,21 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
CheckoutSession checkoutSession = CheckoutSession.getInstance;
if (_showFullLoader == true) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AppLoaderWidget(),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
"${trans("One moment")}...",
style: Theme.of(context).textTheme.subtitle1,
),
)
],
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
AppLoaderWidget(),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
"${trans("One moment")}...",
style: Theme.of(context).textTheme.subtitle1,
),
)
],
),
),
);
}
@ -199,7 +199,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
child: Container(
padding: EdgeInsets.only(left: 10, right: 10),
decoration: BoxDecoration(
color: ThemeColor.get(context).backgroundContainer,
color: ThemeColor.get(context)!.backgroundContainer,
borderRadius: BorderRadius.circular(10),
boxShadow: (Theme.of(context).brightness == Brightness.light)
? wsBoxShadow()
@ -232,10 +232,10 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
resetState: () => setState(() {}),
wooSignalApp: _wooSignalApp,
),
].where((e) => e != null).toList()),
]),
),
),
if (_wooSignalApp.couponEnabled == true)
if (_wooSignalApp!.couponEnabled == true)
CheckoutSelectCouponWidget(
context: context,
checkoutSession: checkoutSession,
@ -244,7 +244,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
children: [
Divider(
color: Colors.black12,
thickness: 1,
@ -253,21 +253,20 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
title: trans("Subtotal"),
),
CheckoutCouponAmountWidget(checkoutSession: checkoutSession),
_wooSignalApp.disableShipping == 1
? null
: CheckoutMetaLine(
title: trans("Shipping fee"),
amount: CheckoutSession.getInstance.shippingType == null
? trans("Select shipping")
: CheckoutSession.getInstance.shippingType
.getTotal(withFormatting: true)),
(_taxRate != null ? CheckoutTaxTotal(taxRate: _taxRate) : null),
if (_wooSignalApp!.disableShipping != 1)
CheckoutMetaLine(
title: trans("Shipping fee"),
amount: CheckoutSession.getInstance.shippingType == null
? trans("Select shipping")
: CheckoutSession.getInstance.shippingType!
.getTotal(withFormatting: true)),
if (_taxRate != null) CheckoutTaxTotal(taxRate: _taxRate),
CheckoutTotal(title: trans("Total"), taxRate: _taxRate),
Divider(
color: Colors.black12,
thickness: 1,
),
].where((e) => e != null).toList(),
],
),
PrimaryButton(
title: _isProcessingPayment
@ -283,7 +282,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_handleCheckout() async {
CheckoutSession checkoutSession = CheckoutSession.getInstance;
if (checkoutSession.billingDetails.billingAddress == null) {
if (checkoutSession.billingDetails!.billingAddress == null) {
showToastNotification(
context,
title: trans("Oops"),
@ -295,7 +294,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
return;
}
if (checkoutSession.billingDetails.billingAddress.hasMissingFields()) {
if (checkoutSession.billingDetails!.billingAddress!.hasMissingFields()) {
showToastNotification(
context,
title: trans("Oops"),
@ -306,7 +305,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
return;
}
if (_wooSignalApp.disableShipping == 0 &&
if (_wooSignalApp!.disableShipping == 0 &&
checkoutSession.shippingType == null) {
showToastNotification(
context,
@ -329,28 +328,27 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
return;
}
if (_wooSignalApp.disableShipping == 0 &&
if (_wooSignalApp!.disableShipping == 0 &&
checkoutSession.shippingType?.minimumValue != null) {
String total = await Cart.getInstance.getTotal();
if (total == null) {
return;
}
double doubleTotal = double.parse(total);
double doubleMinimumValue =
double.parse(checkoutSession.shippingType?.minimumValue);
double.parse(checkoutSession.shippingType!.minimumValue!);
if (doubleTotal < doubleMinimumValue) {
showToastNotification(context,
title: trans("Sorry"),
description:
"${trans("Spend a minimum of")} ${formatDoubleCurrency(total: doubleMinimumValue)} ${trans("for")} ${checkoutSession.shippingType.getTitle()}",
"${trans("Spend a minimum of")} ${formatDoubleCurrency(total: doubleMinimumValue)} ${trans("for")} ${checkoutSession.shippingType!.getTitle()}",
style: ToastNotificationStyleType.INFO,
duration: Duration(seconds: 3));
return;
}
}
bool appStatus = await appWooSignal((api) => api.checkAppStatus());
bool appStatus = await (appWooSignal((api) => api.checkAppStatus()));
if (!appStatus) {
showToastNotification(context,
@ -369,7 +367,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_isProcessingPayment = true;
});
await checkoutSession.paymentType
await checkoutSession.paymentType!
.pay(context, state: this, taxRate: _taxRate);
setState(() {

View File

@ -22,6 +22,8 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:validated/validated.dart' as validate;
import '../../app/models/default_shipping.dart';
class CheckoutDetailsPage extends StatefulWidget {
CheckoutDetailsPage();
@ -32,7 +34,7 @@ class CheckoutDetailsPage extends StatefulWidget {
class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
_CheckoutDetailsPageState();
bool _hasDifferentShippingAddress = false, valRememberDetails = true;
bool? _hasDifferentShippingAddress = false, valRememberDetails = true;
int activeTabIndex = 0;
// TEXT CONTROLLERS
@ -53,9 +55,9 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
_txtShippingPostalCode = TextEditingController(),
_txtShippingEmailAddress = TextEditingController();
CustomerCountry _billingCountry, _shippingCountry;
CustomerCountry? _billingCountry, _shippingCountry;
Widget activeTab;
Widget? activeTab;
Widget tabShippingDetails() => CustomerAddressInput(
txtControllerFirstName: _txtShippingFirstName,
@ -84,12 +86,13 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
void initState() {
super.initState();
if (CheckoutSession.getInstance.billingDetails.billingAddress == null) {
CheckoutSession.getInstance.billingDetails.initSession();
CheckoutSession.getInstance.billingDetails.shippingAddress.initAddress();
CheckoutSession.getInstance.billingDetails.billingAddress.initAddress();
if (CheckoutSession.getInstance.billingDetails!.billingAddress == null) {
CheckoutSession.getInstance.billingDetails!.initSession();
CheckoutSession.getInstance.billingDetails!.shippingAddress!
.initAddress();
CheckoutSession.getInstance.billingDetails!.billingAddress!.initAddress();
}
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails;
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails!;
_setFieldsFromCustomerAddress(billingDetails.billingAddress,
type: "billing");
_setFieldsFromCustomerAddress(billingDetails.shippingAddress,
@ -102,20 +105,18 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
}
_setCustomersDetails() async {
CustomerAddress sfCustomerBillingAddress =
CustomerAddress? sfCustomerBillingAddress =
await CheckoutSession.getInstance.getBillingAddress();
_setFieldsFromCustomerAddress(sfCustomerBillingAddress, type: "billing");
CustomerAddress sfCustomerShippingAddress =
CustomerAddress? sfCustomerShippingAddress =
await CheckoutSession.getInstance.getShippingAddress();
_setFieldsFromCustomerAddress(sfCustomerShippingAddress, type: "shipping");
setState(() {
});
setState(() {});
}
_setFieldsFromCustomerAddress(CustomerAddress customerAddress,
{@required String type}) {
_setFieldsFromCustomerAddress(CustomerAddress? customerAddress,
{required String type}) {
assert(type != "");
if (customerAddress == null) {
return;
@ -134,31 +135,31 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
}
_setFields(
{@required String firstName,
@required String lastName,
@required String addressLine,
@required String city,
@required String postalCode,
@required String emailAddress,
@required String phoneNumber,
@required CustomerCountry customerCountry,
String type}) {
{required String? firstName,
required String? lastName,
required String? addressLine,
required String? city,
required String? postalCode,
required String? emailAddress,
required String? phoneNumber,
required CustomerCountry? customerCountry,
String? type}) {
if (type == "billing") {
_txtBillingFirstName.text = firstName;
_txtBillingLastName.text = lastName;
_txtBillingAddressLine.text = addressLine;
_txtBillingCity.text = city;
_txtBillingPostalCode.text = postalCode;
_txtBillingPhoneNumber.text = phoneNumber;
_txtBillingEmailAddress.text = emailAddress;
_txtBillingFirstName.text = firstName!;
_txtBillingLastName.text = lastName!;
_txtBillingAddressLine.text = addressLine!;
_txtBillingCity.text = city!;
_txtBillingPostalCode.text = postalCode!;
_txtBillingPhoneNumber.text = phoneNumber!;
_txtBillingEmailAddress.text = emailAddress!;
_billingCountry = customerCountry;
} else if (type == "shipping") {
_txtShippingFirstName.text = firstName;
_txtShippingLastName.text = lastName;
_txtShippingAddressLine.text = addressLine;
_txtShippingCity.text = city;
_txtShippingPostalCode.text = postalCode;
_txtShippingEmailAddress.text = emailAddress;
_txtShippingFirstName.text = firstName!;
_txtShippingLastName.text = lastName!;
_txtShippingAddressLine.text = addressLine!;
_txtShippingCity.text = city!;
_txtShippingPostalCode.text = postalCode!;
_txtShippingEmailAddress.text = emailAddress!;
_shippingCountry = customerCountry;
}
}
@ -185,59 +186,56 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (_hasDifferentShippingAddress)
Container(
margin: EdgeInsets.symmetric(vertical: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Padding(
child: Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: <Widget>[
SwitchAddressTab(
title: trans("Billing Details"),
currentTabIndex: activeTabIndex,
type: "billing",
onTapAction: () => setState(() {
activeTabIndex = 0;
activeTab = tabBillingDetails();
})),
SwitchAddressTab(
title: trans("Shipping Address"),
currentTabIndex: activeTabIndex,
type: "shipping",
onTapAction: () => setState(() {
activeTabIndex = 1;
activeTab =
tabShippingDetails();
})),
].where((e) => e != null).toList(),
),
padding: EdgeInsets.symmetric(vertical: 4),
),
].where((e) => e != null).toList(),
if (_hasDifferentShippingAddress!)
Container(
margin: EdgeInsets.symmetric(vertical: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Padding(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: <Widget>[
SwitchAddressTab(
title: trans("Billing Details"),
currentTabIndex: activeTabIndex,
type: "billing",
onTapAction: () => setState(() {
activeTabIndex = 0;
activeTab = tabBillingDetails();
})),
SwitchAddressTab(
title: trans("Shipping Address"),
currentTabIndex: activeTabIndex,
type: "shipping",
onTapAction: () => setState(() {
activeTabIndex = 1;
activeTab = tabShippingDetails();
})),
],
),
padding: EdgeInsets.symmetric(vertical: 4),
),
],
),
height: 60,
),
height: 60,
),
Expanded(
child: Container(
decoration: BoxDecoration(
color: ThemeColor.get(context).backgroundContainer,
borderRadius: BorderRadius.circular(10),
boxShadow:
(Theme.of(context).brightness == Brightness.light)
? wsBoxShadow()
: null,
),
padding: EdgeInsets.only(left: 8, right: 8, top: 8),
margin: EdgeInsets.only(top: 8),
child: (activeTab ?? tabBillingDetails())
),
decoration: BoxDecoration(
color: ThemeColor.get(context)!.backgroundContainer,
borderRadius: BorderRadius.circular(10),
boxShadow: (Theme.of(context).brightness ==
Brightness.light)
? wsBoxShadow()
: null,
),
padding: EdgeInsets.only(left: 8, right: 8, top: 8),
margin: EdgeInsets.only(top: 8),
child: (activeTab ?? tabBillingDetails())),
),
],
),
@ -270,7 +268,7 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
),
Checkbox(
value: valRememberDetails,
onChanged: (bool value) {
onChanged: (bool? value) {
setState(() {
valRememberDetails = value;
});
@ -294,19 +292,19 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
_useDetailsTapped() async {
CustomerAddress customerBillingAddress = _setCustomerAddress(
firstName: _txtBillingFirstName.text,
lastName: _txtBillingLastName.text,
addressLine: _txtBillingAddressLine.text,
city: _txtBillingCity.text,
postalCode: _txtBillingPostalCode.text,
phoneNumber: _txtBillingPhoneNumber.text,
emailAddress: _txtBillingEmailAddress.text,
customerCountry: _billingCountry,
firstName: _txtBillingFirstName.text,
lastName: _txtBillingLastName.text,
addressLine: _txtBillingAddressLine.text,
city: _txtBillingCity.text,
postalCode: _txtBillingPostalCode.text,
phoneNumber: _txtBillingPhoneNumber.text,
emailAddress: _txtBillingEmailAddress.text,
customerCountry: _billingCountry,
);
CheckoutSession.getInstance.billingDetails.shippingAddress =
CheckoutSession.getInstance.billingDetails!.shippingAddress =
customerBillingAddress;
CheckoutSession.getInstance.billingDetails.billingAddress =
CheckoutSession.getInstance.billingDetails!.billingAddress =
customerBillingAddress;
if (_hasDifferentShippingAddress == true) {
@ -353,7 +351,7 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
return;
}
CheckoutSession.getInstance.billingDetails.shippingAddress =
CheckoutSession.getInstance.billingDetails!.shippingAddress =
customerShippingAddress;
}
@ -365,7 +363,7 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
await CheckoutSession.getInstance.clearShippingAddress();
}
CheckoutSession.getInstance.billingDetails.rememberDetails =
CheckoutSession.getInstance.billingDetails!.rememberDetails =
valRememberDetails;
CheckoutSession.getInstance.shipToDifferentAddress =
_hasDifferentShippingAddress;
@ -374,12 +372,12 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
Navigator.pop(context);
}
_onChangeShipping(bool value) async {
_onChangeShipping(bool? value) async {
_hasDifferentShippingAddress = value;
activeTabIndex = 1;
activeTab = value == true ? tabShippingDetails() : tabBillingDetails();
CustomerAddress sfCustomerShippingAddress =
CustomerAddress? sfCustomerShippingAddress =
await CheckoutSession.getInstance.getShippingAddress();
if (sfCustomerShippingAddress == null) {
_setFields(
@ -396,14 +394,14 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
}
CustomerAddress _setCustomerAddress(
{@required String firstName,
@required String lastName,
@required String addressLine,
@required String city,
@required String postalCode,
@required String emailAddress,
String phoneNumber,
@required CustomerCountry customerCountry}) {
{required String firstName,
required String lastName,
required String addressLine,
required String city,
required String postalCode,
required String emailAddress,
String? phoneNumber,
required CustomerCountry? customerCountry}) {
CustomerAddress customerShippingAddress = CustomerAddress();
customerShippingAddress.firstName = firstName;
customerShippingAddress.lastName = lastName;
@ -418,18 +416,18 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
return customerShippingAddress;
}
_navigateToSelectCountry({@required String type}) {
_navigateToSelectCountry({required String type}) {
Navigator.pushNamed(context, "/customer-countries").then((value) {
if (value == null) {
return;
}
if (type == "billing") {
_billingCountry =
CustomerCountry.fromDefaultShipping(defaultShipping: value);
_billingCountry = CustomerCountry.fromDefaultShipping(
defaultShipping: value as DefaultShipping);
activeTab = tabBillingDetails();
} else if (type == "shipping") {
_shippingCountry =
CustomerCountry.fromDefaultShipping(defaultShipping: value);
_shippingCountry = CustomerCountry.fromDefaultShipping(
defaultShipping: value as DefaultShipping);
activeTab = tabShippingDetails();
}
setState(() {});

View File

@ -16,7 +16,6 @@ import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:nylo_support/helpers/helper.dart';
class CheckoutPaymentTypePage extends StatefulWidget {
CheckoutPaymentTypePage();
@ -34,7 +33,7 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
super.initState();
if (CheckoutSession.getInstance.paymentType == null) {
if (getPaymentTypes() != null && getPaymentTypes().isNotEmpty) {
if (getPaymentTypes().isNotEmpty) {
CheckoutSession.getInstance.paymentType = getPaymentTypes().first;
}
}
@ -42,7 +41,7 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
@override
Widget build(BuildContext context) {
List<PaymentType> paymentTypes = getPaymentTypes();
List<PaymentType?> paymentTypes = getPaymentTypes();
if (paymentTypes.isEmpty &&
getEnv('APP_DEBUG', defaultValue: false) == true) {
NyLogger.info(
@ -91,7 +90,7 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
itemBuilder:
(BuildContext context, int index) {
PaymentType paymentType =
paymentTypes[index];
paymentTypes[index]!;
return ListTile(
contentPadding: EdgeInsets.only(
top: 10,
@ -139,7 +138,7 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
],
),
decoration: BoxDecoration(
color: ThemeColor.get(context).backgroundContainer,
color: ThemeColor.get(context)!.backgroundContainer,
borderRadius: BorderRadius.circular(10),
boxShadow:
(Theme.of(context).brightness == Brightness.light)

View File

@ -8,6 +8,7 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/cart_line_item.dart';
@ -20,7 +21,7 @@ import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/shipping_method.dart';
class CheckoutShippingTypePage extends StatefulWidget {
@ -36,7 +37,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
bool _isShippingSupported = true, _isLoading = true;
final List<Map<String, dynamic>> _wsShippingOptions = [];
WSShipping _shipping;
WSShipping? _shipping;
@override
void initState() {
@ -46,12 +47,12 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
_getShippingMethods() async {
List<WSShipping> wsShipping =
await appWooSignal((api) => api.getShippingMethods());
await (appWooSignal((api) => api.getShippingMethods()));
CustomerAddress customerAddress =
CheckoutSession.getInstance.billingDetails.shippingAddress;
String postalCode = customerAddress.postalCode;
CustomerCountry customerCountry = customerAddress.customerCountry;
CheckoutSession.getInstance.billingDetails!.shippingAddress!;
String? postalCode = customerAddress.postalCode;
CustomerCountry? customerCountry = customerAddress.customerCountry;
if (customerCountry == null) {
setState(() {
@ -65,7 +66,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
continue;
}
Locations location = shipping.locations.firstWhere(
Locations? location = shipping.locations!.firstWhereOrNull(
(ws) {
if (customerCountry.countryCode == null || ws.code == null) {
return false;
@ -74,7 +75,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
if (ws.type == "state") {
if (customerCountry.state != null &&
(customerCountry.state?.code ?? "") != "") {
return ws.code == customerCountry.state.code;
return ws.code == customerCountry.state!.code;
}
}
@ -88,7 +89,6 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
return false;
},
orElse: () => null,
);
if (location != null) {
@ -100,8 +100,8 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
await _handleShippingZones(_shipping);
if (_shipping == null) {
WSShipping noZones = wsShipping
.firstWhere((element) => element.parentId == 0, orElse: () => null);
WSShipping? noZones =
wsShipping.firstWhereOrNull((element) => element.parentId == 0);
await _handleShippingZones(noZones);
}
if (_wsShippingOptions.isEmpty) {
@ -117,38 +117,40 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
double total = 0;
List<CartLineItem> cartLineItem = await Cart.getInstance.getCart();
total +=
await workoutShippingCostWC(sum: _wsShippingOptions[index]['cost']);
total += (await (workoutShippingCostWC(
sum: _wsShippingOptions[index]['cost']))) ??
0;
switch (_wsShippingOptions[index]['method_id']) {
case "flat_rate":
FlatRate flatRate = (_wsShippingOptions[index]['object'] as FlatRate);
FlatRate? flatRate = (_wsShippingOptions[index]['object'] as FlatRate?);
if (cartLineItem.firstWhere(
(t) => t.shippingClassId == null || t.shippingClassId == "0",
orElse: () => null) !=
if (cartLineItem.firstWhereOrNull(
(t) => t.shippingClassId == null || t.shippingClassId == "0") !=
null) {
total += await workoutShippingClassCostWC(
sum: flatRate.classCost,
cartLineItem: cartLineItem
.where((t) =>
t.shippingClassId == null || t.shippingClassId == "0")
.toList());
total += await (workoutShippingClassCostWC(
sum: flatRate!.classCost,
cartLineItem: cartLineItem
.where((t) =>
t.shippingClassId == null || t.shippingClassId == "0")
.toList())) ??
0;
}
List<CartLineItem> cItemsWithShippingClasses = cartLineItem
.where((t) => t.shippingClassId != null && t.shippingClassId != "0")
.toList();
for (int i = 0; i < cItemsWithShippingClasses.length; i++) {
ShippingClasses shippingClasses = flatRate.shippingClasses.firstWhere(
(d) => d.id == cItemsWithShippingClasses[i].shippingClassId,
orElse: () => null);
ShippingClasses? shippingClasses = flatRate!.shippingClasses!
.firstWhereOrNull(
(d) => d.id == cItemsWithShippingClasses[i].shippingClassId);
if (shippingClasses != null) {
double classTotal = await workoutShippingClassCostWC(
sum: shippingClasses.cost,
cartLineItem: cartLineItem
.where((g) => g.shippingClassId == shippingClasses.id)
.toList());
double classTotal = await (workoutShippingClassCostWC(
sum: shippingClasses.cost,
cartLineItem: cartLineItem
.where((g) => g.shippingClassId == shippingClasses.id)
.toList())) ??
0;
total += classTotal;
}
}
@ -159,13 +161,10 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
return (total).toString();
}
_handleShippingZones(WSShipping shipping) async {
_handleShippingZones(WSShipping? shipping) async {
if (shipping != null && shipping.methods != null) {
if (shipping.methods.flatRate != null) {
shipping.methods.flatRate
.where((t) => t != null)
.toList()
.forEach((flatRate) {
if (shipping.methods!.flatRate != null) {
shipping.methods!.flatRate!.toList().forEach((flatRate) {
Map<String, dynamic> tmpShippingOption = {};
tmpShippingOption = {
"id": flatRate.id,
@ -178,11 +177,8 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
});
}
if (shipping.methods.localPickup != null) {
shipping.methods.localPickup
.where((t) => t != null)
.toList()
.forEach((localPickup) {
if (shipping.methods!.localPickup != null) {
shipping.methods!.localPickup!.toList().forEach((localPickup) {
Map<String, dynamic> tmpShippingOption = {};
tmpShippingOption = {
"id": localPickup.id,
@ -195,23 +191,21 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
});
}
if (shipping.methods.freeShipping != null) {
List<FreeShipping> freeShipping =
shipping.methods.freeShipping.where((t) => t != null).toList();
if (shipping.methods!.freeShipping != null) {
List<FreeShipping> freeShipping = shipping.methods!.freeShipping!;
for (int i = 0; i < freeShipping.length; i++) {
if (isNumeric(freeShipping[i].cost) ||
freeShipping[i].cost == 'min_amount') {
if (freeShipping[i].cost == 'min_amount') {
String total = await Cart.getInstance.getTotal();
if (total != null) {
double doubleTotal = double.parse(total);
double doubleMinimumValue =
double.parse(freeShipping[i].minimumOrderAmount);
if (doubleTotal < doubleMinimumValue) {
continue;
}
double doubleTotal = double.parse(total);
double doubleMinimumValue =
double.parse(freeShipping[i].minimumOrderAmount!);
if (doubleTotal < doubleMinimumValue) {
continue;
}
}
@ -288,7 +282,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
_wsShippingOptions[index]['title'],
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(
fontWeight: FontWeight.bold,
),
@ -343,19 +337,15 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
style: Theme.of(
context)
.textTheme
.bodyText2
.bodyText2!
.copyWith(
fontSize:
14))
]
.where((e) =>
e != null)
.toList(),
],
),
);
}
}
return null;
},
),
trailing: (CheckoutSession.getInstance
@ -363,7 +353,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
null &&
CheckoutSession
.getInstance
.shippingType
.shippingType!
.object ==
_wsShippingOptions[index]
["object"]
@ -389,7 +379,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
],
),
decoration: BoxDecoration(
color: ThemeColor.get(context).backgroundContainer,
color: ThemeColor.get(context)!.backgroundContainer,
borderRadius: BorderRadius.circular(10),
boxShadow:
(Theme.of(context).brightness == Brightness.light)

View File

@ -14,29 +14,25 @@ import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:nylo_support/widgets/ny_state.dart';
import 'package:nylo_support/widgets/ny_stateful_widget.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/order.dart' as ws_order;
import 'package:nylo_support/helpers/helper.dart';
import '../widgets/woosignal_ui.dart';
class CheckoutStatusPage extends NyStatefulWidget {
final CheckoutStatusController controller = CheckoutStatusController();
CheckoutStatusPage({Key key}) : super(key: key);
CheckoutStatusPage({Key? key}) : super(key: key);
@override
_CheckoutStatusState createState() => _CheckoutStatusState();
}
class _CheckoutStatusState extends NyState<CheckoutStatusPage> {
ws_order.Order _order;
ws_order.Order? _order;
@override
widgetDidLoad() async {
super.widgetDidLoad();
init() async {
_order = widget.controller.data();
Cart.getInstance.clear();
await Cart.getInstance.clear();
CheckoutSession.getInstance.clear();
}
@ -81,7 +77,7 @@ class _CheckoutStatusState extends NyState<CheckoutStatusPage> {
textAlign: TextAlign.left,
),
Text(
"${trans("Order Ref")}. #${_order.id.toString()}",
"${trans("Order Ref")}. #${_order!.id.toString()}",
style: Theme.of(context).textTheme.bodyText1,
textAlign: TextAlign.left,
),
@ -123,10 +119,11 @@ class _CheckoutStatusState extends NyState<CheckoutStatusPage> {
),
Expanded(
child: ListView.builder(
itemCount:
_order.lineItems == null ? 0 : _order.lineItems.length,
itemCount: _order!.lineItems == null
? 0
: _order!.lineItems!.length,
itemBuilder: (BuildContext context, int index) {
ws_order.LineItems lineItem = _order.lineItems[index];
ws_order.LineItems lineItem = _order!.lineItems![index];
return Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
@ -139,7 +136,7 @@ class _CheckoutStatusState extends NyState<CheckoutStatusPage> {
MainAxisAlignment.spaceAround,
children: <Widget>[
Text(
lineItem.name,
lineItem.name!,
style:
Theme.of(context).textTheme.bodyText1,
softWrap: false,

View File

@ -20,7 +20,7 @@ class _CouponPageState extends State<CouponPage> {
final couponController = TextEditingController();
_showAlert({String message, ToastNotificationStyleType style}) {
_showAlert({required String message, ToastNotificationStyleType? style}) {
showToastNotification(
context,
title: trans('Coupon'),
@ -42,9 +42,9 @@ class _CouponPageState extends State<CouponPage> {
_isLoading = true;
});
_coupons = await appWooSignal(
_coupons = await (appWooSignal(
(api) => api.getCoupons(code: couponCode, perPage: 100),
);
));
setState(() {
_isLoading = false;
@ -81,7 +81,7 @@ class _CouponPageState extends State<CouponPage> {
autofocus: true,
controller: couponController,
validator: (value) {
if (value.isEmpty) {
if (value!.isEmpty) {
return trans('Please enter coupon to redeem');
}
return null;
@ -98,7 +98,7 @@ class _CouponPageState extends State<CouponPage> {
Radius.circular(8.0),
),
borderSide: BorderSide(
color: ThemeColor.get(context).primaryAccent)),
color: ThemeColor.get(context)!.primaryAccent)),
filled: true,
hintStyle: TextStyle(color: Colors.grey[800]),
hintText: trans('Add coupon code'),
@ -126,7 +126,7 @@ class _CouponPageState extends State<CouponPage> {
_applyCoupon(CheckoutSession checkoutSession) async {
await findCoupon(couponController.text);
if (_formKey.currentState.validate()) {
if (_formKey.currentState!.validate()) {
// No coupons found
if (_coupons.isEmpty) {
_showAlert(
@ -139,11 +139,11 @@ class _CouponPageState extends State<CouponPage> {
DateTime dateNow = DateTime.now();
List<CartLineItem> cart = await Cart.getInstance.getCart();
List<int> productIds = cart.map((e) => e.productId).toList();
List<int?> productIds = cart.map((e) => e.productId).toList();
// Check excludedProductIds
for (var productId in productIds) {
if (coupon.excludedProductIds.contains(productId)) {
if (coupon.excludedProductIds!.contains(productId)) {
_showAlert(
message:
"${trans('Sorry, this coupon can not be used with your cart')}.",
@ -153,9 +153,9 @@ class _CouponPageState extends State<CouponPage> {
}
// Check email restrictions
String emailAddress =
checkoutSession.billingDetails.billingAddress.emailAddress;
if (coupon.emailRestrictions.contains(emailAddress)) {
String? emailAddress =
checkoutSession.billingDetails!.billingAddress!.emailAddress;
if (coupon.emailRestrictions!.contains(emailAddress)) {
_showAlert(
message: trans('You cannot redeem this coupon'),
style: ToastNotificationStyleType.DANGER);
@ -163,7 +163,7 @@ class _CouponPageState extends State<CouponPage> {
}
// Check for minimum amount
double minimumAmount = double.parse(coupon.minimumAmount);
double minimumAmount = double.parse(coupon.minimumAmount!);
String strSubtotal = await Cart.getInstance.getSubtotal();
double doubleSubtotal = double.parse(strSubtotal);
if (minimumAmount != 0 && doubleSubtotal < minimumAmount) {
@ -175,7 +175,7 @@ class _CouponPageState extends State<CouponPage> {
}
// Check maximum amount
double maximumAmount = double.parse(coupon.maximumAmount);
double maximumAmount = double.parse(coupon.maximumAmount!);
if (maximumAmount != 0 && doubleSubtotal > maximumAmount) {
_showAlert(
message: trans("Spend less than maximumAmount to redeem",
@ -187,7 +187,7 @@ class _CouponPageState extends State<CouponPage> {
// Check if coupon has expired
if (coupon.dateExpires != null &&
dateNow.isAfter(
DateTime.parse(coupon.dateExpires),
DateTime.parse(coupon.dateExpires!),
)) {
_showAlert(
message: trans("This coupon has expired"),
@ -196,7 +196,8 @@ class _CouponPageState extends State<CouponPage> {
}
// Check usage limit
if (coupon.usageLimit != null && coupon.usageCount >= coupon.usageLimit) {
if (coupon.usageLimit != null &&
coupon.usageCount! >= coupon.usageLimit!) {
_showAlert(
message: trans("Usage limit has been reached"),
style: ToastNotificationStyleType.WARNING);
@ -204,11 +205,11 @@ class _CouponPageState extends State<CouponPage> {
}
// Check usage limit per user
int limitPerUser = coupon.usageLimitPerUser;
int? limitPerUser = coupon.usageLimitPerUser;
if (limitPerUser != null &&
coupon.usedBy
coupon.usedBy!
.map((e) => e.toLowerCase())
.where((usedBy) => usedBy == emailAddress.toLowerCase())
.where((usedBy) => usedBy == emailAddress!.toLowerCase())
.length >=
limitPerUser) {
_showAlert(

View File

@ -13,7 +13,7 @@ import 'package:flutter_app/app/models/default_shipping.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
class CustomerCountriesPage extends StatefulWidget {
CustomerCountriesPage();
@ -64,7 +64,7 @@ class _CustomerCountriesPageState extends State<CustomerCountriesPage> {
offset: Offset(0, 2),
),
],
color: ThemeColor.get(context).background),
color: ThemeColor.get(context)!.background),
height: 60,
child: Row(
children: [
@ -106,11 +106,11 @@ class _CustomerCountriesPageState extends State<CustomerCountriesPage> {
decoration: BoxDecoration(
// color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[200])),
border: Border.all(color: Colors.grey[200]!)),
margin: EdgeInsets.symmetric(vertical: 4),
padding:
EdgeInsets.symmetric(vertical: 16, horizontal: 8),
child: Text(defaultShipping.country),
child: Text(defaultShipping.country!),
),
);
},
@ -125,7 +125,7 @@ class _CustomerCountriesPageState extends State<CustomerCountriesPage> {
_handleOnChanged(String value) {
_activeShippingResults = _defaultShipping
.where((element) =>
element.country.toLowerCase().contains(value.toLowerCase()))
element.country!.toLowerCase().contains(value.toLowerCase()))
.toList();
setState(() {});
}
@ -151,7 +151,7 @@ class _CustomerCountriesPageState extends State<CustomerCountriesPage> {
return InkWell(
child: Container(
child: Text(
state.name,
state.name!,
style: Theme.of(context).textTheme.bodyText1,
),
padding: EdgeInsets.only(top: 25, bottom: 25),
@ -173,7 +173,7 @@ class _CustomerCountriesPageState extends State<CustomerCountriesPage> {
}
_popWithShippingResult(DefaultShipping defaultShipping,
{DefaultShippingState state}) {
{DefaultShippingState? state}) {
if (state != null) {
defaultShipping.states = [];
defaultShipping.states.add(state);

View File

@ -26,16 +26,16 @@ class _HomePageState extends State<HomePage> {
_HomePageState();
final GlobalKey _key = GlobalKey();
final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
@override
Widget build(BuildContext context) {
Widget theme =
MelloThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp);
if (AppHelper.instance.appConfig.theme == "notic") {
if (AppHelper.instance.appConfig!.theme == "notic") {
theme = NoticThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp);
}
if (AppHelper.instance.appConfig.theme == "compo") {
if (AppHelper.instance.appConfig!.theme == "compo") {
theme = CompoThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp);
}
return theme;

View File

@ -12,7 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
import '../widgets/woosignal_ui.dart';
@ -37,7 +37,7 @@ class _HomeSearchPageState extends State<HomeSearchPage> {
Navigator.pushNamed(context, "/product-search",
arguments: _txtSearchController.text)
.then((search) {
if (["notic", "compo"].contains(AppHelper.instance.appConfig.theme) ==
if (["notic", "compo"].contains(AppHelper.instance.appConfig!.theme) ==
false) {
Navigator.pop(context);
}

View File

@ -26,24 +26,24 @@ import '../../app/controllers/leave_review_controller.dart';
class LeaveReviewPage extends NyStatefulWidget {
final LeaveReviewController controller = LeaveReviewController();
LeaveReviewPage({Key key}) : super(key: key);
LeaveReviewPage({Key? key}) : super(key: key);
@override
_LeaveReviewPageState createState() => _LeaveReviewPageState();
}
class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
LineItems _lineItem;
Order _order;
LineItems? _lineItem;
Order? _order;
TextEditingController _textEditingController;
int _rating;
TextEditingController? _textEditingController;
int? _rating;
bool _isLoading = false;
@override
widgetDidLoad() async {
_lineItem = widget.controller.data()['line_item'] as LineItems;
_order = widget.controller.data()['order'] as Order;
init() async {
_lineItem = widget.controller.data()['line_item'] as LineItems?;
_order = widget.controller.data()['order'] as Order?;
_textEditingController = TextEditingController();
_rating = 5;
}
@ -74,7 +74,7 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
trans("How would you rate"),
style: Theme.of(context).textTheme.bodyText1,
),
Text(_lineItem.name),
Text(_lineItem!.name!),
Flexible(
child: Container(
child: TextField(
@ -92,7 +92,7 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
padding: EdgeInsets.only(bottom: 16),
),
RatingBar.builder(
initialRating: _rating.toDouble(),
initialRating: _rating!.toDouble(),
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: false,
@ -120,8 +120,8 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
setState(() {
_isLoading = true;
});
String review = _textEditingController.text;
wc_customer_info.Data wcCustomerInfo = await _fetchWpUserData();
String review = _textEditingController!.text;
wc_customer_info.Data? wcCustomerInfo = await _fetchWpUserData();
if (wcCustomerInfo == null) {
showToastNotification(
context,
@ -138,17 +138,19 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
try {
validator(rules: {"review": "min:5"}, data: {"review": review});
ProductReview productReview =
await appWooSignal((api) => api.createProductReview(
productId: _lineItem.productId,
ProductReview? productReview =
await (appWooSignal((api) => api.createProductReview(
productId: _lineItem!.productId,
verified: true,
review: review,
status: "approved",
reviewer: [_order.billing.firstName, _order.billing.lastName]
.join(" "),
reviewer: [
_order!.billing!.firstName,
_order!.billing!.lastName
].join(" "),
rating: _rating,
reviewerEmail: _order.billing.email,
));
reviewerEmail: _order!.billing!.email,
)));
if (productReview == null) {
showToastNotification(context,
@ -171,13 +173,13 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
}
}
Future<wc_customer_info.Data> _fetchWpUserData() async {
String userToken = await readAuthToken();
Future<wc_customer_info.Data?> _fetchWpUserData() async {
String? userToken = await readAuthToken();
wc_customer_info.WCCustomerInfoResponse wcCustomerInfoResponse;
wc_customer_info.WCCustomerInfoResponse? wcCustomerInfoResponse;
try {
wcCustomerInfoResponse = await WPJsonAPI.instance
.api((request) => request.wcCustomerInfo(userToken));
.api((request) => request.wcCustomerInfo(userToken!));
if (wcCustomerInfoResponse == null) {
return null;

View File

@ -65,7 +65,7 @@ class _NoConnectionPageState extends State<NoConnectionPage> {
}
_retry() async {
WooSignalApp wooSignalApp = await appWooSignal((api) => api.getApp());
WooSignalApp? wooSignalApp = await (appWooSignal((api) => api.getApp()));
if (wooSignalApp == null) {
showToastNotification(context,

View File

@ -30,7 +30,7 @@ import 'package:woosignal/models/response/woosignal_app.dart';
class ProductDetailPage extends NyStatefulWidget {
@override
final ProductDetailController controller = ProductDetailController();
ProductDetailPage({Key key}) : super(key: key);
ProductDetailPage({Key? key}) : super(key: key);
@override
_ProductDetailState createState() => _ProductDetailState();
@ -38,16 +38,16 @@ class ProductDetailPage extends NyStatefulWidget {
class _ProductDetailState extends NyState<ProductDetailPage> {
bool _isLoading = true;
ws_product.Product _product;
ws_product.Product? _product;
List<ws_product_variation.ProductVariation> _productVariations = [];
final Map<int, dynamic> _tmpAttributeObj = {};
final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
@override
widgetDidLoad() async {
init() async {
_product = widget.controller.data();
if (_product.type == "variable") {
if (_product!.type == "variable") {
await _fetchProductVariations();
return;
}
@ -62,15 +62,15 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
bool isFetching = true;
while (isFetching) {
List<ws_product_variation.ProductVariation> tmp = await appWooSignal(
(api) => api.getProductVariations(_product.id,
List<ws_product_variation.ProductVariation> tmp = await (appWooSignal(
(api) => api.getProductVariations(_product!.id!,
perPage: 100, page: currentPage),
);
if (tmp != null && tmp.isNotEmpty) {
));
if (tmp.isNotEmpty) {
tmpVariations.addAll(tmp);
}
if (tmp != null && tmp.length >= 100) {
if (tmp.length >= 100) {
currentPage += 1;
} else {
isFetching = false;
@ -85,26 +85,27 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
_modalBottomSheetOptionsForAttribute(int attributeIndex) {
wsModalBottom(
context,
title: "${trans("Select a")} ${_product.attributes[attributeIndex].name}",
title:
"${trans("Select a")} ${_product!.attributes[attributeIndex].name}",
bodyWidget: ListView.separated(
itemCount: _product.attributes[attributeIndex].options.length,
itemCount: _product!.attributes[attributeIndex].options!.length,
separatorBuilder: (BuildContext context, int index) => Divider(),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
_product.attributes[attributeIndex].options[index],
_product!.attributes[attributeIndex].options![index],
style: Theme.of(context).textTheme.subtitle1,
),
trailing: (_tmpAttributeObj.isNotEmpty &&
_tmpAttributeObj.containsKey(attributeIndex) &&
_tmpAttributeObj[attributeIndex]["value"] ==
_product.attributes[attributeIndex].options[index])
_product!.attributes[attributeIndex].options![index])
? Icon(Icons.check, color: Colors.blueAccent)
: null,
onTap: () {
_tmpAttributeObj[attributeIndex] = {
"name": _product.attributes[attributeIndex].name,
"value": _product.attributes[attributeIndex].options[index]
"name": _product!.attributes[attributeIndex].name,
"value": _product!.attributes[attributeIndex].options![index]
};
Navigator.pop(context, () {});
Navigator.pop(context);
@ -117,7 +118,7 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
}
_modalBottomSheetAttributes() {
ws_product_variation.ProductVariation productVariation = widget.controller
ws_product_variation.ProductVariation? productVariation = widget.controller
.findProductVariation(
tmpAttributeObj: _tmpAttributeObj,
productVariations: _productVariations);
@ -125,21 +126,21 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
context,
title: trans("Options"),
bodyWidget: ListView.separated(
itemCount: _product.attributes.length,
itemCount: _product!.attributes.length,
separatorBuilder: (BuildContext context, int index) => Divider(
color: Colors.black12,
thickness: 1,
),
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(_product.attributes[index].name,
title: Text(_product!.attributes[index].name!,
style: Theme.of(context).textTheme.subtitle1),
subtitle: (_tmpAttributeObj.isNotEmpty &&
_tmpAttributeObj.containsKey(index))
? Text(_tmpAttributeObj[index]["value"],
style: Theme.of(context).textTheme.bodyText1)
: Text(
"${trans("Select a")} ${_product.attributes[index].name}"),
"${trans("Select a")} ${_product!.attributes[index].name}"),
trailing: (_tmpAttributeObj.isNotEmpty &&
_tmpAttributeObj.containsKey(index))
? Icon(Icons.check, color: Colors.blueAccent)
@ -157,7 +158,7 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
Text(
(productVariation != null
? "${trans("Price")}: ${formatStringCurrency(total: productVariation.price)}"
: (((_product.attributes.length ==
: (((_product!.attributes.length ==
_tmpAttributeObj.values.length) &&
productVariation == null)
? trans("This variation is unavailable")
@ -175,7 +176,7 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
PrimaryButton(
title: trans("Add to cart"),
action: () async {
if (_product.attributes.length !=
if (_product!.attributes.length !=
_tmpAttributeObj.values.length) {
showToastNotification(context,
title: trans("Oops"),
@ -208,7 +209,7 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
CartLineItem cartLineItem = CartLineItem.fromProductVariation(
quantityAmount: widget.controller.quantity,
options: options,
product: _product,
product: _product!,
productVariation: productVariation,
);
@ -230,10 +231,10 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
if (_wooSignalApp.wishlistEnabled)
if (_wooSignalApp!.wishlistEnabled!)
FutureBuildWidget(
asyncFuture: hasAddedWishlistProduct(_product.id),
onValue: (isInFavourites) {
asyncFuture: hasAddedWishlistProduct(_product!.id),
onValue: (dynamic isInFavourites) {
return isInFavourites
? IconButton(
onPressed: () => widget.controller.toggleWishList(
@ -244,8 +245,9 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
onPressed: () => widget.controller.toggleWishList(
onSuccess: () => setState(() {}),
wishlistAction: WishlistAction.add),
icon: Icon(Icons.favorite_border,
color: Colors.black54));
icon: Icon(
Icons.favorite_border,
));
}),
CartIconWidget(),
],
@ -286,11 +288,11 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
}
_addItemToCart() async {
if (_product.type != "simple") {
if (_product!.type != "simple") {
_modalBottomSheetAttributes();
return;
}
if (_product.stockStatus != "instock") {
if (_product!.stockStatus != "instock") {
showToastNotification(context,
title: trans("Sorry"),
description: trans("This item is out of stock"),
@ -301,7 +303,7 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
await widget.controller.itemAddToCart(
cartLineItem: CartLineItem.fromProduct(
quantityAmount: widget.controller.quantity, product: _product),
quantityAmount: widget.controller.quantity, product: _product!),
onSuccess: () => setState(() {}));
}
}

View File

@ -12,23 +12,22 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/app/controllers/product_image_viewer_controller.dart';
import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_support/widgets/ny_state.dart';
import 'package:nylo_support/widgets/ny_stateful_widget.dart';
import 'package:flutter_swiper_tv/flutter_swiper.dart';
import 'package:nylo_framework/nylo_framework.dart';
class ProductImageViewerPage extends NyStatefulWidget {
@override
final ProductImageViewerController controller =
ProductImageViewerController();
ProductImageViewerPage({Key key}) : super(key: key);
ProductImageViewerPage({Key? key}) : super(key: key);
@override
_ProductImageViewerPageState createState() => _ProductImageViewerPageState();
}
class _ProductImageViewerPageState extends NyState<ProductImageViewerPage> {
int _initialIndex;
List<String> _arrImageSrc;
int? _initialIndex;
List<String?> _arrImageSrc = [];
@override
void initState() {
@ -43,10 +42,10 @@ class _ProductImageViewerPageState extends NyState<ProductImageViewerPage> {
return Scaffold(
body: SafeAreaWidget(
child: Column(
children: <Widget>[
children: [
Expanded(
child: Swiper(
index: _initialIndex,
index: _initialIndex!,
itemBuilder: (BuildContext context, int index) =>
CachedImageWidget(
image: (_arrImageSrc.isEmpty

View File

@ -8,6 +8,7 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:collection/collection.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/app/controllers/product_reviews_loader_controller.dart';
@ -25,7 +26,7 @@ import '../../app/controllers/product_reviews_controller.dart';
class ProductReviewsPage extends NyStatefulWidget {
final ProductReviewsController controller = ProductReviewsController();
ProductReviewsPage({Key key}) : super(key: key);
ProductReviewsPage({Key? key}) : super(key: key);
@override
_ProductReviewsPageState createState() => _ProductReviewsPageState();
@ -34,14 +35,14 @@ class ProductReviewsPage extends NyStatefulWidget {
class _ProductReviewsPageState extends NyState<ProductReviewsPage> {
final RefreshController _refreshController =
RefreshController(initialRefresh: false);
Product _product;
Product? _product;
bool _shouldStopRequests = false, _isLoading = true;
final ProductReviewsLoaderController _productReviewsLoaderController =
ProductReviewsLoaderController();
@override
widgetDidLoad() async {
_product = widget.data() as Product;
init() async {
_product = widget.data() as Product?;
await fetchProductReviews();
}
@ -63,113 +64,116 @@ class _ProductReviewsPageState extends NyState<ProductReviewsPage> {
? AppLoaderWidget()
: SafeArea(
child: Column(
// shrinkWrap: true,
children: [
Container(
height: mediaQuery.size.height / 5,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
margin: EdgeInsets.symmetric(vertical: 16),
decoration: BoxDecoration(
border:
Border(bottom: BorderSide(color: Colors.black12))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
_product.name,
style: Theme.of(context).textTheme.headline6,
),
),
Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
_product.ratingCount.toString() + " Reviews",
style: Theme.of(context).textTheme.bodyText2,
),
),
Row(
children: [
Container(
margin: EdgeInsets.only(right: 8),
child: Text(
_product.averageRating + " Stars",
style: Theme.of(context).textTheme.bodyText2,
),
// shrinkWrap: true,
children: [
Container(
height: mediaQuery.size.height / 5,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
margin: EdgeInsets.symmetric(vertical: 16),
decoration: BoxDecoration(
border:
Border(bottom: BorderSide(color: Colors.black12))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
_product!.name!,
style: Theme.of(context).textTheme.headline6,
),
RatingBarIndicator(
rating: double.parse(_product.averageRating),
itemBuilder: (context, index) => Icon(
Icons.star,
color: Colors.amber,
),
itemCount: 5,
itemSize: 20.0,
direction: Axis.horizontal,
),
Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
_product!.ratingCount.toString() + " Reviews",
style: Theme.of(context).textTheme.bodyText2,
),
],
),
],
),
Row(
children: [
Container(
margin: EdgeInsets.only(right: 8),
child: Text(
_product!.averageRating! + " Stars",
style: Theme.of(context).textTheme.bodyText2,
),
),
RatingBarIndicator(
rating: double.parse(_product!.averageRating!),
itemBuilder: (context, index) => Icon(
Icons.star,
color: Colors.amber,
),
itemCount: 5,
itemSize: 20.0,
direction: Axis.horizontal,
),
],
),
],
),
),
),
Expanded(
Expanded(
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: (productReviews.length != null &&
productReviews.isNotEmpty
? StaggeredGridView.countBuilder(
crossAxisCount: 2,
scrollDirection: Axis.vertical,
itemCount: productReviews.length,
itemBuilder: (BuildContext context, int index) {
ProductReview productReview = productReviews[index];
return Container(
padding: EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
margin: EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.black12))),
child: ProductReviewItemContainerWidget(
productReview: productReview),
);
},
staggeredTileBuilder: (int index) {
return StaggeredTile.fit(2);
},
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
)
: NoResultsForProductsWidget()),
))
],
)),
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: (productReviews.isNotEmpty
? StaggeredGrid.count(
crossAxisCount: 2,
axisDirection: AxisDirection.down,
children:
productReviews.mapIndexed((index, value) {
ProductReview productReview =
productReviews[index];
return StaggeredGridTile.fit(
crossAxisCellCount: 2,
// mainAxisCellCount: 2,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 16, vertical: 8),
margin: EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.black12))),
child: ProductReviewItemContainerWidget(
productReview: productReview),
));
}).toList(),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
)
: NoResultsForProductsWidget()),
),
)
],
),
),
);
}

View File

@ -12,7 +12,7 @@ class WishListPageWidget extends StatefulWidget {
class _WishListPageWidgetState extends State<WishListPageWidget> {
List<Product> _products = [];
bool isLoading;
bool? isLoading;
@override
void initState() {
@ -31,12 +31,12 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
});
return;
}
_products = await appWooSignal((api) => api.getProducts(
_products = await (appWooSignal((api) => api.getProducts(
include: productIds,
perPage: 100,
status: "publish",
stockStatus: "instock",
));
)));
setState(() {
isLoading = false;
});
@ -50,7 +50,7 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
title: Text(trans("Wishlist")),
),
body: SafeArea(
child: isLoading
child: isLoading!
? AppLoaderWidget()
: _products.isEmpty && isLoading == false
? Center(
@ -68,9 +68,9 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
Text(trans("No items found"),
style: Theme.of(context)
.textTheme
.headline6
.setColor(
context, (color) => color.primaryContent))
.headline6!
.setColor(context,
(color) => color!.primaryContent))
],
),
)
@ -86,6 +86,7 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
child: Row(
children: [
Container(
margin: EdgeInsets.only(left: 8),
child: CachedImageWidget(
image: (product.images.isNotEmpty
? product.images.first.src
@ -103,7 +104,13 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(product.name),
Text(
product.name!,
style: TextStyle(
fontWeight: FontWeight.bold),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
Text(
formatStringCurrency(
total: product.price),
@ -113,7 +120,7 @@ class _WishListPageWidgetState extends State<WishListPageWidget> {
),
),
Container(
width: 100,
width: MediaQuery.of(context).size.width / 5,
alignment: Alignment.center,
child: IconButton(
icon: Icon(

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/config/app_font.dart';
import 'package:flutter_app/config/font.dart';
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
import 'package:flutter_app/resources/themes/text_theme/default_text_theme.dart';
import 'package:google_fonts/google_fonts.dart';
@ -11,14 +11,14 @@ import 'package:nylo_framework/nylo_framework.dart';
|--------------------------------------------------------------------------
| Dark Theme
|
| Theme Config - config/app_theme.dart
| Theme Config - config/theme.dart
|--------------------------------------------------------------------------
*/
ThemeData darkTheme(BaseColorStyles darkColors) {
try {
appFont = GoogleFonts.getFont(
AppHelper.instance.appConfig.themeFont ?? "Poppins");
AppHelper.instance.appConfig!.themeFont ?? "Poppins");
} on Exception catch (e) {
if (getEnv('APP_DEBUG') == true) {
NyLogger.error(e.toString());
@ -37,7 +37,7 @@ ThemeData darkTheme(BaseColorStyles darkColors) {
scaffoldBackgroundColor: darkColors.background,
appBarTheme: AppBarTheme(
backgroundColor: darkColors.appBarBackground,
titleTextStyle: darkTheme.headline6
titleTextStyle: darkTheme.headline6!
.copyWith(color: darkColors.appBarPrimaryContent),
iconTheme: IconThemeData(color: darkColors.appBarPrimaryContent),
elevation: 1.0,

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/config/app_font.dart';
import 'package:flutter_app/config/font.dart';
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
import 'package:flutter_app/resources/themes/text_theme/default_text_theme.dart';
import 'package:google_fonts/google_fonts.dart';
@ -11,14 +11,14 @@ import 'package:nylo_framework/nylo_framework.dart';
|--------------------------------------------------------------------------
| Light Theme
|
| Theme Config - config/app_theme.dart
| Theme Config - config/theme.dart
|--------------------------------------------------------------------------
*/
ThemeData lightTheme(BaseColorStyles lightColors) {
try {
appFont = GoogleFonts.getFont(
AppHelper.instance.appConfig.themeFont ?? "Poppins");
AppHelper.instance.appConfig!.themeFont ?? "Poppins");
} on Exception catch (e) {
if (getEnv('APP_DEBUG') == true) {
NyLogger.error(e.toString());
@ -38,7 +38,7 @@ ThemeData lightTheme(BaseColorStyles lightColors) {
hintColor: lightColors.primaryAccent,
appBarTheme: AppBarTheme(
backgroundColor: lightColors.appBarBackground,
titleTextStyle: lightTheme.headline6
titleTextStyle: lightTheme.headline6!
.copyWith(color: lightColors.appBarPrimaryContent),
iconTheme: IconThemeData(color: lightColors.appBarPrimaryContent),
elevation: 1.0,

View File

@ -12,13 +12,13 @@ class DarkThemeColors implements BaseColorStyles {
// general
@override
Color get background => Color(int.parse(
AppHelper.instance.appConfig.themeColors['dark']['background']));
AppHelper.instance.appConfig!.themeColors!['dark']['background']));
@override
Color get backgroundContainer => const Color(0xFF4a4a4a);
@override
Color get primaryContent => Color(int.parse(
AppHelper.instance.appConfig.themeColors['dark']['primary_text']));
AppHelper.instance.appConfig!.themeColors!['dark']['primary_text']));
@override
Color get primaryAccent => const Color(0xFF818181);
@ -29,11 +29,12 @@ class DarkThemeColors implements BaseColorStyles {
// app bar
@override
Color get appBarBackground => Color(int.parse(
AppHelper.instance.appConfig.themeColors['dark']['app_bar_background']));
Color get appBarBackground =>
Color(int.parse(AppHelper.instance.appConfig!.themeColors!['dark']
['app_bar_background']));
@override
Color get appBarPrimaryContent => Color(int.parse(
AppHelper.instance.appConfig.themeColors['dark']['app_bar_text']));
AppHelper.instance.appConfig!.themeColors!['dark']['app_bar_text']));
@override
Color get inputPrimaryContent => Colors.white;
@ -41,10 +42,10 @@ class DarkThemeColors implements BaseColorStyles {
// buttons
@override
Color get buttonBackground => Color(int.parse(
AppHelper.instance.appConfig.themeColors['dark']['button_background']));
AppHelper.instance.appConfig!.themeColors!['dark']['button_background']));
@override
Color get buttonPrimaryContent => Color(int.parse(
AppHelper.instance.appConfig.themeColors['dark']['button_text']));
AppHelper.instance.appConfig!.themeColors!['dark']['button_text']));
// bottom tab bar
@override

View File

@ -13,12 +13,12 @@ class LightThemeColors implements BaseColorStyles {
@override
Color get background => Color(int.parse(
AppHelper.instance.appConfig.themeColors['light']['background']));
AppHelper.instance.appConfig!.themeColors!['light']['background']));
@override
Color get backgroundContainer => Colors.white;
@override
Color get primaryContent => Color(int.parse(
AppHelper.instance.appConfig.themeColors['light']['primary_text']));
AppHelper.instance.appConfig!.themeColors!['light']['primary_text']));
@override
Color get primaryAccent => const Color(0xFF87c694);
@ -29,22 +29,24 @@ class LightThemeColors implements BaseColorStyles {
// app bar
@override
Color get appBarBackground => Color(int.parse(
AppHelper.instance.appConfig.themeColors['light']['app_bar_background']));
Color get appBarBackground =>
Color(int.parse(AppHelper.instance.appConfig!.themeColors!['light']
['app_bar_background']));
@override
Color get appBarPrimaryContent => Color(int.parse(
AppHelper.instance.appConfig.themeColors['light']['app_bar_text']));
AppHelper.instance.appConfig!.themeColors!['light']['app_bar_text']));
@override
Color get inputPrimaryContent => Colors.black;
// buttons
@override
Color get buttonBackground => Color(int.parse(
AppHelper.instance.appConfig.themeColors['light']['button_background']));
Color get buttonBackground =>
Color(int.parse(AppHelper.instance.appConfig!.themeColors!['light']
['button_background']));
@override
Color get buttonPrimaryContent => Color(int.parse(
AppHelper.instance.appConfig.themeColors['light']['button_text']));
AppHelper.instance.appConfig!.themeColors!['light']['button_text']));
// bottom tab bar
@override

View File

@ -68,7 +68,7 @@ class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
enablePullDown: true,
enablePullUp: true,
footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) {
builder: (BuildContext context, LoadStatus? mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text(trans("pull up load"));
@ -120,7 +120,7 @@ class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
overflow: TextOverflow.ellipsis,
),
Text(
order.status.capitalize(),
order.status!.capitalize(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
@ -141,17 +141,17 @@ class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
formatStringCurrency(total: order.total),
style: Theme.of(context)
.textTheme
.bodyText2
.bodyText2!
.copyWith(fontWeight: FontWeight.w600),
textAlign: TextAlign.left,
),
Text(
order.lineItems.length.toString() +
order.lineItems!.length.toString() +
" " +
trans("items"),
style: Theme.of(context)
.textTheme
.bodyText1
.bodyText1!
.copyWith(fontWeight: FontWeight.w600),
textAlign: TextAlign.left,
),
@ -159,16 +159,16 @@ class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
),
Text(
dateFormatted(
date: order.dateCreated,
date: order.dateCreated!,
formatType: formatForDateTime(FormatType.date),
) +
"\n" +
dateFormatted(
date: order.dateCreated,
date: order.dateCreated!,
formatType: formatForDateTime(FormatType.time),
),
textAlign: TextAlign.right,
style: Theme.of(context).textTheme.bodyText1.copyWith(
style: Theme.of(context).textTheme.bodyText1!.copyWith(
fontWeight: FontWeight.w400,
),
),
@ -214,7 +214,7 @@ class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
}
fetchOrders() async {
String userId = await readUserId();
String? userId = await readUserId();
if (userId == null) {
setState(() {
_isLoadingOrders = false;
@ -238,7 +238,7 @@ class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
userId: userId);
}
_viewOrderDetail(int i, int orderId) => Navigator.pushNamed(
_viewOrderDetail(int i, int? orderId) => Navigator.pushNamed(
context,
"/account-order-detail",
arguments: orderId,

View File

@ -13,7 +13,7 @@ import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
import 'package:nylo_framework/nylo_framework.dart';
class AccountDetailSettingsWidget extends StatelessWidget {
const AccountDetailSettingsWidget({Key key, @required this.refreshAccount})
const AccountDetailSettingsWidget({Key? key, required this.refreshAccount})
: super(key: key);
final Function refreshAccount;
@override

View File

@ -12,7 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class AppLoaderWidget extends StatelessWidget {
const AppLoaderWidget({Key key}) : super(key: key);
const AppLoaderWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -9,11 +9,11 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart';
import 'package:nylo_support/helpers/helper.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:package_info/package_info.dart';
class AppVersionWidget extends StatelessWidget {
const AppVersionWidget({Key key}) : super(key: key);
const AppVersionWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -29,15 +29,14 @@ class AppVersionWidget extends StatelessWidget {
case ConnectionState.done:
if (snapshot.hasError) return Text("");
return Padding(
child: Text("${trans("Version")}: ${snapshot.data.version}",
child: Text("${trans("Version")}: ${snapshot.data!.version}",
style: Theme.of(context)
.textTheme
.bodyText2
.bodyText2!
.copyWith(fontWeight: FontWeight.w300)),
padding: EdgeInsets.only(top: 15, bottom: 15),
);
}
return null; // unreachable
},
);
}

View File

@ -14,15 +14,12 @@ import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
class PrimaryButton extends StatelessWidget {
const PrimaryButton({
Key key,
this.title,
this.action,
this.isLoading = false
}) : super(key: key);
const PrimaryButton(
{Key? key, this.title, this.action, this.isLoading = false})
: super(key: key);
final String title;
final void Function() action;
final String? title;
final Function? action;
final bool isLoading;
@override
@ -31,30 +28,30 @@ class PrimaryButton extends StatelessWidget {
title: title,
action: action,
isLoading: isLoading,
textStyle: Theme.of(context).textTheme.button.copyWith(
textStyle: Theme.of(context).textTheme.button!.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
color: ThemeColor.get(context).buttonPrimaryContent),
bgColor: ThemeColor.get(context).buttonBackground,
color: ThemeColor.get(context)!.buttonPrimaryContent),
bgColor: ThemeColor.get(context)!.buttonBackground,
);
}
class SecondaryButton extends StatelessWidget {
const SecondaryButton({
Key key,
Key? key,
this.title,
this.action,
}) : super(key: key);
final String title;
final void Function() action;
final String? title;
final Function? action;
@override
Widget build(BuildContext context) => WooSignalButton(
key: key,
title: title,
action: action,
textStyle: Theme.of(context).textTheme.bodyText1.copyWith(
textStyle: Theme.of(context).textTheme.bodyText1!.copyWith(
color: Colors.black87,
),
bgColor: Color(0xFFF6F6F9),
@ -63,34 +60,40 @@ class SecondaryButton extends StatelessWidget {
class LinkButton extends StatelessWidget {
const LinkButton({
Key key,
Key? key,
this.title,
this.action,
}) : super(key: key);
final String title;
final void Function() action;
final String? title;
final Function? action;
@override
Widget build(BuildContext context) {
final double screenWidth = MediaQuery.of(context).size.width;
return InkWell(
key: key,
child: Container(
child: Container(
height: (screenWidth >= 385 ? 55 : 49),
width: double.infinity,
decoration: BoxDecoration(
color: Colors.transparent,
),
child: Center(child: Text(title, textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodyText1,)),),
onTap: action,
child: Center(
child: Text(
title!,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyText1,
)),
),
onTap: action == null ? null : () async => await action!(),
);
}
}
class WooSignalButton extends StatelessWidget {
const WooSignalButton({
Key key,
Key? key,
this.title,
this.action,
this.textStyle,
@ -98,10 +101,10 @@ class WooSignalButton extends StatelessWidget {
this.bgColor,
}) : super(key: key);
final String title;
final void Function() action;
final TextStyle textStyle;
final Color bgColor;
final String? title;
final Function? action;
final TextStyle? textStyle;
final Color? bgColor;
final bool isLoading;
@override
@ -115,22 +118,28 @@ class WooSignalButton extends StatelessWidget {
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
padding: EdgeInsets.all(8),
elevation: 0,
primary: bgColor,
shadowColor: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
padding: EdgeInsets.all(8),
elevation: 0,
primary: bgColor,
shadowColor: Colors.transparent,
),
child: isLoading ? AppLoaderWidget() : AutoSizeText(
title,
style: textStyle,
maxLines: (screenWidth >= 385 ? 2 : 1),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
onPressed: isLoading == true ? () {} : action,
child: isLoading
? AppLoaderWidget()
: AutoSizeText(
title!,
style: textStyle,
maxLines: (screenWidth >= 385 ? 2 : 1),
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
onPressed: (action == null || isLoading == true)
? null
: () async {
await action!();
},
),
);
}

View File

@ -13,7 +13,7 @@ import 'package:flutter/material.dart';
class CachedImageWidget extends StatelessWidget {
const CachedImageWidget({
Key key,
Key? key,
this.image,
this.height = 70,
this.width = 70,
@ -26,7 +26,7 @@ class CachedImageWidget extends StatelessWidget {
this.fit = BoxFit.contain,
}) : super(key: key);
final String image;
final String? image;
final double height;
final double width;
final Widget placeholder;
@ -34,7 +34,7 @@ class CachedImageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) => CachedNetworkImage(
imageUrl: image,
imageUrl: image!,
placeholder: (context, url) => placeholder,
errorWidget: (context, url, error) => Icon(Icons.error),
height: height,

View File

@ -13,7 +13,7 @@ import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/cart_line_item.dart';
class CartIconWidget extends StatefulWidget {
CartIconWidget({Key key}) : super(key: key);
CartIconWidget({Key? key}) : super(key: key);
@override
_CartIconWidgetState createState() => _CartIconWidgetState();
@ -45,12 +45,12 @@ class _CartIconWidgetState extends State<CartIconWidget> {
if (snapshot.hasError) {
return Text("");
} else {
List<int> cartItems =
snapshot.data.map((e) => e.quantity).toList();
List<int?> cartItems =
snapshot.data!.map((e) => e.quantity).toList();
String cartValue = "0";
if (cartItems.isNotEmpty) {
cartValue = cartItems
.reduce((value, element) => value + element)
.reduce((value, element) => value! + element!)
.toString();
}
return Text(

View File

@ -7,7 +7,7 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart';
class CheckoutCouponAmountWidget extends StatelessWidget {
const CheckoutCouponAmountWidget({Key key, @required this.checkoutSession})
const CheckoutCouponAmountWidget({Key? key, required this.checkoutSession})
: super(key: key);
final CheckoutSession checkoutSession;
@ -29,7 +29,7 @@ class CheckoutCouponAmountWidget extends StatelessWidget {
}
return Padding(
child: CheckoutMetaLine(
title: "${trans('Coupon')}: ${checkoutSession.coupon.code}",
title: "${trans('Coupon')}: ${checkoutSession.coupon!.code}",
amount: "-" + formatStringCurrency(total: snapshot.data),
),
padding: EdgeInsets.only(bottom: 0, top: 0),

View File

@ -5,14 +5,14 @@ import 'package:nylo_framework/nylo_framework.dart';
class CheckoutPaymentTypeWidget extends StatelessWidget {
const CheckoutPaymentTypeWidget(
{Key key,
@required this.context,
@required this.checkoutSession,
{Key? key,
required this.context,
required this.checkoutSession,
this.resetState})
: super(key: key);
final CheckoutSession checkoutSession;
final BuildContext context;
final Function resetState;
final Function? resetState;
@override
Widget build(BuildContext context) {
@ -23,13 +23,13 @@ class CheckoutPaymentTypeWidget extends StatelessWidget {
? Container(
color: Colors.white,
child: Image.asset(
getImageAsset(checkoutSession.paymentType.assetImage),
getImageAsset(checkoutSession.paymentType!.assetImage),
width: 70,
),
)
: Icon(Icons.payment),
leadTitle: hasPaymentType
? checkoutSession.paymentType.desc
? checkoutSession.paymentType!.desc
: trans("Select a payment method"),
action: _actionPayWith,
showBorderBottom: true,
@ -38,6 +38,6 @@ class CheckoutPaymentTypeWidget extends StatelessWidget {
_actionPayWith() {
Navigator.pushNamed(context, "/checkout-payment-type")
.then((value) => resetState());
.then((value) => resetState!());
}
}

View File

@ -12,9 +12,9 @@ import 'package:webview_flutter/webview_flutter.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
class PayPalCheckout extends StatefulWidget {
final String description;
final String amount;
final List<CartLineItem> cartLineItems;
final String? description;
final String? amount;
final List<CartLineItem>? cartLineItems;
PayPalCheckout({this.description, this.amount, this.cartLineItems});
@ -26,49 +26,49 @@ class WebViewState extends NyState<PayPalCheckout> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
String payerId = '';
String? payerId = '';
int intCount = 0;
StreamSubscription<String> _onUrlChanged;
final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
String formCheckoutShippingAddress;
StreamSubscription<String>? _onUrlChanged;
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
String? formCheckoutShippingAddress;
setCheckoutShippingAddress(CustomerAddress customerAddress) {
String tmp = "";
if (customerAddress.firstName != null) {
tmp +=
'<input type="hidden" name="first_name" value="${customerAddress.firstName.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="first_name" value="${customerAddress.firstName!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
if (customerAddress.lastName != null) {
tmp +=
'<input type="hidden" name="last_name" value="${customerAddress.lastName.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="last_name" value="${customerAddress.lastName!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
if (customerAddress.addressLine != null) {
tmp +=
'<input type="hidden" name="address1" value="${customerAddress.addressLine.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="address1" value="${customerAddress.addressLine!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
if (customerAddress.city != null) {
tmp +=
'<input type="hidden" name="city" value="${customerAddress.city.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="city" value="${customerAddress.city!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
if (customerAddress.customerCountry.hasState() &&
customerAddress.customerCountry.state.name != null) {
if (customerAddress.customerCountry!.hasState() &&
customerAddress.customerCountry!.state!.name != null) {
tmp +=
'<input type="hidden" name="state" value="${customerAddress.customerCountry.state.name.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="state" value="${customerAddress.customerCountry!.state!.name!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
if (customerAddress.postalCode != null) {
tmp +=
'<input type="hidden" name="zip" value="${customerAddress.postalCode.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="zip" value="${customerAddress.postalCode!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
if (customerAddress.customerCountry.countryCode != null) {
if (customerAddress.customerCountry!.countryCode != null) {
tmp +=
'<input type="hidden" name="country" value="${customerAddress.customerCountry.countryCode.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
'<input type="hidden" name="country" value="${customerAddress.customerCountry!.countryCode!.replaceAll(RegExp(r'[^\d\w\s,\-+]+'), '')}">\n';
}
formCheckoutShippingAddress = tmp;
}
String getPayPalItemName() {
return truncateString(
widget.description.replaceAll(RegExp(r'[^\w\s]+'), ''), 124);
widget.description!.replaceAll(RegExp(r'[^\w\s]+'), ''), 124);
}
String getPayPalPaymentType() {
@ -76,8 +76,8 @@ class WebViewState extends NyState<PayPalCheckout> {
}
String getPayPalUrl() {
bool liveMode =
envVal('PAYPAL_LIVE_MODE', defaultValue: _wooSignalApp.paypalLiveMode);
bool? liveMode =
envVal('PAYPAL_LIVE_MODE', defaultValue: _wooSignalApp!.paypalLiveMode);
return liveMode == true
? "https://www.paypal.com/cgi-bin/webscr"
: "https://www.sandbox.paypal.com/cgi-bin/webscr";
@ -88,14 +88,14 @@ class WebViewState extends NyState<PayPalCheckout> {
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
setCheckoutShippingAddress(
CheckoutSession.getInstance.billingDetails.shippingAddress);
CheckoutSession.getInstance.billingDetails!.shippingAddress!);
setState(() {});
}
@override
void dispose() {
if (_onUrlChanged != null) {
_onUrlChanged.cancel();
_onUrlChanged!.cancel();
}
super.dispose();
}
@ -117,9 +117,9 @@ class WebViewState extends NyState<PayPalCheckout> {
<form method="post" name="paypal_form" action="${getPayPalUrl()}">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="amount" value="${widget.amount}">
<input type="hidden" name="lc" value="${envVal('PAYPAL_LOCALE', defaultValue: _wooSignalApp.paypalLocale)}">
<input type="hidden" name="currency_code" value="${_wooSignalApp.currencyMeta.code}">
<input type="hidden" name="business" value="${envVal('PAYPAL_ACCOUNT_EMAIL', defaultValue: _wooSignalApp.paypalEmail)}">
<input type="hidden" name="lc" value="${envVal('PAYPAL_LOCALE', defaultValue: _wooSignalApp!.paypalLocale)}">
<input type="hidden" name="currency_code" value="${_wooSignalApp!.currencyMeta!.code}">
<input type="hidden" name="business" value="${envVal('PAYPAL_ACCOUNT_EMAIL', defaultValue: _wooSignalApp!.paypalEmail)}">
<input type="hidden" name="return" value="https://woosignal.com/paypal/payment~success">
<input type="hidden" name="cancel_return" value="https://woosignal.com/paypal/payment~failure">
<input type="hidden" name="item_name" value="${getPayPalItemName()}">

View File

@ -4,10 +4,10 @@ import 'package:nylo_framework/nylo_framework.dart';
class CheckoutSelectCouponWidget extends StatelessWidget {
const CheckoutSelectCouponWidget(
{Key key,
@required this.context,
@required this.checkoutSession,
@required this.resetState})
{Key? key,
required this.context,
required this.checkoutSession,
required this.resetState})
: super(key: key);
final CheckoutSession checkoutSession;
@ -25,22 +25,21 @@ class CheckoutSelectCouponWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
hasCoupon == true
? IconButton(
padding: EdgeInsets.symmetric(vertical: 3),
onPressed: _clearCoupon,
icon: Icon(
Icons.close,
size: 19,
))
: null,
if (hasCoupon == true)
IconButton(
padding: EdgeInsets.symmetric(vertical: 3),
onPressed: _clearCoupon,
icon: Icon(
Icons.close,
size: 19,
)),
Text(
hasCoupon
? "Coupon Applied: " + checkoutSession.coupon.code
? "Coupon Applied: " + checkoutSession.coupon!.code!
: trans('Apply Coupon'),
style: Theme.of(context).textTheme.subtitle2,
),
].where((element) => element != null).toList(),
],
),
),
);
@ -52,7 +51,7 @@ class CheckoutSelectCouponWidget extends StatelessWidget {
}
_actionCoupon() {
if (checkoutSession.billingDetails.billingAddress == null) {
if (checkoutSession.billingDetails!.billingAddress == null) {
showToastNotification(
context,
title: trans("Oops"),
@ -64,7 +63,7 @@ class CheckoutSelectCouponWidget extends StatelessWidget {
return;
}
if (checkoutSession.billingDetails.billingAddress.hasMissingFields()) {
if (checkoutSession.billingDetails!.billingAddress!.hasMissingFields()) {
showToastNotification(
context,
title: trans("Oops"),

View File

@ -7,21 +7,21 @@ import 'package:woosignal/models/response/woosignal_app.dart';
class CheckoutShippingTypeWidget extends StatelessWidget {
const CheckoutShippingTypeWidget(
{Key key,
@required this.context,
@required this.wooSignalApp,
@required this.checkoutSession,
{Key? key,
required this.context,
required this.wooSignalApp,
required this.checkoutSession,
this.resetState})
: super(key: key);
final CheckoutSession checkoutSession;
final BuildContext context;
final Function resetState;
final WooSignalApp wooSignalApp;
final Function? resetState;
final WooSignalApp? wooSignalApp;
@override
Widget build(BuildContext context) {
bool hasDisableShipping = wooSignalApp.disableShipping == 1;
bool hasDisableShipping = wooSignalApp!.disableShipping == 1;
if (hasDisableShipping == true) {
return SizedBox.shrink();
}
@ -31,7 +31,7 @@ class CheckoutShippingTypeWidget extends StatelessWidget {
hasSelectedShippingType ? "Shipping selected" : "Select shipping"),
leadImage: Icon(Icons.local_shipping),
leadTitle: hasSelectedShippingType
? checkoutSession.shippingType.getTitle()
? checkoutSession.shippingType!.getTitle()
: trans("Select a shipping option"),
action: _actionSelectShipping,
showBorderBottom: false,
@ -39,8 +39,8 @@ class CheckoutShippingTypeWidget extends StatelessWidget {
}
_actionSelectShipping() {
CustomerAddress shippingAddress =
checkoutSession.billingDetails.shippingAddress;
CustomerAddress? shippingAddress =
checkoutSession.billingDetails!.shippingAddress;
if (shippingAddress == null || shippingAddress.customerCountry == null) {
showToastNotification(
context,
@ -51,6 +51,6 @@ class CheckoutShippingTypeWidget extends StatelessWidget {
return;
}
Navigator.pushNamed(context, "/checkout-shipping-type")
.then((value) => resetState());
.then((value) => resetState!());
}
}

View File

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
class CheckoutStoreHeadingWidget extends StatelessWidget {
const CheckoutStoreHeadingWidget({Key key}) : super(key: key);
const CheckoutStoreHeadingWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {

View File

@ -5,28 +5,28 @@ import 'package:nylo_framework/nylo_framework.dart';
class CheckoutUserDetailsWidget extends StatelessWidget {
const CheckoutUserDetailsWidget(
{Key key,
@required this.context,
@required this.checkoutSession,
{Key? key,
required this.context,
required this.checkoutSession,
this.resetState})
: super(key: key);
final CheckoutSession checkoutSession;
final BuildContext context;
final Function resetState;
final Function? resetState;
@override
Widget build(BuildContext context) {
bool hasUserCheckoutInfo = (checkoutSession.billingDetails != null &&
checkoutSession.billingDetails.billingAddress != null);
checkoutSession.billingDetails!.billingAddress != null);
return CheckoutRowLine(
heading: trans("Billing/shipping details"),
leadImage: Icon(Icons.home),
leadTitle: hasUserCheckoutInfo
? (checkoutSession.billingDetails == null ||
checkoutSession.billingDetails.billingAddress
checkoutSession.billingDetails!.billingAddress!
.hasMissingFields()
? trans("Billing address is incomplete")
: checkoutSession.billingDetails.billingAddress.addressFull())
: checkoutSession.billingDetails!.billingAddress!.addressFull())
: trans("Add billing & shipping details"),
action: _actionCheckoutDetails,
showBorderBottom: true,
@ -35,7 +35,7 @@ class CheckoutUserDetailsWidget extends StatelessWidget {
_actionCheckoutDetails() {
Navigator.pushNamed(context, "/checkout-details").then((e) {
resetState();
resetState!();
// setState(() {
// _showFullLoader = true;
// });

View File

@ -6,16 +6,16 @@ import 'package:flutter_app/resources/widgets/buttons.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/woosignal_ui.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:flutter_swiper_tv/flutter_swiper.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/models/response/products.dart';
class CompoHomeWidget extends StatefulWidget {
CompoHomeWidget({Key key, @required this.wooSignalApp}) : super(key: key);
CompoHomeWidget({Key? key, required this.wooSignalApp}) : super(key: key);
final WooSignalApp wooSignalApp;
final WooSignalApp? wooSignalApp;
@override
_CompoHomeWidgetState createState() => _CompoHomeWidgetState();
@ -29,19 +29,19 @@ class _CompoHomeWidgetState extends State<CompoHomeWidget> {
}
_loadHome() async {
categories = await appWooSignal((api) =>
api.getProductCategories(parent: 0, perPage: 50, hideEmpty: true));
categories = await (appWooSignal((api) =>
api.getProductCategories(parent: 0, perPage: 50, hideEmpty: true)));
categories.sort((category1, category2) =>
category1.menuOrder.compareTo(category2.menuOrder));
category1.menuOrder!.compareTo(category2.menuOrder!));
for (var category in categories) {
List<Product> products = await appWooSignal(
List<Product> products = await (appWooSignal(
(api) => api.getProducts(
perPage: 10,
category: category.id.toString(),
status: "publish",
stockStatus: "instock"),
);
));
if (products.isNotEmpty) {
categoryAndProducts.addAll({category: products});
setState(() {});
@ -60,7 +60,7 @@ class _CompoHomeWidgetState extends State<CompoHomeWidget> {
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
List<String> bannerImages = widget.wooSignalApp.bannerImages;
List<String>? bannerImages = widget.wooSignalApp!.bannerImages;
return Scaffold(
drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp),
appBar: AppBar(
@ -74,7 +74,7 @@ class _CompoHomeWidgetState extends State<CompoHomeWidget> {
: ListView(
shrinkWrap: true,
children: [
if (bannerImages.isNotEmpty)
if (bannerImages!.isNotEmpty)
Container(
child: Swiper(
itemBuilder: (BuildContext context, int index) {
@ -101,17 +101,16 @@ class _CompoHomeWidgetState extends State<CompoHomeWidget> {
margin: EdgeInsets.only(top: 10),
child: Column(
children: [
hasImage
? InkWell(
child: CachedImageWidget(
image: catProds.key.image.src,
height: containerHeight / 2,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
onTap: () => _showCategory(catProds.key),
)
: null,
if (hasImage)
InkWell(
child: CachedImageWidget(
image: catProds.key.image!.src,
height: containerHeight / 2,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
),
onTap: () => _showCategory(catProds.key),
),
ConstrainedBox(
constraints: BoxConstraints(
minHeight: 50,
@ -128,10 +127,10 @@ class _CompoHomeWidgetState extends State<CompoHomeWidget> {
children: [
Expanded(
child: AutoSizeText(
catProds.key.name,
catProds.key.name!,
style: Theme.of(context)
.textTheme
.subtitle1
.subtitle1!
.copyWith(
fontWeight: FontWeight.bold,
fontSize: 22),
@ -172,7 +171,7 @@ class _CompoHomeWidgetState extends State<CompoHomeWidget> {
itemCount: catProds.value.length,
),
)
].where((e) => e != null).toList(),
],
),
);
}),

Some files were not shown because too many files have changed in this diff Show More