diff --git a/LabelStoreMax/CHANGELOG.md b/LabelStoreMax/CHANGELOG.md index 1ecd8db..c461e27 100644 --- a/LabelStoreMax/CHANGELOG.md +++ b/LabelStoreMax/CHANGELOG.md @@ -1,5 +1,12 @@ -## [2.0.2] - 2020-05-04 +## [2.0.2] - 2020-05-08 +* Flutter 1.17.0 support +* Sort by feature +* Cash on delivery added +* RazorPay added +* Login/register flow change for Apple user guidelines +* Bug fixes +* Pubspec.yaml update * AndroidManifest.xml bug fix ## [2.0.1] - 2020-04-30 diff --git a/LabelStoreMax/assets/images/cart_empty.png b/LabelStoreMax/assets/images/cart_empty.png deleted file mode 100644 index 7e9595d..0000000 Binary files a/LabelStoreMax/assets/images/cart_empty.png and /dev/null differ diff --git a/LabelStoreMax/assets/images/cash_on_delivery.jpeg b/LabelStoreMax/assets/images/cash_on_delivery.jpeg new file mode 100644 index 0000000..647ace9 Binary files /dev/null and b/LabelStoreMax/assets/images/cash_on_delivery.jpeg differ diff --git a/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj b/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj index 0611d1c..1e9b492 100644 --- a/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj +++ b/LabelStoreMax/ios/Runner.xcodeproj/project.pbxproj @@ -264,9 +264,6 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Braintree/Braintree.framework", - "${PODS_ROOT}/Braintree/Frameworks/CardinalMobile.framework", - "${BUILT_PRODUCTS_DIR}/BraintreeDropIn/BraintreeDropIn.framework", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", "${PODS_ROOT}/../Flutter/Flutter.framework", "${BUILT_PRODUCTS_DIR}/Stripe/Stripe.framework", @@ -275,6 +272,8 @@ "${BUILT_PRODUCTS_DIR}/flutter_web_browser/flutter_web_browser.framework", "${BUILT_PRODUCTS_DIR}/package_info/package_info.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", + "${PODS_ROOT}/razorpay-pod/Pod/Razorpay.framework", + "${BUILT_PRODUCTS_DIR}/razorpay_flutter/razorpay_flutter.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", @@ -282,9 +281,6 @@ ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Braintree.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CardinalMobile.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BraintreeDropIn.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stripe.framework", @@ -293,6 +289,8 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_web_browser.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Razorpay.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/razorpay_flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", diff --git a/LabelStoreMax/ios/Runner/AppDelegate.swift b/LabelStoreMax/ios/Runner/AppDelegate.swift index 349cce6..643f0ca 100644 --- a/LabelStoreMax/ios/Runner/AppDelegate.swift +++ b/LabelStoreMax/ios/Runner/AppDelegate.swift @@ -1,6 +1,5 @@ import UIKit import Flutter -import Braintree @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { diff --git a/LabelStoreMax/lang/en.json b/LabelStoreMax/lang/en.json index 079703c..f5f0ce5 100644 --- a/LabelStoreMax/lang/en.json +++ b/LabelStoreMax/lang/en.json @@ -129,5 +129,18 @@ "Shipping Details": "Shipping Details", "State": "State", "Country": "Country", - "UPDATE DETAILS": "UPDATE DETAILS" + "UPDATE DETAILS": "UPDATE DETAILS", + "No more products": "No more products", + "release to load more": "release to load more", + "Load Failed! Click retry!": "Load Failed! Click retry!", + "pull up load": "pull up load", + "Sort: Low to high": "Sort: Low to high", + "Sort: High to low": "Sort: High to low", + "Sort: Name A-Z": "Sort: Name A-Z", + "Sort: Name Z-A": "Sort: Name Z-A", + "Cancel": "Cancel", + "Sort results": "Sort results", + "you're now logged in": "You're now logged in", + "Hello": "Hello", + "Welcome back": "Welcome back" } \ No newline at end of file diff --git a/LabelStoreMax/lib/app_payment_methods.dart b/LabelStoreMax/lib/app_payment_methods.dart index fc0d964..7f81f0d 100644 --- a/LabelStoreMax/lib/app_payment_methods.dart +++ b/LabelStoreMax/lib/app_payment_methods.dart @@ -10,6 +10,7 @@ import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/models/payment_type.dart'; +import 'package:label_storemax/providers/cash_on_delivery.dart'; import 'package:label_storemax/providers/stripe_pay.dart'; // Payment methods available for uses in the app @@ -25,11 +26,21 @@ List arrPaymentMethods = [ ), ), + addPayment( + PaymentType( + id: 2, + name: "CashOnDelivery", + desc: "Cash on delivery", + assetImage: "cash_on_delivery.jpeg", + pay: cashOnDeliveryPay, + ), + ), + // e.g. add more here // addPayment( // PaymentType( -// id: 2, +// id: 3, // name: "MyNewPaymentMethod", // desc: "Debit or Credit Card", // assetImage: "add icon image to assets/images/myimage.png", diff --git a/LabelStoreMax/lib/helpers/app_localizations.dart b/LabelStoreMax/lib/helpers/app_localizations.dart index 9fdbc98..9a67ead 100644 --- a/LabelStoreMax/lib/helpers/app_localizations.dart +++ b/LabelStoreMax/lib/helpers/app_localizations.dart @@ -50,8 +50,10 @@ class _AppLocalizationsDelegate const _AppLocalizationsDelegate(); @override - bool isSupported(Locale locale) => - app_locales_supported.contains(locale.languageCode); + bool isSupported(Locale locale) => app_locales_supported + .map((e) => e.languageCode) + .toList() + .contains(locale.languageCode); @override bool shouldReload(_AppLocalizationsDelegate old) => false; diff --git a/LabelStoreMax/lib/helpers/app_themes.dart b/LabelStoreMax/lib/helpers/app_themes.dart index bab11c3..196fddc 100644 --- a/LabelStoreMax/lib/helpers/app_themes.dart +++ b/LabelStoreMax/lib/helpers/app_themes.dart @@ -82,9 +82,9 @@ TextTheme textThemePrimary() { fontWeight: FontWeight.w600), headline: new TextStyle(color: Colors.black, fontFamily: appFontFamily), title: new TextStyle( - color: Colors.black, - fontFamily: appFontFamily, - ), + color: Colors.black87, + fontFamily: appFontFamily, + fontWeight: FontWeight.w600), subhead: new TextStyle( color: Colors.black, fontFamily: appFontFamily, diff --git a/LabelStoreMax/lib/helpers/data/order_wc.dart b/LabelStoreMax/lib/helpers/data/order_wc.dart index b0a7162..80ddf22 100644 --- a/LabelStoreMax/lib/helpers/data/order_wc.dart +++ b/LabelStoreMax/lib/helpers/data/order_wc.dart @@ -19,7 +19,7 @@ import 'package:label_storemax/models/checkout_session.dart'; import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/response/tax_rate.dart'; -Future buildOrderWC({TaxRate taxRate}) async { +Future buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { OrderWC orderWC = OrderWC(); String paymentMethodName = CheckoutSession.getInstance.paymentType.name ?? ""; @@ -30,7 +30,7 @@ Future buildOrderWC({TaxRate taxRate}) async { orderWC.paymentMethodTitle = paymentMethodName.toLowerCase(); - orderWC.setPaid = true; + orderWC.setPaid = markPaid; orderWC.status = "pending"; orderWC.currency = app_currency_iso.toUpperCase(); orderWC.customerId = diff --git a/LabelStoreMax/lib/helpers/enums/sort_enums.dart b/LabelStoreMax/lib/helpers/enums/sort_enums.dart new file mode 100644 index 0000000..126a203 --- /dev/null +++ b/LabelStoreMax/lib/helpers/enums/sort_enums.dart @@ -0,0 +1,16 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// 2020, WooSignal Ltd. All rights reserved. +// + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + +enum SortByType { + LowToHigh, + HighToLow, + NameAZ, + NameZA, +} diff --git a/LabelStoreMax/lib/helpers/shared_pref/sp_auth.dart b/LabelStoreMax/lib/helpers/shared_pref/sp_auth.dart index e4df759..183cf73 100644 --- a/LabelStoreMax/lib/helpers/shared_pref/sp_auth.dart +++ b/LabelStoreMax/lib/helpers/shared_pref/sp_auth.dart @@ -38,5 +38,5 @@ authLogout(BuildContext context) async { await sharedPref.save(keyAuthCheck, null); destroyUserId(context); Cart.getInstance.clear(); - navigatorPush(context, routeName: "/account-landing", forgetAll: true); + navigatorPush(context, routeName: "/home", forgetAll: true); } diff --git a/LabelStoreMax/lib/helpers/tools.dart b/LabelStoreMax/lib/helpers/tools.dart index 105cddd..0c7abca 100644 --- a/LabelStoreMax/lib/helpers/tools.dart +++ b/LabelStoreMax/lib/helpers/tools.dart @@ -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:flutter/cupertino.dart'; import 'package:intl/intl.dart'; import 'package:label_storemax/app_payment_methods.dart'; import 'package:label_storemax/helpers/app_localizations.dart'; @@ -22,9 +23,12 @@ import 'package:label_storemax/models/payment_type.dart'; import 'package:html/parser.dart'; import 'package:flutter_web_browser/flutter_web_browser.dart'; import 'package:flutter_money_formatter/flutter_money_formatter.dart'; +import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:math_expressions/math_expressions.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'; @@ -65,11 +69,6 @@ showStatusAlert(context, ); } -class PaymentMethodType { - static final int STRIPE = 1; - static final int APPLEPAY = 2; -} - class EdgeAlertStyle { static final int SUCCESS = 1; static final int WARNING = 2; @@ -142,7 +141,7 @@ String formatStringCurrency({@required String total}) { if (total == null || total == "") { tmpVal = 0; } else { - tmpVal = double.parse(total); + tmpVal = parseWcPrice(total); } FlutterMoneyFormatter fmf = FlutterMoneyFormatter( amount: tmpVal, @@ -185,6 +184,9 @@ checkout( } double strCal({@required String sum}) { + if (sum == null || sum == "") { + return 0; + } Parser p = Parser(); Expression exp = p.parse(sum); ContextModel cm = ContextModel(); @@ -192,6 +194,9 @@ double strCal({@required String sum}) { } Future workoutShippingCostWC({@required String sum}) async { + if (sum == null || sum == "") { + return 0; + } List cartLineItem = await Cart.getInstance.getCart(); sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) { return cartLineItem @@ -263,6 +268,9 @@ Future workoutShippingCostWC({@required String sum}) async { Future workoutShippingClassCostWC( {@required String sum, List cartLineItem}) async { + if (sum == null || sum == "") { + return 0; + } sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) { return cartLineItem .map((f) => f.quantity) @@ -357,14 +365,22 @@ bool validPassword(String pw) { } navigatorPush(BuildContext context, - {@required String routeName, Object arguments, bool forgetAll = false}) { + {@required String routeName, + Object arguments, + bool forgetAll = false, + int forgetLast}) { if (forgetAll) { Navigator.of(context).pushNamedAndRemoveUntil( routeName, (Route route) => false, arguments: arguments ?? null); - } else { - Navigator.of(context).pushNamed(routeName, arguments: arguments ?? null); } + if (forgetLast != null) { + int count = 0; + Navigator.of(context).popUntil((route) { + return count++ == forgetLast; + }); + } + Navigator.of(context).pushNamed(routeName, arguments: arguments ?? null); } PlatformDialogAction dialogAction(BuildContext context, @@ -450,3 +466,58 @@ String formatForDateTime(FormatType formatType) { } String capitalize(String s) => s[0].toUpperCase() + s.substring(1); + +double parseWcPrice(String price) => (double.tryParse(price) ?? 0); + +Widget refreshableScroll(context, + {@required refreshController, + @required VoidCallback onRefresh, + @required VoidCallback onLoading, + @required List products, + @required onTap, + key}) { + return SmartRefresher( + enablePullDown: false, + enablePullUp: true, + footer: CustomFooter( + builder: (BuildContext context, LoadStatus mode) { + Widget body; + if (mode == LoadStatus.idle) { + body = Text(trans(context, "pull up load")); + } else if (mode == LoadStatus.loading) { + body = CupertinoActivityIndicator(); + } else if (mode == LoadStatus.failed) { + body = Text(trans(context, "Load Failed! Click retry!")); + } else if (mode == LoadStatus.canLoading) { + body = Text(trans(context, "release to load more")); + } else { + body = Text(trans(context, "No more products")); + } + return Container( + height: 55.0, + child: Center(child: body), + ); + }, + ), + controller: refreshController, + onRefresh: onRefresh, + onLoading: onLoading, + child: (products.length != null && products.length > 0 + ? GridView.count( + crossAxisCount: 2, + children: List.generate( + products.length, + (index) { + return wsCardProductItem(context, + index: index, product: products[index], onTap: onTap); + }, + )) + : wsNoResults(context))); +} + +class UserAuth { + UserAuth._privateConstructor(); + static final UserAuth instance = UserAuth._privateConstructor(); + + String redirect = "/home"; +} diff --git a/LabelStoreMax/lib/labelconfig.dart b/LabelStoreMax/lib/labelconfig.dart index f93e80d..2b57d92 100644 --- a/LabelStoreMax/lib/labelconfig.dart +++ b/LabelStoreMax/lib/labelconfig.dart @@ -10,11 +10,13 @@ // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +import 'dart:ui'; + /* Developer Notes SUPPORT EMAIL - support@woosignal.com - VERSION - 2.0.1 + VERSION - 2.0.2 https://woosignal.com */ @@ -22,15 +24,51 @@ const app_name = "MyApp"; -const app_key = "your app key"; +const app_key = + "Your app key from WooSingal"; // Your App key from WooSignal // link: https://woosignal.com/dashboard/apps -const app_logo_url = "https://is5-ssl.mzstatic.com/image/thumb/Purple115/v4/4b/e8/9a/4be89a5a-607e-1fb3-c45a-3261e84a061b/source/512x512bb.jpg"; +const app_logo_url = "https://woosignal.com/images/120x120_woosignal.png"; const app_terms_url = "https://yourdomain.com/terms"; const app_privacy_url = "https://yourdomain.com/privacy"; + +/**/ + +const app_currency_symbol = "\£"; +const app_currency_iso = "gbp"; +const app_locales_supported = [ + Locale('en'), +]; +// If you want to localize the app, add the locale above +// then create a new lang json file using keys from en.json +// e.g. lang/es.json + + +/**/ + +// Available: "Stripe", "CashOnDelivery", +// Add the method to the array below e.g. ["Stripe", "CashOnDelivery"] + +const app_payment_methods = ["Stripe"]; + + +/**/ + +// Your StripeAccount key from WooSignal +// link: https://woosignal.com/dashboard + +const app_stripe_account = "Your StripeAccount from WooSignal"; + +const app_stripe_live_mode = false; +// For Live Payments follow the below steps +// #1 SET the above to true for live payments +// #2 Next visit https://woosignal.com/dashboard +// #3 Then change "Environment for Stripe" to Live mode + + /**/ // Allows customers to login/register, view account, purchase items as a user. @@ -40,29 +78,10 @@ const app_privacy_url = "https://yourdomain.com/privacy"; const use_wp_login = false; const app_base_url = "https://mysite.com"; // change to your url -const app_forgot_password_url = "https://mysite.com/my-account/lost-password"; // change to your forgot password url +const app_forgot_password_url = + "https://mysite.com/my-account/lost-password"; // change to your forgot password url const app_wp_api_path = "/wp-json"; // By default "/wp-json" should work -/**/ - -// Your StripeAccount key from WooSignal -// link: https://woosignal.com/dashboard - -const app_stripe_account = "Stripe Key from WooSignal"; - -const app_stripe_live_mode = false; -// For Live Payments follow the below steps -// #1 SET the above to true for live payments -// #2 Next visit https://woosignal.com/dashboard -// #3 Then change "Environment for Stripe" to Live mode - -/**/ - -const app_currency_symbol = "\£"; -const app_currency_iso = "gbp"; -const app_locales_supported = ['en']; - -const app_payment_methods = ["Stripe"]; /**/ diff --git a/LabelStoreMax/lib/main.dart b/LabelStoreMax/lib/main.dart index c458467..4cd7744 100644 --- a/LabelStoreMax/lib/main.dart +++ b/LabelStoreMax/lib/main.dart @@ -10,7 +10,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:label_storemax/helpers/shared_pref/sp_auth.dart'; import 'package:label_storemax/pages/account_billing_details.dart'; import 'package:label_storemax/pages/account_detail.dart'; import 'package:label_storemax/pages/account_landing.dart'; @@ -51,13 +50,12 @@ void main() async { DeviceOrientation.portraitUp, ]); - String initialRoute = (use_wp_login) ? "/account-landing" : "/home"; - WPJsonAPI.instance.initWith( - baseUrl: app_base_url, - shouldDebug: app_debug, - wpJsonPath: app_wp_api_path); - if (await authCheck() == true) { - initialRoute = "/home"; + String initialRoute = "/home"; + if (use_wp_login == true) { + WPJsonAPI.instance.initWith( + baseUrl: app_base_url, + shouldDebug: app_debug, + wpJsonPath: app_wp_api_path); } runApp( @@ -71,7 +69,6 @@ void main() async { '/cart': (BuildContext context) => new CartPage(), '/error': (BuildContext context) => new ErrorPage(), '/checkout': (BuildContext context) => new CheckoutConfirmationPage(), - '/account-landing': (BuildContext context) => new AccountLandingPage(), '/account-register': (BuildContext context) => new AccountRegistrationPage(), '/account-detail': (BuildContext context) => new AccountDetailPage(), @@ -84,6 +81,12 @@ void main() async { }, onGenerateRoute: (settings) { switch (settings.name) { + case '/account-landing': + return PageTransition( + child: AccountLandingPage(), + type: PageTransitionType.downToUp, + ); + case '/browse-category': if (settings.arguments != null) { final ProductCategory category = @@ -200,9 +203,7 @@ void main() async { return null; } }, - supportedLocales: [ - Locale('en'), - ], + supportedLocales: app_locales_supported, localizationsDelegates: [ AppLocalizations.delegate, GlobalWidgetsLocalizations.delegate, diff --git a/LabelStoreMax/lib/models/cart.dart b/LabelStoreMax/lib/models/cart.dart index d8c4502..3e4ec63 100644 --- a/LabelStoreMax/lib/models/cart.dart +++ b/LabelStoreMax/lib/models/cart.dart @@ -142,7 +142,7 @@ class Cart { if (taxableCartLines.length > 0) { cartSubtotal = taxableCartLines - .map((m) => double.parse(m.subtotal)) + .map((m) => parseWcPrice(m.subtotal)) .reduce((a, b) => a + b); } @@ -155,13 +155,19 @@ class Cart { case "flat_rate": FlatRate flatRate = (shippingType.object as FlatRate); if (flatRate.taxable != null && flatRate.taxable) { - shippingTotal += double.parse(shippingType.cost); + shippingTotal += parseWcPrice( + shippingType.cost == null || shippingType.cost == "" + ? "0" + : shippingType.cost); } break; case "local_pickup": LocalPickup localPickup = (shippingType.object as LocalPickup); if (localPickup.taxable != null && localPickup.taxable) { - shippingTotal += double.parse(localPickup.cost); + shippingTotal += parseWcPrice( + (localPickup.cost == null || localPickup.cost == "" + ? "0" + : localPickup.cost)); } break; default: @@ -171,10 +177,10 @@ class Cart { double total = 0; if (subtotal != 0) { - total += ((double.parse(taxRate.rate) * subtotal) / 100); + total += ((parseWcPrice(taxRate.rate) * subtotal) / 100); } if (shippingTotal != 0) { - total += ((double.parse(taxRate.rate) * shippingTotal) / 100); + total += ((parseWcPrice(taxRate.rate) * shippingTotal) / 100); } return (total).toStringAsFixed(2); } diff --git a/LabelStoreMax/lib/models/cart_line_item.dart b/LabelStoreMax/lib/models/cart_line_item.dart index 1a8f782..7597463 100644 --- a/LabelStoreMax/lib/models/cart_line_item.dart +++ b/LabelStoreMax/lib/models/cart_line_item.dart @@ -8,6 +8,8 @@ // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +import 'package:label_storemax/helpers/tools.dart'; + class CartLineItem { String name; int productId; @@ -45,7 +47,7 @@ class CartLineItem { this.metaData}); String getCartTotal() { - return (quantity * double.parse(subtotal)).toString(); + return (quantity * parseWcPrice(subtotal)).toString(); } CartLineItem.fromJson(Map json) @@ -56,7 +58,10 @@ class CartLineItem { shippingClassId = json['shipping_class_id'].toString(), taxStatus = json['tax_status'], stockQuantity = json['stock_quantity'], - isManagedStock = json['is_managed_stock'], + isManagedStock = (json['is_managed_stock'] != null && + json['is_managed_stock'] is bool) + ? json['is_managed_stock'] + : false, shippingIsTaxable = json['shipping_is_taxable'], subtotal = json['subtotal'], total = json['total'], diff --git a/LabelStoreMax/lib/models/checkout_session.dart b/LabelStoreMax/lib/models/checkout_session.dart index efe6e00..29d6fb0 100644 --- a/LabelStoreMax/lib/models/checkout_session.dart +++ b/LabelStoreMax/lib/models/checkout_session.dart @@ -61,18 +61,18 @@ class CheckoutSession { } Future total({bool withFormat, TaxRate taxRate}) async { - double totalCart = double.parse(await Cart.getInstance.getTotal()); + double totalCart = parseWcPrice(await Cart.getInstance.getTotal()); double totalShipping = 0; if (shippingType != null && shippingType.object != null) { switch (shippingType.methodId) { case "flat_rate": - totalShipping = double.parse(shippingType.cost); + totalShipping = parseWcPrice(shippingType.cost); break; case "free_shipping": - totalShipping = double.parse(shippingType.cost); + totalShipping = parseWcPrice(shippingType.cost); break; case "local_pickup": - totalShipping = double.parse(shippingType.cost); + totalShipping = parseWcPrice(shippingType.cost); break; default: break; @@ -83,12 +83,12 @@ class CheckoutSession { if (taxRate != null) { String taxAmount = await Cart.getInstance.taxAmount(taxRate); - total += double.parse(taxAmount); + total += parseWcPrice(taxAmount); } if (withFormat != null && withFormat == true) { return formatDoubleCurrency(total: total); } - return total.toString(); + return total.toStringAsFixed(2); } } diff --git a/LabelStoreMax/lib/pages/about.dart b/LabelStoreMax/lib/pages/about.dart index 3ad0288..925706c 100644 --- a/LabelStoreMax/lib/pages/about.dart +++ b/LabelStoreMax/lib/pages/about.dart @@ -42,7 +42,7 @@ class _AboutPageState extends State { }, ), title: Text(trans(context, "About"), - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.headline6), centerTitle: true, ), body: SafeArea( @@ -85,8 +85,9 @@ class _AboutPageState extends State { trans(context, "Version") + ": " + snapshot.data.version, - style: - Theme.of(context).primaryTextTheme.body2), + style: Theme.of(context) + .primaryTextTheme + .bodyText1), padding: EdgeInsets.only(top: 15, bottom: 15), ); } diff --git a/LabelStoreMax/lib/pages/account_billing_details.dart b/LabelStoreMax/lib/pages/account_billing_details.dart index 337686b..8ce8fe6 100644 --- a/LabelStoreMax/lib/pages/account_billing_details.dart +++ b/LabelStoreMax/lib/pages/account_billing_details.dart @@ -89,7 +89,7 @@ class _AccountBillingDetailsPageState extends State { backgroundColor: Colors.transparent, title: Text( trans(context, "Billing Details"), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, ), centerTitle: true, ), diff --git a/LabelStoreMax/lib/pages/account_detail.dart b/LabelStoreMax/lib/pages/account_detail.dart index 295fe8e..9671cc9 100644 --- a/LabelStoreMax/lib/pages/account_detail.dart +++ b/LabelStoreMax/lib/pages/account_detail.dart @@ -85,7 +85,7 @@ class _AccountDetailPageState extends State ), title: Text( trans(context, "Account"), - style: Theme.of(context).primaryTextTheme.title, + style: Theme.of(context).primaryTextTheme.headline6, ), centerTitle: true, ), @@ -212,7 +212,12 @@ class _AccountDetailPageState extends State leading: Icon(Icons.account_circle), title: Text(trans(context, "Update details")), onTap: () { - Navigator.pushNamed(context, "/account-update"); + Navigator.pushNamed(context, "/account-update").then((onValue) { + setState(() { + _isLoading = true; + }); + _fetchWpUserData(); + }); }, ), ), @@ -238,9 +243,7 @@ class _AccountDetailPageState extends State child: ListTile( leading: Icon(Icons.exit_to_app), title: Text(trans(context, "Logout")), - onTap: () { - authLogout(context); - }, + onTap: () => authLogout(context), ), ), ], @@ -331,7 +334,7 @@ class _AccountDetailPageState extends State formatStringCurrency(total: _orders[i].total), style: Theme.of(context) .primaryTextTheme - .body1 + .bodyText2 .copyWith( fontWeight: FontWeight.w600, color: Colors.black), @@ -343,7 +346,7 @@ class _AccountDetailPageState extends State trans(context, "items"), style: Theme.of(context) .primaryTextTheme - .body2 + .bodyText1 .copyWith( fontWeight: FontWeight.w600, color: Colors.black), @@ -364,7 +367,7 @@ class _AccountDetailPageState extends State textAlign: TextAlign.right, style: Theme.of(context) .primaryTextTheme - .body2 + .bodyText1 .copyWith( fontWeight: FontWeight.w400, color: Colors.black), diff --git a/LabelStoreMax/lib/pages/account_landing.dart b/LabelStoreMax/lib/pages/account_landing.dart index 9230b14..dea32ef 100644 --- a/LabelStoreMax/lib/pages/account_landing.dart +++ b/LabelStoreMax/lib/pages/account_landing.dart @@ -68,7 +68,7 @@ class _AccountLandingPageState extends State { textAlign: TextAlign.left, style: Theme.of(context) .primaryTextTheme - .display1 + .headline4 .copyWith( fontSize: 24, fontWeight: FontWeight.w700, @@ -119,7 +119,7 @@ class _AccountLandingPageState extends State { Padding( child: Text( trans(context, "Create an account"), - style: Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context).primaryTextTheme.bodyText1, ), padding: EdgeInsets.only(left: 8), ) @@ -133,6 +133,10 @@ class _AccountLandingPageState extends State { action: () { launch(app_forgot_password_url); }), + Divider(), + wsLinkButton(context, title: trans(context, "Back"), action: () { + Navigator.pop(context); + }), ], ), ), @@ -157,7 +161,13 @@ class _AccountLandingPageState extends State { authUser(token); storeUserId(wpUserLoginResponse.data.userId.toString()); - navigatorPush(context, routeName: "/home", forgetAll: true); + showEdgeAlertWith(context, + title: trans(context, "Hello"), + desc: trans(context, "Welcome back"), + style: EdgeAlertStyle.SUCCESS, + icon: Icons.account_circle); + navigatorPush(context, + routeName: UserAuth.instance.redirect, forgetLast: 1); } else { showEdgeAlertWith(context, title: trans(context, "Oops!"), diff --git a/LabelStoreMax/lib/pages/account_order_detail.dart b/LabelStoreMax/lib/pages/account_order_detail.dart index a28e614..2af4bf8 100644 --- a/LabelStoreMax/lib/pages/account_order_detail.dart +++ b/LabelStoreMax/lib/pages/account_order_detail.dart @@ -55,7 +55,7 @@ class _AccountOrderDetailPageState extends State { ), title: Text( "Order #" + _orderId.toString(), - style: Theme.of(context).primaryTextTheme.title, + style: Theme.of(context).primaryTextTheme.headline6, ), centerTitle: true, ), @@ -157,7 +157,7 @@ class _AccountOrderDetailPageState extends State { total: _order.lineItems[i].total), style: Theme.of(context) .primaryTextTheme - .body1 + .bodyText2 .copyWith( fontWeight: FontWeight.w600, color: Colors.black), @@ -169,7 +169,7 @@ class _AccountOrderDetailPageState extends State { .toString(), style: Theme.of(context) .primaryTextTheme - .body2 + .bodyText1 .copyWith( fontWeight: FontWeight.w600, color: Colors.black), diff --git a/LabelStoreMax/lib/pages/account_register.dart b/LabelStoreMax/lib/pages/account_register.dart index 550764c..e00be64 100644 --- a/LabelStoreMax/lib/pages/account_register.dart +++ b/LabelStoreMax/lib/pages/account_register.dart @@ -16,7 +16,6 @@ import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/widgets/buttons.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:woosignal/helpers/shared_pref.dart'; -import 'package:wp_json_api/models/responses/WPUserInfoUpdatedResponse.dart'; import 'package:wp_json_api/models/responses/WPUserRegisterResponse.dart'; import 'package:wp_json_api/wp_json_api.dart'; @@ -61,7 +60,7 @@ class _AccountRegistrationPageState extends State { ), title: Text( "Register", - style: Theme.of(context).primaryTextTheme.title, + style: Theme.of(context).primaryTextTheme.headline6, ), centerTitle: true, ), @@ -173,19 +172,25 @@ class _AccountRegistrationPageState extends State { WPUserRegisterResponse wpUserRegisterResponse = await WPJsonAPI.instance .api((request) => request.wpRegister( - email: email, password: password, username: username)); + email: email.toLowerCase(), + password: password, + username: username)); if (wpUserRegisterResponse != null) { String token = wpUserRegisterResponse.data.userToken; authUser(token); storeUserId(wpUserRegisterResponse.data.userId.toString()); - WPUserInfoUpdatedResponse wpUserInfoUpdatedResponse = await WPJsonAPI - .instance - .api((request) => request.wpUpdateUserInfo(token, - firstName: firstName, lastName: lastName)); + await WPJsonAPI.instance.api((request) => request + .wpUpdateUserInfo(token, firstName: firstName, lastName: lastName)); - navigatorPush(context, routeName: "/home", forgetAll: true); + showEdgeAlertWith(context, + title: trans(context, "Hello") + " $firstName", + desc: trans(context, "you're now logged in"), + style: EdgeAlertStyle.SUCCESS, + icon: Icons.account_circle); + navigatorPush(context, + routeName: UserAuth.instance.redirect, forgetLast: 2); } else { setState(() { showEdgeAlertWith(context, diff --git a/LabelStoreMax/lib/pages/account_shipping_details.dart b/LabelStoreMax/lib/pages/account_shipping_details.dart index 45e9004..8680049 100644 --- a/LabelStoreMax/lib/pages/account_shipping_details.dart +++ b/LabelStoreMax/lib/pages/account_shipping_details.dart @@ -90,7 +90,7 @@ class _AccountShippingDetailsPageState backgroundColor: Colors.transparent, title: Text( trans(context, "Shipping Details"), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, ), centerTitle: true, ), diff --git a/LabelStoreMax/lib/pages/browse_category.dart b/LabelStoreMax/lib/pages/browse_category.dart index 0719588..5f48307 100644 --- a/LabelStoreMax/lib/pages/browse_category.dart +++ b/LabelStoreMax/lib/pages/browse_category.dart @@ -8,9 +8,13 @@ // 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/material.dart'; +import 'package:label_storemax/helpers/enums/sort_enums.dart'; import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:label_storemax/widgets/buttons.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; import 'package:label_storemax/widgets/woosignal_ui.dart'; @@ -29,8 +33,9 @@ class _BrowseCategoryPageState extends State { _BrowseCategoryPageState(this._selectedCategory); List _products = []; - var _productsController = ScrollController(); + RefreshController _refreshController = + RefreshController(initialRefresh: false); ProductCategory _selectedCategory; bool _isLoading; int _page; @@ -46,34 +51,17 @@ class _BrowseCategoryPageState extends State { _page = 1; _shouldStopRequests = false; waitForNextRequest = false; - - _fetchProductsForCategory(); - _addScrollListener(); - } - - _addScrollListener() async { - _productsController.addListener(() { - double maxScroll = _productsController.position.maxScrollExtent; - double currentScroll = _productsController.position.pixels; - double delta = 50.0; - if (maxScroll - currentScroll <= delta) { - if (_shouldStopRequests) { - return; - } - if (waitForNextRequest) { - return; - } - - _fetchMoreProducts(); - } - }); + _fetchMoreProducts(); } _fetchMoreProducts() async { waitForNextRequest = true; - List products = await appWooSignal((api) { - return api.getProducts(perPage: 50, page: _page, status: "publish"); - }); + List products = await appWooSignal((api) => api.getProducts( + perPage: 50, + category: _selectedCategory.id.toString(), + page: _page, + status: "publish", + stockStatus: "instock")); _products.addAll(products); waitForNextRequest = false; _page = _page + 1; @@ -82,13 +70,6 @@ class _BrowseCategoryPageState extends State { if (products.length == 0) { _shouldStopRequests = true; } - } - - _fetchProductsForCategory() async { - _products = await appWooSignal((api) { - return api.getProducts( - category: _selectedCategory.id.toString(), perPage: 50); - }); setState(() { _isLoading = false; }); @@ -109,12 +90,18 @@ class _BrowseCategoryPageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text(trans(context, "Browse"), - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.subtitle1), Text(_selectedCategory.name, - style: Theme.of(context).primaryTextTheme.title) + style: Theme.of(context).primaryTextTheme.headline6) ], ), centerTitle: true, + actions: [ + IconButton( + icon: Icon(Icons.tune), + onPressed: _modalSheetTune, + ) + ], ), body: SafeArea( minimum: safeAreaDefault(), @@ -122,25 +109,105 @@ class _BrowseCategoryPageState extends State { ? Center( child: showAppLoader(), ) - : Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: (_products.length != null && _products.length > 0 - ? GridView.count( - crossAxisCount: 2, - controller: _productsController, - children: List.generate(_products.length, (index) { - return wsCardProductItem(context, - index: index, product: _products[index]); - })) - : wsNoResults(context)), - flex: 1, - ), - ], - ), + : refreshableScroll(context, + refreshController: _refreshController, + onRefresh: _onRefresh, + onLoading: _onLoading, + products: _products, + onTap: _showProduct), ), ); } + + void _onRefresh() async { + await _fetchMoreProducts(); + setState(() {}); + if (_shouldStopRequests) { + _refreshController.resetNoData(); + } else { + _refreshController.refreshCompleted(); + } + } + + void _onLoading() async { + await _fetchMoreProducts(); + + if (mounted) { + setState(() {}); + if (_shouldStopRequests) { + _refreshController.loadNoData(); + } else { + _refreshController.loadComplete(); + } + } + } + + _sortProducts({@required SortByType by}) { + switch (by) { + case SortByType.LowToHigh: + _products.sort((product1, product2) => (parseWcPrice(product1.price)) + .compareTo((double.tryParse(product2.price) ?? 0))); + break; + case SortByType.HighToLow: + _products.sort((product1, product2) => (parseWcPrice(product2.price)) + .compareTo((double.tryParse(product1.price) ?? 0))); + break; + case SortByType.NameAZ: + _products.sort( + (product1, product2) => product1.name.compareTo(product2.name)); + break; + case SortByType.NameZA: + _products.sort( + (product1, product2) => product2.name.compareTo(product1.name)); + break; + } + setState(() { + Navigator.pop(context); + }); + } + + _modalSheetTune() { + wsModalBottom( + context, + title: trans(context, "Sort results"), + bodyWidget: ListView( + children: [ + wsLinkButton(context, + title: trans(context, "Sort: Low to high"), + action: () => _sortProducts(by: SortByType.LowToHigh)), + Divider( + height: 0, + ), + wsLinkButton(context, + title: trans(context, "Sort: High to low"), + action: () => _sortProducts(by: SortByType.HighToLow)), + Divider( + height: 0, + ), + wsLinkButton(context, + title: trans(context, "Sort: Name A-Z"), + action: () => _sortProducts(by: SortByType.NameAZ)), + Divider( + height: 0, + ), + wsLinkButton(context, + title: trans(context, "Sort: Name Z-A"), + action: () => _sortProducts(by: SortByType.NameZA)), + Divider( + height: 0, + ), + wsLinkButton(context, + title: trans(context, "Cancel"), action: _dismissModal) + ], + ), + ); + } + + _dismissModal() { + Navigator.pop(context); + } + + _showProduct(WS.Product product) { + Navigator.pushNamed(context, "/product-detail", arguments: product); + } } diff --git a/LabelStoreMax/lib/pages/browse_search.dart b/LabelStoreMax/lib/pages/browse_search.dart index 07988f5..d07cfd6 100644 --- a/LabelStoreMax/lib/pages/browse_search.dart +++ b/LabelStoreMax/lib/pages/browse_search.dart @@ -11,8 +11,8 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:woosignal/models/response/products.dart' as WS; -import 'package:label_storemax/widgets/woosignal_ui.dart'; class BrowseSearchPage extends StatefulWidget { final String search; @@ -25,7 +25,8 @@ class BrowseSearchPage extends StatefulWidget { class _BrowseSearchState extends State { _BrowseSearchState(this._search); - var _productsController = ScrollController(); + RefreshController _refreshController = + RefreshController(initialRefresh: false); List _products = []; String _search; bool _isLoading; @@ -42,39 +43,26 @@ class _BrowseSearchState extends State { _shouldStopRequests = false; waitForNextRequest = false; - _fetchProductsForSearch(_page); - _addScrollListener(); + _fetchProductsForSearch(); } - _addScrollListener() async { - _productsController.addListener(() { - double maxScroll = _productsController.position.maxScrollExtent; - double currentScroll = _productsController.position.pixels; - double delta = 50.0; - if (maxScroll - currentScroll <= delta) { - if (_shouldStopRequests) { - return; - } - if (waitForNextRequest) { - return; - } - _fetchProductsForSearch(_page); - } - }); - } - - _fetchProductsForSearch(int page) async { + _fetchProductsForSearch() async { waitForNextRequest = true; - List products = await appWooSignal((api) { - _page = _page + 1; - return api.getProducts( - search: _search, perPage: 100, page: page, status: "publish"); - }); + List products = await appWooSignal((api) => api.getProducts( + perPage: 100, + search: _search, + page: _page, + status: "publish", + stockStatus: "instock")); + _products.addAll(products); + waitForNextRequest = false; + _page = _page + 1; + + waitForNextRequest = false; if (products.length == 0) { _shouldStopRequests = true; } setState(() { - _products.addAll(products.toList()); _isLoading = false; }); } @@ -94,9 +82,9 @@ class _BrowseSearchState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text(trans(context, "Search results for"), - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.subtitle1), Text("\"" + _search + "\"", - style: Theme.of(context).primaryTextTheme.title) + style: Theme.of(context).primaryTextTheme.headline6) ], ), centerTitle: true, @@ -107,29 +95,40 @@ class _BrowseSearchState extends State { ? Center( child: showAppLoader(), ) - : Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: (_products.length != null && _products.length > 0 - ? GridView.count( - crossAxisCount: 2, - controller: _productsController, - children: List.generate( - _products.length, - (index) { - return wsCardProductItem(context, - index: index, product: _products[index]); - }, - ), - ) - : wsNoResults(context)), - flex: 1, - ), - ], - ), + : refreshableScroll(context, + refreshController: _refreshController, + onRefresh: _onRefresh, + onLoading: _onLoading, + products: _products, + onTap: _showProduct), ), ); } + + void _onRefresh() async { + await _fetchProductsForSearch(); + setState(() {}); + if (_shouldStopRequests) { + _refreshController.resetNoData(); + } else { + _refreshController.refreshCompleted(); + } + } + + void _onLoading() async { + await _fetchProductsForSearch(); + + if (mounted) { + setState(() {}); + if (_shouldStopRequests) { + _refreshController.loadNoData(); + } else { + _refreshController.loadComplete(); + } + } + } + + _showProduct(WS.Product product) { + Navigator.pushNamed(context, "/product-detail", arguments: product); + } } diff --git a/LabelStoreMax/lib/pages/cart.dart b/LabelStoreMax/lib/pages/cart.dart index 7e757f2..805e311 100644 --- a/LabelStoreMax/lib/pages/cart.dart +++ b/LabelStoreMax/lib/pages/cart.dart @@ -10,7 +10,9 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:label_storemax/helpers/shared_pref/sp_auth.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/models/cart.dart'; import 'package:label_storemax/models/cart_line_item.dart'; import 'package:label_storemax/models/checkout_session.dart'; @@ -67,6 +69,9 @@ class _CartPageState extends State { void _actionProceedToCheckout() async { List cartLineItems = await Cart.getInstance.getCart(); + if (_isLoading == true) { + return; + } if (cartLineItems.length <= 0) { showEdgeAlertWith(context, title: trans(context, "Cart"), @@ -94,6 +99,11 @@ class _CartPageState extends State { CheckoutSession.getInstance.billingDetails.shippingAddress = sfCustomerAddress; } + if (use_wp_login == true && !(await authCheck())) { + UserAuth.instance.redirect = "/checkout"; + Navigator.pushNamed(context, "/account-landing"); + return; + } Navigator.pushNamed(context, "/checkout"); } @@ -131,6 +141,9 @@ class _CartPageState extends State { desc: trans(context, "Item removed"), style: EdgeAlertStyle.WARNING, icon: Icons.remove_shopping_cart); + if (_cartLines.length == 0) { + _isCartEmpty = true; + } setState(() {}); } @@ -142,6 +155,7 @@ class _CartPageState extends State { desc: trans(context, "Cart cleared"), style: EdgeAlertStyle.SUCCESS, icon: Icons.delete_outline); + _isCartEmpty = true; setState(() {}); } @@ -151,7 +165,7 @@ class _CartPageState extends State { resizeToAvoidBottomPadding: false, appBar: AppBar( title: Text(trans(context, "Shopping Cart"), - style: Theme.of(context).appBarTheme.textTheme.title), + style: Theme.of(context).appBarTheme.textTheme.headline6), textTheme: Theme.of(context).textTheme, elevation: 1, actions: [ @@ -161,7 +175,7 @@ class _CartPageState extends State { child: Align( child: Padding( child: Text(trans(context, "Clear Cart"), - style: Theme.of(context).primaryTextTheme.body2), + style: Theme.of(context).primaryTextTheme.bodyText1), padding: EdgeInsets.only(right: 8), ), alignment: Alignment.centerLeft, @@ -191,7 +205,8 @@ class _CartPageState extends State { ), Padding( child: Text(trans(context, "Empty Basket"), - style: Theme.of(context).primaryTextTheme.body1), + style: + Theme.of(context).primaryTextTheme.bodyText2), padding: EdgeInsets.only(top: 10), ) ], diff --git a/LabelStoreMax/lib/pages/checkout_confirmation.dart b/LabelStoreMax/lib/pages/checkout_confirmation.dart index 3d859a5..5b0e7e9 100644 --- a/LabelStoreMax/lib/pages/checkout_confirmation.dart +++ b/LabelStoreMax/lib/pages/checkout_confirmation.dart @@ -30,19 +30,18 @@ class CheckoutConfirmationPage extends StatefulWidget { class CheckoutConfirmationPageState extends State { CheckoutConfirmationPageState(); - GlobalKey _key = - GlobalKey(); - bool _showFullLoader; List _taxRates; TaxRate _taxRate; + bool _isProcessingPayment; @override void initState() { super.initState(); _showFullLoader = true; + _isProcessingPayment = false; if (CheckoutSession.getInstance.paymentType == null) { CheckoutSession.getInstance.paymentType = arrPaymentMethods.first; } @@ -50,8 +49,6 @@ class CheckoutConfirmationPageState extends State { _getTaxes(); } - _fetchUserId() {} - void reloadState({bool showLoader}) { setState(() { _showFullLoader = showLoader ?? false; @@ -135,7 +132,7 @@ class CheckoutConfirmationPageState extends State { children: [ Center( child: Text(trans(context, "Checkout"), - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.subtitle1), ), Expanded( child: Container( @@ -239,8 +236,10 @@ class CheckoutConfirmationPageState extends State { ], ), wsPrimaryButton(context, - title: trans(context, "CHECKOUT"), - action: _handleCheckout), + title: _isProcessingPayment + ? "PROCESSING..." + : trans(context, "CHECKOUT"), + action: _isProcessingPayment ? null : _handleCheckout), ], ) : Center( @@ -252,7 +251,7 @@ class CheckoutConfirmationPageState extends State { padding: const EdgeInsets.only(top: 15), child: Text( trans(context, "One moment") + "...", - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, ), ) ], @@ -301,7 +300,21 @@ class CheckoutConfirmationPageState extends State { return; } + if (_isProcessingPayment == true) { + return; + } + + setState(() { + _isProcessingPayment = true; + }); + CheckoutSession.getInstance.paymentType .pay(context, state: this, taxRate: _taxRate); + + Future.delayed(Duration(milliseconds: 5000), () { + setState(() { + _isProcessingPayment = false; + }); + }); } } diff --git a/LabelStoreMax/lib/pages/checkout_details.dart b/LabelStoreMax/lib/pages/checkout_details.dart index 47b79b9..7e8402f 100644 --- a/LabelStoreMax/lib/pages/checkout_details.dart +++ b/LabelStoreMax/lib/pages/checkout_details.dart @@ -85,35 +85,33 @@ class _CheckoutDetailsPageState extends State { _showSelectCountryModal() { wsModalBottom(context, title: trans(context, "Select a country"), - bodyWidget: Expanded( - child: ListView.separated( - itemCount: appCountryOptions.length, - itemBuilder: (BuildContext context, int index) { - Map strName = appCountryOptions[index]; + bodyWidget: ListView.separated( + itemCount: appCountryOptions.length, + itemBuilder: (BuildContext context, int index) { + Map strName = appCountryOptions[index]; - return InkWell( - child: Container( - child: Text(strName["name"], - style: Theme.of(context).primaryTextTheme.body2), - padding: EdgeInsets.only(top: 25, bottom: 25), - ), - splashColor: Colors.grey, - highlightColor: Colors.black12, - onTap: () { - setState(() { - _strBillingCountry = strName["name"]; - Navigator.of(context).pop(); - }); - }, - ); - }, - separatorBuilder: (cxt, i) { - return Divider( - height: 0, - color: Colors.black12, - ); - }, - ), + return InkWell( + child: Container( + child: Text(strName["name"], + style: Theme.of(context).primaryTextTheme.bodyText1), + padding: EdgeInsets.only(top: 25, bottom: 25), + ), + splashColor: Colors.grey, + highlightColor: Colors.black12, + onTap: () { + setState(() { + _strBillingCountry = strName["name"]; + Navigator.of(context).pop(); + }); + }, + ); + }, + separatorBuilder: (cxt, i) { + return Divider( + height: 0, + color: Colors.black12, + ); + }, )); } @@ -125,7 +123,7 @@ class _CheckoutDetailsPageState extends State { backgroundColor: Colors.transparent, title: Text( trans(context, "Billing & Shipping Details"), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.headline6, ), centerTitle: true, ), @@ -241,7 +239,8 @@ class _CheckoutDetailsPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Text(trans(context, "Remember my details"), - style: Theme.of(context).primaryTextTheme.body2), + style: + Theme.of(context).primaryTextTheme.bodyText2), Checkbox( value: valRememberDetails, onChanged: (bool value) { diff --git a/LabelStoreMax/lib/pages/checkout_payment_type.dart b/LabelStoreMax/lib/pages/checkout_payment_type.dart index efd288c..2bc6bc6 100644 --- a/LabelStoreMax/lib/pages/checkout_payment_type.dart +++ b/LabelStoreMax/lib/pages/checkout_payment_type.dart @@ -43,7 +43,7 @@ class _CheckoutPaymentTypePageState extends State { appBar: AppBar( backgroundColor: Colors.transparent, title: Text(trans(context, "Payment Method"), - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.headline6), automaticallyImplyLeading: false, centerTitle: true, ), @@ -74,35 +74,41 @@ class _CheckoutPaymentTypePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Expanded( - child: ListView.builder( - itemCount: getPaymentTypes().length, - itemBuilder: (BuildContext context, int index) { - return ListTile( - contentPadding: EdgeInsets.only( - top: 10, bottom: 10, left: 8, right: 8), - leading: Image( - image: AssetImage("assets/images/" + - getPaymentTypes()[index].assetImage), - width: 60, - fit: BoxFit.fitHeight, - alignment: Alignment.center), - title: Text(getPaymentTypes()[index].desc, - style: Theme.of(context) - .primaryTextTheme - .subhead), - selected: true, - trailing: (CheckoutSession - .getInstance.paymentType == - getPaymentTypes()[index] - ? Icon(Icons.check) - : null), - onTap: () { - CheckoutSession.getInstance.paymentType = - getPaymentTypes()[index]; - Navigator.pop(context); - }, - ); - }), + child: ListView.separated( + itemCount: getPaymentTypes().length, + itemBuilder: (BuildContext context, int index) { + return ListTile( + contentPadding: EdgeInsets.only( + top: 10, bottom: 10, left: 8, right: 8), + leading: Image( + image: AssetImage("assets/images/" + + getPaymentTypes()[index].assetImage), + width: 60, + fit: BoxFit.contain, + alignment: Alignment.center), + title: Text(getPaymentTypes()[index].desc, + style: Theme.of(context) + .primaryTextTheme + .subtitle1), + selected: true, + trailing: + (CheckoutSession.getInstance.paymentType == + getPaymentTypes()[index] + ? Icon(Icons.check) + : null), + onTap: () { + CheckoutSession.getInstance.paymentType = + getPaymentTypes()[index]; + Navigator.pop(context); + }, + ); + }, + separatorBuilder: (cxt, i) { + return Divider( + color: Colors.black12, + ); + }, + ), ), wsLinkButton(context, title: trans(context, "CANCEL"), action: () { diff --git a/LabelStoreMax/lib/pages/checkout_shipping_type.dart b/LabelStoreMax/lib/pages/checkout_shipping_type.dart index 6b57661..db3342a 100644 --- a/LabelStoreMax/lib/pages/checkout_shipping_type.dart +++ b/LabelStoreMax/lib/pages/checkout_shipping_type.dart @@ -17,7 +17,6 @@ import 'package:label_storemax/models/customer_address.dart'; import 'package:label_storemax/models/shipping_type.dart'; import 'package:label_storemax/widgets/app_loader.dart'; import 'package:label_storemax/widgets/buttons.dart'; -import 'package:math_expressions/math_expressions.dart'; import 'package:woosignal/models/response/shipping_method.dart'; import 'package:label_storemax/app_country_options.dart'; @@ -49,9 +48,8 @@ class _CheckoutShippingTypePageState extends State { } _getShippingMethods() async { - List wsShipping = await appWooSignal((api) { - return api.getShippingMethods(); - }); + List wsShipping = + await appWooSignal((api) => api.getShippingMethods()); CustomerAddress customerAddress = CheckoutSession.getInstance.billingDetails.shippingAddress; String postalCode = customerAddress.postalCode; @@ -70,9 +68,12 @@ class _CheckoutShippingTypePageState extends State { } } - if (_shipping != null) { + if (_shipping != null && _shipping.methods != null) { if (_shipping.methods.flatRate != null) { - _shipping.methods.flatRate.forEach((flatRate) { + _shipping.methods.flatRate + .where((t) => t != null) + .toList() + .forEach((flatRate) { Map tmpShippingOption = {}; tmpShippingOption = { "id": flatRate.id, @@ -86,7 +87,10 @@ class _CheckoutShippingTypePageState extends State { } if (_shipping.methods.localPickup != null) { - _shipping.methods.localPickup.forEach((localPickup) { + _shipping.methods.localPickup + .where((t) => t != null) + .toList() + .forEach((localPickup) { Map tmpShippingOption = {}; tmpShippingOption = { "id": localPickup.id, @@ -100,7 +104,10 @@ class _CheckoutShippingTypePageState extends State { } if (_shipping.methods.freeShipping != null) { - _shipping.methods.freeShipping.forEach((freeShipping) { + _shipping.methods.freeShipping + .where((t) => t != null) + .toList() + .forEach((freeShipping) { if (isNumeric(freeShipping.cost)) { Map tmpShippingOption = {}; tmpShippingOption = { @@ -183,7 +190,7 @@ class _CheckoutShippingTypePageState extends State { context, "Shipping Methods", ), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.headline6, ), automaticallyImplyLeading: false, centerTitle: true, @@ -234,7 +241,7 @@ class _CheckoutShippingTypePageState extends State { ['title'], style: Theme.of(context) .primaryTextTheme - .subhead), + .subtitle1), selected: true, subtitle: FutureBuilder( future: _getShippingPrice(index), @@ -299,7 +306,7 @@ class _CheckoutShippingTypePageState extends State { "Shipping is not supported for your country, sorry"), style: Theme.of(context) .primaryTextTheme - .title, + .headline6, textAlign: TextAlign.center))), wsLinkButton(context, title: trans(context, "CANCEL"), action: () { diff --git a/LabelStoreMax/lib/pages/checkout_status.dart b/LabelStoreMax/lib/pages/checkout_status.dart index 0efbd36..f9e810b 100644 --- a/LabelStoreMax/lib/pages/checkout_status.dart +++ b/LabelStoreMax/lib/pages/checkout_status.dart @@ -60,25 +60,25 @@ class _CheckoutStatusState extends State { Padding( child: Text( trans(context, "Order Status"), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, ), padding: EdgeInsets.only(bottom: 15), ), Text( trans(context, "Thank You!"), - style: Theme.of(context).primaryTextTheme.title, + style: Theme.of(context).primaryTextTheme.headline6, textAlign: TextAlign.left, ), Text( trans(context, "Your transaction details"), - style: Theme.of(context).primaryTextTheme.body1, + style: Theme.of(context).primaryTextTheme.bodyText2, textAlign: TextAlign.left, ), Text( trans(context, "Order Ref") + ". #" + _order.id.toString(), - style: Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context).primaryTextTheme.bodyText1, textAlign: TextAlign.left, ), ], @@ -96,7 +96,9 @@ class _CheckoutStatusState extends State { child: Image( image: new AssetImage("assets/images/camion.gif"), height: 170), - color: Colors.white, + decoration: BoxDecoration( + color: Colors.white, + ), width: double.infinity), ], ), @@ -104,7 +106,7 @@ class _CheckoutStatusState extends State { child: Padding( child: Text( trans(context, "Items"), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, textAlign: TextAlign.left, ), padding: EdgeInsets.all(8), @@ -130,24 +132,28 @@ class _CheckoutStatusState extends State { Text(lineItem.name, style: Theme.of(context) .primaryTextTheme - .body2, + .bodyText1, softWrap: false, maxLines: 2, overflow: TextOverflow.ellipsis), Text("x" + lineItem.quantity.toString(), style: Theme.of(context) .primaryTextTheme - .body1), + .bodyText2), ], ), ), Text( formatStringCurrency( total: lineItem.total.toString()), - style: Theme.of(context).primaryTextTheme.body2) + style: Theme.of(context) + .primaryTextTheme + .bodyText1) ], ), - decoration: BoxDecoration(color: Colors.white), + decoration: BoxDecoration( + color: Colors.white, + ), padding: EdgeInsets.all(16), margin: EdgeInsets.all(8), ); diff --git a/LabelStoreMax/lib/pages/error_page.dart b/LabelStoreMax/lib/pages/error_page.dart index 69dc746..4673d61 100644 --- a/LabelStoreMax/lib/pages/error_page.dart +++ b/LabelStoreMax/lib/pages/error_page.dart @@ -46,7 +46,7 @@ class _ErrorPageState extends State { padding: const EdgeInsets.all(16.0), child: Text( trans(context, "Sorry, something went wrong"), - style: Theme.of(context).primaryTextTheme.body1, + style: Theme.of(context).primaryTextTheme.bodyText2, textAlign: TextAlign.center, ), ), diff --git a/LabelStoreMax/lib/pages/home.dart b/LabelStoreMax/lib/pages/home.dart index 264cf77..053370e 100644 --- a/LabelStoreMax/lib/pages/home.dart +++ b/LabelStoreMax/lib/pages/home.dart @@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/widgets/app_loader.dart'; import 'package:label_storemax/widgets/cart_icon.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:woosignal/models/response/product_category.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS; import 'package:label_storemax/widgets/woosignal_ui.dart'; @@ -26,10 +27,11 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { _HomePageState(); + RefreshController _refreshController = + RefreshController(initialRefresh: false); List _products = []; List _categories = []; - - var _productsController = ScrollController(); + final GlobalKey _key = GlobalKey(); int _page; bool _shouldStopRequests; @@ -41,115 +43,68 @@ class _HomePageState extends State { super.initState(); _isLoading = true; - _page = 1; _home(); - _addScrollListener(); } _home() async { - await _fetchProducts(); - await _fetchCategories(); _shouldStopRequests = false; waitForNextRequest = false; + await _fetchMoreProducts(); + await _fetchCategories(); setState(() { _isLoading = false; }); } - _fetchProducts() async { - _products = await appWooSignal((api) { - return api.getProducts(perPage: 50, page: _page, status: "publish"); - }); - } - _fetchCategories() async { _categories = await appWooSignal((api) { return api.getProductCategories(); }); } - _addScrollListener() async { - _productsController.addListener(() { - double maxScroll = _productsController.position.maxScrollExtent; - double currentScroll = _productsController.position.pixels; - double delta = 50.0; - if (maxScroll - currentScroll <= delta) { - if (_shouldStopRequests) { - return; - } - if (waitForNextRequest) { - return; - } - _fetchMoreProducts(); - } - }); - } - _fetchMoreProducts() async { + if (_shouldStopRequests) { + return; + } + if (waitForNextRequest) { + return; + } waitForNextRequest = true; - List products = await appWooSignal((api) { - _page = _page + 1; - return api.getProducts(perPage: 50, page: _page, status: "publish"); - }); + List products = await appWooSignal((api) => api.getProducts( + perPage: 50, page: _page, status: "publish", stockStatus: "instock")); + _page = _page + 1; if (products.length == 0) { _shouldStopRequests = true; } + waitForNextRequest = false; setState(() { _products.addAll(products.toList()); }); } void _modalBottomSheetMenu() { - showModalBottomSheet( - context: context, - backgroundColor: Colors.transparent, - builder: (builder) { - return new Container( - height: double.infinity, - width: double.infinity - 10, - color: Colors.transparent, - child: new Container( - padding: EdgeInsets.only(top: 25, left: 18, right: 18), - decoration: new BoxDecoration( - color: Colors.white, - borderRadius: new BorderRadius.only( - topLeft: const Radius.circular(10.0), - topRight: const Radius.circular(10.0), - ), - ), - child: Column( - children: [ - Text(trans(context, "Categories"), - style: Theme.of(context).primaryTextTheme.display1, - textAlign: TextAlign.left), - Expanded( - child: new ListView.builder( - itemCount: _categories.length, - itemBuilder: (BuildContext context, int index) { - return InkWell( - child: Container( - child: Text(_categories[index].name), - padding: EdgeInsets.all(15), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: HexColor("#f2f2f2"), width: 2), - ), - ), - ), - onTap: () { - Navigator.pushNamed(context, "/browse-category", - arguments: _categories[index]); - }, - ); - }), - ) - ], - ), - ), - ); - }, + _key.currentState.setState(() {}); + wsModalBottom( + context, + title: trans(context, "Categories"), + bodyWidget: ListView.separated( + itemCount: _categories.length, + separatorBuilder: (cxt, i) { + return Divider(); + }, + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: Text(parseHtmlString(_categories[index].name)), + onTap: () { + Navigator.pop(context); + Navigator.pushNamed(context, "/browse-category", + arguments: _categories[index]) + .then((value) => setState(() {})); + }, + ); + }, + ), ); } @@ -161,9 +116,7 @@ class _HomePageState extends State { leading: Container( child: IconButton( icon: Icon(Icons.menu), - onPressed: () { - Navigator.pushNamed(context, "/home-menu"); - }, + onPressed: () => Navigator.pushNamed(context, "/home-menu"), ), margin: EdgeInsets.only(left: 0), ), @@ -177,11 +130,10 @@ class _HomePageState extends State { color: Colors.black, size: 35, ), - onPressed: () { - Navigator.pushNamed(context, "/home-search"); - }, + onPressed: () => Navigator.pushNamed(context, "/home-search") + .then((value) => _key.currentState.setState(() {})), ), - wsCartIcon(context) + wsCartIcon(context, key: _key) ], ), body: SafeArea( @@ -198,10 +150,10 @@ class _HomePageState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ Text(trans(context, "Shop") + " / ", - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.subtitle1), Text( trans(context, "Newest"), - style: Theme.of(context).primaryTextTheme.body1, + style: Theme.of(context).primaryTextTheme.bodyText2, ) ], ), @@ -210,25 +162,21 @@ class _HomePageState extends State { height: 60, child: Text( trans(context, "Browse categories"), - style: Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context).primaryTextTheme.bodyText1, ), - onPressed: () { - _modalBottomSheetMenu(); - }, + onPressed: _modalBottomSheetMenu, ) ], ), (_isLoading ? Expanded(child: showAppLoader()) : Expanded( - child: GridView.count( - controller: _productsController, - crossAxisCount: 2, - children: List.generate(_products.length, (index) { - return wsCardProductItem(context, - index: index, product: _products[index]); - }), - ), + child: refreshableScroll(context, + refreshController: _refreshController, + onRefresh: _onRefresh, + onLoading: _onLoading, + products: _products, + onTap: _showProduct), flex: 1, )), ], @@ -236,4 +184,32 @@ class _HomePageState extends State { ), ); } + + void _onRefresh() async { + await _fetchMoreProducts(); + setState(() {}); + if (_shouldStopRequests) { + _refreshController.resetNoData(); + } else { + _refreshController.refreshCompleted(); + } + } + + void _onLoading() async { + await _fetchMoreProducts(); + + if (mounted) { + setState(() {}); + if (_shouldStopRequests) { + _refreshController.loadNoData(); + } else { + _refreshController.loadComplete(); + } + } + } + + _showProduct(WS.Product product) { + Navigator.pushNamed(context, "/product-detail", arguments: product) + .then((value) => _key.currentState.setState(() {})); + } } diff --git a/LabelStoreMax/lib/pages/home_menu.dart b/LabelStoreMax/lib/pages/home_menu.dart index af4ce9b..7ed8d64 100644 --- a/LabelStoreMax/lib/pages/home_menu.dart +++ b/LabelStoreMax/lib/pages/home_menu.dart @@ -9,6 +9,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:label_storemax/helpers/shared_pref/sp_auth.dart'; import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/widgets/menu_item.dart'; import 'package:label_storemax/helpers/tools.dart'; @@ -37,7 +38,7 @@ class _HomeMenuPageState extends State { backgroundColor: Colors.transparent, elevation: 0.0, title: Text(trans(context, "Menu"), - style: Theme.of(context).primaryTextTheme.title), + style: Theme.of(context).primaryTextTheme.headline6), leading: IconButton( icon: Icon(Icons.close), onPressed: () { @@ -89,7 +90,12 @@ class _HomeMenuPageState extends State { Navigator.pushNamed(context, "/about"); } - void _actionProfile() { + void _actionProfile() async { + if (use_wp_login == true && !(await authCheck())) { + UserAuth.instance.redirect = "/account-detail"; + Navigator.pushNamed(context, "/account-landing"); + return; + } Navigator.pushNamed(context, "/account-detail"); } } diff --git a/LabelStoreMax/lib/pages/home_search.dart b/LabelStoreMax/lib/pages/home_search.dart index 8551b41..13cf4a7 100644 --- a/LabelStoreMax/lib/pages/home_search.dart +++ b/LabelStoreMax/lib/pages/home_search.dart @@ -61,7 +61,7 @@ class _HomeSearchPageState extends State { ), TextField( controller: _txtSearchController, - style: Theme.of(context).primaryTextTheme.display2, + style: Theme.of(context).primaryTextTheme.headline3, keyboardType: TextInputType.text, autocorrect: false, autofocus: true, diff --git a/LabelStoreMax/lib/pages/product_detail.dart b/LabelStoreMax/lib/pages/product_detail.dart index 35d840c..60deae1 100644 --- a/LabelStoreMax/lib/pages/product_detail.dart +++ b/LabelStoreMax/lib/pages/product_detail.dart @@ -50,9 +50,23 @@ class _ProductDetailState extends State { } _fetchProductVariations() async { - _productVariations = await appWooSignal((api) { - return api.getProductVariations(_product.id); - }); + List tmpVariations = []; + int currentPage = 1; + + bool isFetching = true; + while (isFetching) { + List tmp = await appWooSignal((api) { + return api.getProductVariations(_product.id, + perPage: 100, page: currentPage); + }); + if (tmp != null && tmp.length > 0) { + tmpVariations.addAll(tmp); + currentPage += 1; + } else { + isFetching = false; + } + } + _productVariations = tmpVariations; setState(() { _isLoading = false; }); @@ -89,33 +103,30 @@ class _ProductDetailState extends State { title: trans(context, "Select a") + " " + _product.attributes[attributeIndex].name, - bodyWidget: Expanded( - child: ListView.separated( - 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], - style: Theme.of(context).primaryTextTheme.subhead), - trailing: (_tmpAttributeObj.isNotEmpty && - _tmpAttributeObj.containsKey(attributeIndex) && - _tmpAttributeObj[attributeIndex]["value"] == - _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] - }; - Navigator.pop(context, () {}); - Navigator.pop(context); - _modalBottomSheetAttributes(); - }, - ); - }, - ), - flex: 1, + bodyWidget: ListView.separated( + 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], + style: Theme.of(context).primaryTextTheme.subtitle1), + trailing: (_tmpAttributeObj.isNotEmpty && + _tmpAttributeObj.containsKey(attributeIndex) && + _tmpAttributeObj[attributeIndex]["value"] == + _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] + }; + Navigator.pop(context, () {}); + Navigator.pop(context); + _modalBottomSheetAttributes(); + }, + ); + }, ), ); } @@ -134,8 +145,7 @@ class _ProductDetailState extends State { wsModalBottom( context, title: trans(context, "Options"), - bodyWidget: Expanded( - child: ListView.separated( + bodyWidget: ListView.separated( itemCount: _product.attributes.length, separatorBuilder: (BuildContext context, int index) => Divider( color: Colors.black12, @@ -144,11 +154,11 @@ class _ProductDetailState extends State { itemBuilder: (BuildContext context, int index) { return ListTile( title: Text(_product.attributes[index].name, - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.subtitle1), subtitle: (_tmpAttributeObj.isNotEmpty && _tmpAttributeObj.containsKey(index)) ? Text(_tmpAttributeObj[index]["value"], - style: Theme.of(context).primaryTextTheme.body2) + style: Theme.of(context).primaryTextTheme.bodyText1) : Text(trans(context, "Select a") + " " + _product.attributes[index].name), @@ -161,7 +171,7 @@ class _ProductDetailState extends State { }, ); }, - )), + ), extraWidget: Container( decoration: BoxDecoration( border: Border(top: BorderSide(color: Colors.black12, width: 1))), @@ -179,14 +189,14 @@ class _ProductDetailState extends State { findProductVariation() == null) ? trans(context, "This variation is unavailable") : trans(context, "Choose your options"))), - style: Theme.of(context).primaryTextTheme.subhead), + style: Theme.of(context).primaryTextTheme.subtitle1), Text( (findProductVariation() != null ? findProductVariation().stockStatus != "instock" ? trans(context, "Out of stock") : "" : ""), - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, ), wsPrimaryButton(context, title: trans(context, "Add to cart"), action: () { @@ -255,11 +265,10 @@ class _ProductDetailState extends State { wsModalBottom( context, title: trans(context, "Description"), - bodyWidget: Expanded( - child: SingleChildScrollView( - child: Text(parseHtmlString(_product.description)), + bodyWidget: SingleChildScrollView( + child: Text( + parseHtmlString(_product.description), ), - flex: 1, ), ); } @@ -312,7 +321,9 @@ class _ProductDetailState extends State { Container( height: 100, padding: EdgeInsets.symmetric( - vertical: 10, horizontal: 16), + vertical: 10, + horizontal: 16, + ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -320,8 +331,11 @@ class _ProductDetailState extends State { Flexible( child: Text( _product.name, - style: - Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context) + .primaryTextTheme + .bodyText1 + .copyWith( + color: Colors.black87, fontSize: 20), textAlign: TextAlign.left, overflow: TextOverflow.ellipsis, maxLines: 2, @@ -338,13 +352,24 @@ class _ProductDetailState extends State { total: _product.price), style: Theme.of(context) .primaryTextTheme - .display1 + .headline4 .copyWith( fontSize: 20, ), textAlign: TextAlign.right, ), - ], + (_product.onSale == true + ? Text( + formatStringCurrency( + total: _product.regularPrice), + style: TextStyle( + color: Colors.grey, + decoration: + TextDecoration.lineThrough, + ), + ) + : null) + ].where((t) => t != null).toList(), ), flex: 2, ) @@ -352,7 +377,10 @@ class _ProductDetailState extends State { ), ), Container( - color: Colors.white, + decoration: BoxDecoration( + color: Colors.white, + boxShadow: wsBoxShadow(), + borderRadius: BorderRadius.circular(4)), padding: EdgeInsets.symmetric(vertical: 4, horizontal: 16), height: 180, @@ -378,15 +406,13 @@ class _ProductDetailState extends State { trans(context, "Full description"), style: Theme.of(context) .primaryTextTheme - .body1 + .bodyText2 .copyWith(fontSize: 14), textAlign: TextAlign.right, ), height: 50, minWidth: 60, - onPressed: () { - _modalBottomSheetMenu(); - }, + onPressed: _modalBottomSheetMenu, ), ], ), @@ -432,7 +458,8 @@ class _ProductDetailState extends State { children: [ Text( "Quantity", - style: Theme.of(context).primaryTextTheme.body2, + style: + Theme.of(context).primaryTextTheme.bodyText1, ), Row( children: [ @@ -451,8 +478,9 @@ class _ProductDetailState extends State { ), Text( _quantityIndicator.toString(), - style: - Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context) + .primaryTextTheme + .bodyText1, ), IconButton( icon: Icon( @@ -479,11 +507,12 @@ class _ProductDetailState extends State { child: Align( child: Text( formatStringCurrency( - total: (double.parse(_product.price) * + total: (parseWcPrice(_product.price) * _quantityIndicator) .toString()), - style: - Theme.of(context).primaryTextTheme.display1, + style: Theme.of(context) + .primaryTextTheme + .headline4, textAlign: TextAlign.center, ), alignment: Alignment.centerLeft, @@ -492,9 +521,7 @@ class _ProductDetailState extends State { child: wsPrimaryButton( context, title: trans(context, "Add to cart"), - action: () { - _addItemToCart(); - }, + action: () => _addItemToCart(), ), ), ], diff --git a/LabelStoreMax/lib/pages/product_image_viewer_page.dart b/LabelStoreMax/lib/pages/product_image_viewer_page.dart index bbfa233..a8af256 100644 --- a/LabelStoreMax/lib/pages/product_image_viewer_page.dart +++ b/LabelStoreMax/lib/pages/product_image_viewer_page.dart @@ -50,13 +50,15 @@ class _ProductImageViewerPageState extends State { index: _initialIndex, itemBuilder: (BuildContext context, int index) { return CachedNetworkImage( - imageUrl: _arrImageSrc[index], - placeholder: (context, url) => - new CircularProgressIndicator( - strokeWidth: 2, backgroundColor: Colors.black12), - errorWidget: (context, url, error) => - new Icon(Icons.error), - fit: BoxFit.contain); + imageUrl: _arrImageSrc[index], + placeholder: (context, url) => + new CircularProgressIndicator( + strokeWidth: 2, + backgroundColor: Colors.black12, + ), + errorWidget: (context, url, error) => new Icon(Icons.error), + fit: BoxFit.contain, + ); }, itemCount: _arrImageSrc.length, viewportFraction: 0.9, diff --git a/LabelStoreMax/lib/providers/cash_on_delivery.dart b/LabelStoreMax/lib/providers/cash_on_delivery.dart new file mode 100644 index 0000000..33a9e54 --- /dev/null +++ b/LabelStoreMax/lib/providers/cash_on_delivery.dart @@ -0,0 +1,51 @@ +// +// LabelCore +// Label StoreMAX +// +// Created by Anthony Gordon. +// 2020, WooSignal Ltd. All rights reserved. +// + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// + +import 'package:flutter/widgets.dart'; +import 'package:label_storemax/helpers/data/order_wc.dart'; +import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/pages/checkout_confirmation.dart'; +import 'package:woosignal/models/payload/order_wc.dart'; +import 'package:woosignal/models/response/order.dart'; +import 'package:woosignal/models/response/tax_rate.dart'; + +cashOnDeliveryPay(context, + {@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { + try { + OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: false); + + Order order = await appWooSignal((api) => api.createOrder(orderWC)); + + if (order != null) { + Cart.getInstance.clear(); + Navigator.pushNamed(context, "/checkout-status", arguments: order); + } else { + showEdgeAlertWith( + context, + title: trans(context, "Error"), + desc: trans(context, + trans(context, "Something went wrong, please contact our store")), + ); + state.reloadState(showLoader: false); + } + } catch (ex) { + showEdgeAlertWith( + context, + title: trans(context, "Error"), + desc: trans(context, + trans(context, "Something went wrong, please contact our store")), + ); + state.reloadState(showLoader: false); + } +} diff --git a/LabelStoreMax/lib/providers/example_pay.dart b/LabelStoreMax/lib/providers/example_pay.dart new file mode 100644 index 0000000..bf80751 --- /dev/null +++ b/LabelStoreMax/lib/providers/example_pay.dart @@ -0,0 +1,62 @@ +// +// LabelCore +// Label StoreMAX +// +// Created by Anthony Gordon. +// 2020, WooSignal Ltd. All rights reserved. +// + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// + +import 'package:flutter/widgets.dart'; +import 'package:label_storemax/helpers/data/order_wc.dart'; +import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/pages/checkout_confirmation.dart'; +import 'package:woosignal/models/payload/order_wc.dart'; +import 'package:woosignal/models/response/order.dart'; +import 'package:woosignal/models/response/tax_rate.dart'; + +// CALL THE BELOW METHOD TO SHOW AND HIDE LOADER +// state.reloadState(showLoader: false); + +// CHECKOUT HELPER +// IT WILL RETURN THE ORDER TOTAL, BILLING DETAILS AND CART +// await checkout(taxRate, (total, billingDetails, cart) async { +// +// }); + +// REMEMBER TO ADD THIS METHOD E.G. "examplePay" TO THE APP_PAYMENT_METHODS +// AS THE PAY METHOD + +examplePay(context, + {@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { + // HANDLE YOUR PAYMENT INTEGRATION HERE + // ... + // ... + // ... + // THEN ON SUCCESS OF A PAYMENT YOU CAN DO SOMETHING SIMILAR BELOW + + // CREATES ORDER MODEL + OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true); + + // CREATES ORDER IN WOOCOMMERCE + Order order = await appWooSignal((api) => api.createOrder(orderWC)); + + // CHECK IF ORDER IS NULL + if (order != null) { + Cart.getInstance.clear(); + Navigator.pushNamed(context, "/checkout-status", arguments: order); + } else { + showEdgeAlertWith( + context, + title: trans(context, "Error"), + desc: trans(context, + trans(context, "Something went wrong, please contact our store")), + ); + state.reloadState(showLoader: false); + } +} diff --git a/LabelStoreMax/lib/providers/stripe_pay.dart b/LabelStoreMax/lib/providers/stripe_pay.dart index c55277a..8640156 100644 --- a/LabelStoreMax/lib/providers/stripe_pay.dart +++ b/LabelStoreMax/lib/providers/stripe_pay.dart @@ -25,87 +25,94 @@ import 'package:woosignal_stripe/woosignal_stripe.dart'; stripePay(context, {@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { - // CONFIGURE STRIPE - FlutterStripePayment.setStripeSettings( - stripeAccount: app_stripe_account, liveMode: app_stripe_live_mode); + try { + // CONFIGURE STRIPE + FlutterStripePayment.setStripeSettings( + stripeAccount: app_stripe_account, liveMode: app_stripe_live_mode); - var paymentResponse = await FlutterStripePayment.addPaymentMethod(); + var paymentResponse = await FlutterStripePayment.addPaymentMethod(); - // CHECK STATUS FROM STRIPE - if (paymentResponse.status == PaymentResponseStatus.succeeded) { - state.reloadState(showLoader: true); + // CHECK STATUS FROM STRIPE + if (paymentResponse.status == PaymentResponseStatus.succeeded) { + state.reloadState(showLoader: true); - // CHECKOUT HELPER - await checkout(taxRate, (total, billingDetails, cart) async { - Map address = { - "name": billingDetails.billingAddress.nameFull(), - "line1": billingDetails.shippingAddress.addressLine, - "city": billingDetails.shippingAddress.city, - "postal_code": billingDetails.shippingAddress.postalCode, - "country": billingDetails.shippingAddress.country - }; + // CHECKOUT HELPER + await checkout(taxRate, (total, billingDetails, cart) async { + Map address = { + "name": billingDetails.billingAddress.nameFull(), + "line1": billingDetails.shippingAddress.addressLine, + "city": billingDetails.shippingAddress.city, + "postal_code": billingDetails.shippingAddress.postalCode, + "country": billingDetails.shippingAddress.country + }; - String cartShortDesc = await cart.cartShortDesc(); + String cartShortDesc = await cart.cartShortDesc(); - dynamic rsp = await appWooSignal((api) { - return api.stripePaymentIntent( - amount: total, - email: billingDetails.billingAddress.emailAddress, - desc: cartShortDesc, - shipping: address, + dynamic rsp = await appWooSignal((api) => api.stripePaymentIntent( + amount: total, + email: billingDetails.billingAddress.emailAddress, + desc: cartShortDesc, + shipping: address, + )); + + if (rsp == null) { + showEdgeAlertWith(context, + title: trans(context, "Oops!"), + desc: trans(context, "Something went wrong, please try again."), + icon: Icons.payment, + style: EdgeAlertStyle.WARNING); + state.reloadState(showLoader: false); + return; + } + + String clientSecret = rsp["client_secret"]; + var intentResponse = await FlutterStripePayment.confirmPaymentIntent( + clientSecret, + paymentResponse.paymentMethodId, + (double.parse(total) * 100), ); - }); - if (rsp == null) { - showEdgeAlertWith(context, - title: trans(context, "Oops!"), - desc: trans(context, "Something went wrong, please try again."), - icon: Icons.payment, - style: EdgeAlertStyle.WARNING); - state.reloadState(showLoader: false); - return; - } + if (intentResponse.status == PaymentResponseStatus.succeeded) { + OrderWC orderWC = await buildOrderWC(taxRate: taxRate); + Order order = await appWooSignal((api) => api.createOrder(orderWC)); - String clientSecret = rsp["client_secret"]; - var intentResponse = await FlutterStripePayment.confirmPaymentIntent( - clientSecret, - paymentResponse.paymentMethodId, - (double.parse(total) * 100), - ); - - if (intentResponse.status == PaymentResponseStatus.succeeded) { - OrderWC orderWC = await buildOrderWC(taxRate: taxRate); - Order order = await appWooSignal((api) { - return api.createOrder(orderWC); - }); - - if (order != null) { - Cart.getInstance.clear(); - Navigator.pushNamed(context, "/checkout-status", arguments: order); - } else { + if (order != null) { + Cart.getInstance.clear(); + Navigator.pushNamed(context, "/checkout-status", arguments: order); + } else { + showEdgeAlertWith( + context, + title: trans(context, "Error"), + desc: trans( + context, + trans(context, + "Something went wrong, please contact our store")), + ); + state.reloadState(showLoader: false); + } + } else if (intentResponse.status == PaymentResponseStatus.failed) { + if (app_debug) { + print(intentResponse.errorMessage); + } showEdgeAlertWith( context, title: trans(context, "Error"), - desc: trans( - context, - trans( - context, "Something went wrong, please contact our store")), + desc: intentResponse.errorMessage, ); state.reloadState(showLoader: false); + } else { + state.reloadState(showLoader: false); } - } else if (intentResponse.status == PaymentResponseStatus.failed) { - if (app_debug) { - print(intentResponse.errorMessage); - } - showEdgeAlertWith( - context, - title: trans(context, "Error"), - desc: intentResponse.errorMessage, - ); - state.reloadState(showLoader: false); - } else { - state.reloadState(showLoader: false); - } - }); + }); + } else { + state.reloadState(showLoader: false); + } + } catch (ex) { + showEdgeAlertWith(context, + title: trans(context, "Oops!"), + desc: trans(context, "Something went wrong, please try again."), + icon: Icons.payment, + style: EdgeAlertStyle.WARNING); + state.reloadState(showLoader: false); } } diff --git a/LabelStoreMax/lib/widgets/buttons.dart b/LabelStoreMax/lib/widgets/buttons.dart index d9a1496..c21c19f 100644 --- a/LabelStoreMax/lib/widgets/buttons.dart +++ b/LabelStoreMax/lib/widgets/buttons.dart @@ -38,7 +38,7 @@ Widget wsSecondaryButton(BuildContext context, child: RaisedButton( padding: EdgeInsets.all(10), child: Text(title, - style: Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context).primaryTextTheme.bodyText1, textAlign: TextAlign.center), onPressed: action, color: HexColor("#f6f6f9"), @@ -54,7 +54,7 @@ Widget wsLinkButton(BuildContext context, child: MaterialButton( padding: EdgeInsets.all(10), child: Text(title, - style: Theme.of(context).primaryTextTheme.body2, + style: Theme.of(context).primaryTextTheme.bodyText1, textAlign: TextAlign.left), onPressed: action, elevation: 0, diff --git a/LabelStoreMax/lib/widgets/cart_icon.dart b/LabelStoreMax/lib/widgets/cart_icon.dart index a2964ef..cfc2210 100644 --- a/LabelStoreMax/lib/widgets/cart_icon.dart +++ b/LabelStoreMax/lib/widgets/cart_icon.dart @@ -12,44 +12,48 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/models/cart.dart'; import 'package:label_storemax/models/cart_line_item.dart'; -Widget wsCartIcon(BuildContext context) { - return IconButton( - icon: Stack( - children: [ - Positioned.fill( - child: Align( - child: Icon(Icons.shopping_cart, size: 20, color: Colors.black87), - alignment: Alignment.bottomCenter, - ), - bottom: 0), - Positioned.fill( - child: Align( - child: FutureBuilder>( - future: Cart.getInstance.getCart(), - builder: (BuildContext context, - AsyncSnapshot> snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return Text(""); - default: - if (snapshot.hasError) - return Text(""); - else - return new Text( - snapshot.data.length.toString(), - style: Theme.of(context).primaryTextTheme.body2, - textAlign: TextAlign.center, - ); - } - }, +Widget wsCartIcon(BuildContext context, {Key key}) { + return StatefulBuilder( + key: key, + builder: (BuildContext context, StateSetter setState) => IconButton( + icon: Stack( + children: [ + Positioned.fill( + child: Align( + child: + Icon(Icons.shopping_cart, size: 20, color: Colors.black87), + alignment: Alignment.bottomCenter, ), - alignment: Alignment.topCenter, - ), - top: 0) - ], + bottom: 0), + Positioned.fill( + child: Align( + child: FutureBuilder>( + future: Cart.getInstance.getCart(), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return Text(""); + default: + if (snapshot.hasError) + return Text(""); + else + return new Text( + snapshot.data.length.toString(), + style: Theme.of(context).primaryTextTheme.bodyText1, + textAlign: TextAlign.center, + ); + } + }, + ), + alignment: Alignment.topCenter, + ), + top: 0) + ], + ), + onPressed: () { + Navigator.pushNamed(context, "/cart"); + }, ), - onPressed: () { - Navigator.pushNamed(context, "/cart"); - }, ); } diff --git a/LabelStoreMax/lib/widgets/menu_item.dart b/LabelStoreMax/lib/widgets/menu_item.dart index d97b4ab..7c90ce6 100644 --- a/LabelStoreMax/lib/widgets/menu_item.dart +++ b/LabelStoreMax/lib/widgets/menu_item.dart @@ -24,7 +24,7 @@ Widget wsMenuItem(BuildContext context, children: [ leading, Text(" " + title, - style: Theme.of(context).primaryTextTheme.body1), + style: Theme.of(context).primaryTextTheme.bodyText2), ], ), ), diff --git a/LabelStoreMax/lib/widgets/woosignal_ui.dart b/LabelStoreMax/lib/widgets/woosignal_ui.dart index ae86b89..1fd2913 100644 --- a/LabelStoreMax/lib/widgets/woosignal_ui.dart +++ b/LabelStoreMax/lib/widgets/woosignal_ui.dart @@ -28,7 +28,7 @@ Widget wsRow2Text(BuildContext context, {String text1, String text2}) { children: [ Flexible( child: Container( - child: Text(text1, style: Theme.of(context).textTheme.title), + child: Text(text1, style: Theme.of(context).textTheme.headline6), ), flex: 3, ), @@ -37,7 +37,7 @@ Widget wsRow2Text(BuildContext context, {String text1, String text2}) { child: Text(text2, style: Theme.of(context) .primaryTextTheme - .body2 + .bodyText1 .copyWith(fontSize: 16, color: Colors.black87)), ), flex: 3, @@ -50,7 +50,7 @@ Widget wsNoResults(BuildContext context) { return Column( children: [ Text(trans(context, "No results"), - style: Theme.of(context).primaryTextTheme.body1), + style: Theme.of(context).primaryTextTheme.bodyText2), ], ); } @@ -70,7 +70,10 @@ Widget wsCheckoutRow(BuildContext context, children: [ Padding( child: Text(heading, - style: Theme.of(context).primaryTextTheme.body1), + style: Theme.of(context) + .primaryTextTheme + .bodyText2 + .copyWith(fontSize: 16)), padding: EdgeInsets.only(bottom: 8), ), Flexible( @@ -87,8 +90,9 @@ Widget wsCheckoutRow(BuildContext context, Flexible( child: Container( child: Text(leadTitle, - style: - Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context) + .primaryTextTheme + .subtitle1, maxLines: 2, overflow: TextOverflow.ellipsis, softWrap: false), @@ -131,15 +135,15 @@ Widget wsTextEditingRow(BuildContext context, children: [ Flexible( child: Padding( - child: - Text(heading, style: Theme.of(context).primaryTextTheme.body2), + child: Text(heading, + style: Theme.of(context).primaryTextTheme.bodyText1), padding: EdgeInsets.only(bottom: 2), ), ), Flexible( child: TextField( controller: controller, - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, keyboardType: keyboardType ?? TextInputType.text, autocorrect: false, autofocus: shouldAutoFocus ?? false, @@ -160,13 +164,15 @@ Widget widgetCheckoutMeta(BuildContext context, {String title, String amount}) { children: [ Flexible( child: Container( - child: Text(title, style: Theme.of(context).primaryTextTheme.body1), + child: + Text(title, style: Theme.of(context).primaryTextTheme.bodyText2), ), flex: 3, ), Flexible( child: Container( - child: Text(amount, style: Theme.of(context).primaryTextTheme.body2), + child: + Text(amount, style: Theme.of(context).primaryTextTheme.bodyText1), ), flex: 3, ) @@ -188,51 +194,68 @@ List wsBoxShadow({double blurRadius}) { ]; } -Widget wsCardProductItem(BuildContext context, {int index, Product product}) { +Widget wsCardProductItem(BuildContext context, + {int index, Product product, onTap}) { return InkWell( child: Container( - padding: EdgeInsets.all(10), - margin: EdgeInsets.all(5), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(5), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Flexible( - child: CachedNetworkImage( - imageUrl: (product.images.length > 0 - ? product.images.first.src - : ""), - placeholder: (context, url) => - new CircularProgressIndicator(), - errorWidget: (context, url, error) => new Icon(Icons.error), - fit: BoxFit.fitWidth), - flex: 4, + padding: EdgeInsets.all(10), + margin: EdgeInsets.all(5), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(5), + boxShadow: wsBoxShadow(blurRadius: 4), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Flexible( + child: CachedNetworkImage( + imageUrl: + (product.images.length > 0 ? product.images.first.src : ""), + placeholder: (context, url) => new CircularProgressIndicator(), + errorWidget: (context, url, error) => new Icon(Icons.error), + fit: BoxFit.contain), + flex: 4, + ), + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + formatStringCurrency(total: product.price), + style: Theme.of(context).textTheme.bodyText1, + textAlign: TextAlign.center, + ), + (product.onSale + ? Padding( + padding: const EdgeInsets.only(left: 8), + child: Text( + formatStringCurrency(total: product.regularPrice), + style: Theme.of(context).textTheme.bodyText1.copyWith( + decoration: TextDecoration.lineThrough, + color: Colors.grey), + textAlign: TextAlign.left, + ), + ) + : null), + ].where((t) => t != null).toList(), ), - Flexible( - child: Text( - formatStringCurrency(total: product.price), - style: Theme.of(context).textTheme.body2, - textAlign: TextAlign.left, - ), - flex: 1, + flex: 1, + ), + Expanded( + child: Text( + product.name, + style: Theme.of(context).textTheme.bodyText2, + overflow: TextOverflow.clip, + maxLines: 1, ), - Expanded( - child: Text( - product.name, - style: Theme.of(context).textTheme.body1, - overflow: TextOverflow.clip, - maxLines: 1, - ), - flex: 1, - ) - ], - )), - onTap: () { - Navigator.pushNamed(context, "/product-detail", arguments: product); - }, + flex: 1, + ) + ], + ), + ), + onTap: () => onTap(product), ); } @@ -245,27 +268,41 @@ void wsModalBottom(BuildContext context, return SafeArea( child: Container( height: double.infinity, - width: double.infinity - 10, + width: double.infinity, color: Colors.transparent, child: new Container( - padding: EdgeInsets.only(top: 25, left: 18, right: 18), + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: new BoxDecoration( color: Colors.white, borderRadius: new BorderRadius.only( - topLeft: const Radius.circular(10.0), - topRight: const Radius.circular(10.0)), + topLeft: const Radius.circular(10.0), + topRight: const Radius.circular(10.0), + ), ), child: Column( children: [ - Text(title, - style: Theme.of(context) - .primaryTextTheme - .display1 - .copyWith(fontSize: 20), - textAlign: TextAlign.left), - bodyWidget, - extraWidget ?? Container() - ], + Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Text(title, + style: Theme.of(context) + .primaryTextTheme + .headline4 + .copyWith(fontSize: 20), + textAlign: TextAlign.left), + ), + Expanded( + child: Container( + padding: + EdgeInsets.symmetric(horizontal: 16, vertical: 8), + width: double.infinity, + decoration: BoxDecoration( + boxShadow: wsBoxShadow(), + color: Colors.white, + borderRadius: BorderRadius.circular(8)), + child: bodyWidget), + ), + extraWidget ?? null + ].where((t) => t != null).toList(), )), ), ); @@ -431,13 +468,14 @@ Widget wsCardCartItem(BuildContext context, children: [ Text( cartLineItem.name, - style: Theme.of(context).primaryTextTheme.subhead, + style: Theme.of(context).primaryTextTheme.subtitle1, overflow: TextOverflow.ellipsis, maxLines: 3, ), (cartLineItem.variationOptions != null ? Text(cartLineItem.variationOptions, - style: Theme.of(context).primaryTextTheme.body2) + style: + Theme.of(context).primaryTextTheme.bodyText1) : Container()), Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -449,11 +487,14 @@ Widget wsCardCartItem(BuildContext context, : trans(context, "In Stock")), style: (cartLineItem.stockStatus == "outofstock" ? Theme.of(context).textTheme.caption - : Theme.of(context).primaryTextTheme.body1)), + : Theme.of(context) + .primaryTextTheme + .bodyText2)), Text( formatDoubleCurrency( total: double.parse(cartLineItem.total)), - style: Theme.of(context).primaryTextTheme.subhead, + style: + Theme.of(context).primaryTextTheme.subtitle1, textAlign: TextAlign.center) ], ), @@ -479,7 +520,7 @@ Widget wsCardCartItem(BuildContext context, highlightColor: Colors.transparent, ), Text(cartLineItem.quantity.toString(), - style: Theme.of(context).primaryTextTheme.title), + style: Theme.of(context).primaryTextTheme.headline6), IconButton( icon: Icon(Icons.remove_circle_outline), onPressed: actionDecrementQuantity, diff --git a/LabelStoreMax/pubspec.lock b/LabelStoreMax/pubspec.lock index 7b8a97c..0858f4e 100644 --- a/LabelStoreMax/pubspec.lock +++ b/LabelStoreMax/pubspec.lock @@ -7,35 +7,28 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.11" + version: "2.0.13" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "1.5.2" + version: "1.6.0" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.0" + version: "2.4.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" - braintree_payment: - dependency: "direct main" - description: - name: braintree_payment - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.4" + version: "2.0.0" bubble_tab_indicator: dependency: "direct main" description: @@ -56,7 +49,7 @@ packages: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" clock: dependency: transitive description: @@ -70,7 +63,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.11" + version: "1.14.12" convert: dependency: transitive description: @@ -84,7 +77,7 @@ packages: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4" csslib: dependency: transitive description: @@ -237,7 +230,7 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.12" intl: dependency: "direct main" description: @@ -350,13 +343,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.2" + pull_to_refresh: + dependency: "direct main" + description: + name: pull_to_refresh + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.8" quiver: dependency: transitive description: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.1.3" rxdart: dependency: transitive description: @@ -403,7 +403,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.5.5" + version: "1.7.0" sqflite: dependency: transitive description: @@ -466,7 +466,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.11" + version: "0.2.15" transformer_page_view: dependency: transitive description: @@ -529,7 +529,7 @@ packages: name: woosignal url: "https://pub.dartlang.org" source: hosted - version: "1.0.6" + version: "1.0.8" woosignal_stripe: dependency: "direct main" description: @@ -550,7 +550,7 @@ packages: name: xml url: "https://pub.dartlang.org" source: hosted - version: "3.5.0" + version: "3.6.1" yaml: dependency: transitive description: diff --git a/LabelStoreMax/pubspec.yaml b/LabelStoreMax/pubspec.yaml index 339bff9..48942e7 100644 --- a/LabelStoreMax/pubspec.yaml +++ b/LabelStoreMax/pubspec.yaml @@ -1,5 +1,5 @@ # Label StoreMax -# Version 2.0.0 +# Version 2.0.2 #authors: - "Anthony Gordon" #documentation: https://woosignal.com/docs/app/ios/label-storemax #homepage: https://woosignal.com/ @@ -23,7 +23,7 @@ environment: sdk: ">=2.1.0 <3.0.0" dependencies: - woosignal: ^1.0.6 + woosignal: ^1.0.8 woosignal_stripe: ^0.0.4 wp_json_api: ^0.1.2 shared_preferences: ^0.5.6+3 @@ -34,6 +34,7 @@ dependencies: flutter_money_formatter: ^0.8.3 platform_alert_dialog: ^1.0.0+2 flutter_web_browser: ^0.11.0 + pull_to_refresh: ^1.5.8 dio: ^3.0.9 intl: ^0.16.1 flutter_swiper: ^1.1.6 @@ -44,7 +45,6 @@ dependencies: flutter_spinkit: ^4.1.2+1 flutter_launcher_icons: ^0.7.4 html: ^0.14.0+3 - braintree_payment: ^1.2.4 flutter: sdk: flutter @@ -75,7 +75,7 @@ flutter: - assets/images/credit_cards.png - assets/images/shipping_icon.png - assets/images/dark_powered_by_stripe.png - - assets/images/cart_empty.png + - assets/images/cash_on_delivery.jpeg - lang/en.json fonts: