Flutter 1.17.0 support, Sort by feature, Cash on delivery added, Login/register flow change for Apple user guidelines, Bug fixes, Pubspec.yaml update, AndroidManifest.xml bug fix

This commit is contained in:
WooSignal 2020-05-08 15:35:30 +01:00
parent 54e215507f
commit 8cd7118b0b
48 changed files with 1131 additions and 676 deletions

View File

@ -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 * AndroidManifest.xml bug fix
## [2.0.1] - 2020-04-30 ## [2.0.1] - 2020-04-30

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -264,9 +264,6 @@
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${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", "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework",
"${PODS_ROOT}/../Flutter/Flutter.framework", "${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/Stripe/Stripe.framework", "${BUILT_PRODUCTS_DIR}/Stripe/Stripe.framework",
@ -275,6 +272,8 @@
"${BUILT_PRODUCTS_DIR}/flutter_web_browser/flutter_web_browser.framework", "${BUILT_PRODUCTS_DIR}/flutter_web_browser/flutter_web_browser.framework",
"${BUILT_PRODUCTS_DIR}/package_info/package_info.framework", "${BUILT_PRODUCTS_DIR}/package_info/package_info.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.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}/shared_preferences/shared_preferences.framework",
"${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework",
"${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
@ -282,9 +281,6 @@
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( 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}/FMDB.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stripe.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}/flutter_web_browser.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.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}/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}/shared_preferences.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",

View File

@ -1,6 +1,5 @@
import UIKit import UIKit
import Flutter import Flutter
import Braintree
@UIApplicationMain @UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {

View File

@ -129,5 +129,18 @@
"Shipping Details": "Shipping Details", "Shipping Details": "Shipping Details",
"State": "State", "State": "State",
"Country": "Country", "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"
} }

View File

@ -10,6 +10,7 @@
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/models/payment_type.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'; import 'package:label_storemax/providers/stripe_pay.dart';
// Payment methods available for uses in the app // Payment methods available for uses in the app
@ -25,11 +26,21 @@ List<PaymentType> arrPaymentMethods = [
), ),
), ),
addPayment(
PaymentType(
id: 2,
name: "CashOnDelivery",
desc: "Cash on delivery",
assetImage: "cash_on_delivery.jpeg",
pay: cashOnDeliveryPay,
),
),
// e.g. add more here // e.g. add more here
// addPayment( // addPayment(
// PaymentType( // PaymentType(
// id: 2, // id: 3,
// name: "MyNewPaymentMethod", // name: "MyNewPaymentMethod",
// desc: "Debit or Credit Card", // desc: "Debit or Credit Card",
// assetImage: "add icon image to assets/images/myimage.png", // assetImage: "add icon image to assets/images/myimage.png",

View File

@ -50,8 +50,10 @@ class _AppLocalizationsDelegate
const _AppLocalizationsDelegate(); const _AppLocalizationsDelegate();
@override @override
bool isSupported(Locale locale) => bool isSupported(Locale locale) => app_locales_supported
app_locales_supported.contains(locale.languageCode); .map((e) => e.languageCode)
.toList()
.contains(locale.languageCode);
@override @override
bool shouldReload(_AppLocalizationsDelegate old) => false; bool shouldReload(_AppLocalizationsDelegate old) => false;

View File

@ -82,9 +82,9 @@ TextTheme textThemePrimary() {
fontWeight: FontWeight.w600), fontWeight: FontWeight.w600),
headline: new TextStyle(color: Colors.black, fontFamily: appFontFamily), headline: new TextStyle(color: Colors.black, fontFamily: appFontFamily),
title: new TextStyle( title: new TextStyle(
color: Colors.black, color: Colors.black87,
fontFamily: appFontFamily, fontFamily: appFontFamily,
), fontWeight: FontWeight.w600),
subhead: new TextStyle( subhead: new TextStyle(
color: Colors.black, color: Colors.black,
fontFamily: appFontFamily, fontFamily: appFontFamily,

View File

@ -19,7 +19,7 @@ import 'package:label_storemax/models/checkout_session.dart';
import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
Future<OrderWC> buildOrderWC({TaxRate taxRate}) async { Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
OrderWC orderWC = OrderWC(); OrderWC orderWC = OrderWC();
String paymentMethodName = CheckoutSession.getInstance.paymentType.name ?? ""; String paymentMethodName = CheckoutSession.getInstance.paymentType.name ?? "";
@ -30,7 +30,7 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate}) async {
orderWC.paymentMethodTitle = paymentMethodName.toLowerCase(); orderWC.paymentMethodTitle = paymentMethodName.toLowerCase();
orderWC.setPaid = true; orderWC.setPaid = markPaid;
orderWC.status = "pending"; orderWC.status = "pending";
orderWC.currency = app_currency_iso.toUpperCase(); orderWC.currency = app_currency_iso.toUpperCase();
orderWC.customerId = orderWC.customerId =

View File

@ -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,
}

View File

@ -38,5 +38,5 @@ authLogout(BuildContext context) async {
await sharedPref.save(keyAuthCheck, null); await sharedPref.save(keyAuthCheck, null);
destroyUserId(context); destroyUserId(context);
Cart.getInstance.clear(); Cart.getInstance.clear();
navigatorPush(context, routeName: "/account-landing", forgetAll: true); navigatorPush(context, routeName: "/home", forgetAll: true);
} }

View File

@ -8,6 +8,7 @@
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:label_storemax/app_payment_methods.dart'; import 'package:label_storemax/app_payment_methods.dart';
import 'package:label_storemax/helpers/app_localizations.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:html/parser.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart'; import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:flutter_money_formatter/flutter_money_formatter.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:math_expressions/math_expressions.dart';
import 'package:platform_alert_dialog/platform_alert_dialog.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:status_alert/status_alert.dart';
import 'package:woosignal/models/response/products.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/woosignal.dart'; import 'package:woosignal/woosignal.dart';
@ -65,11 +69,6 @@ showStatusAlert(context,
); );
} }
class PaymentMethodType {
static final int STRIPE = 1;
static final int APPLEPAY = 2;
}
class EdgeAlertStyle { class EdgeAlertStyle {
static final int SUCCESS = 1; static final int SUCCESS = 1;
static final int WARNING = 2; static final int WARNING = 2;
@ -142,7 +141,7 @@ String formatStringCurrency({@required String total}) {
if (total == null || total == "") { if (total == null || total == "") {
tmpVal = 0; tmpVal = 0;
} else { } else {
tmpVal = double.parse(total); tmpVal = parseWcPrice(total);
} }
FlutterMoneyFormatter fmf = FlutterMoneyFormatter( FlutterMoneyFormatter fmf = FlutterMoneyFormatter(
amount: tmpVal, amount: tmpVal,
@ -185,6 +184,9 @@ checkout(
} }
double strCal({@required String sum}) { double strCal({@required String sum}) {
if (sum == null || sum == "") {
return 0;
}
Parser p = Parser(); Parser p = Parser();
Expression exp = p.parse(sum); Expression exp = p.parse(sum);
ContextModel cm = ContextModel(); ContextModel cm = ContextModel();
@ -192,6 +194,9 @@ double strCal({@required String sum}) {
} }
Future<double> workoutShippingCostWC({@required String sum}) async { Future<double> workoutShippingCostWC({@required String sum}) async {
if (sum == null || sum == "") {
return 0;
}
List<CartLineItem> cartLineItem = await Cart.getInstance.getCart(); List<CartLineItem> cartLineItem = await Cart.getInstance.getCart();
sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) { sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) {
return cartLineItem return cartLineItem
@ -263,6 +268,9 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
Future<double> workoutShippingClassCostWC( Future<double> workoutShippingClassCostWC(
{@required String sum, List<CartLineItem> cartLineItem}) async { {@required String sum, List<CartLineItem> cartLineItem}) async {
if (sum == null || sum == "") {
return 0;
}
sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) { sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) {
return cartLineItem return cartLineItem
.map((f) => f.quantity) .map((f) => f.quantity)
@ -357,14 +365,22 @@ bool validPassword(String pw) {
} }
navigatorPush(BuildContext context, navigatorPush(BuildContext context,
{@required String routeName, Object arguments, bool forgetAll = false}) { {@required String routeName,
Object arguments,
bool forgetAll = false,
int forgetLast}) {
if (forgetAll) { if (forgetAll) {
Navigator.of(context).pushNamedAndRemoveUntil( Navigator.of(context).pushNamedAndRemoveUntil(
routeName, (Route<dynamic> route) => false, routeName, (Route<dynamic> route) => false,
arguments: arguments ?? null); 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, PlatformDialogAction dialogAction(BuildContext context,
@ -450,3 +466,58 @@ String formatForDateTime(FormatType formatType) {
} }
String capitalize(String s) => s[0].toUpperCase() + s.substring(1); 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<Product> 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";
}

View File

@ -10,11 +10,13 @@
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'dart:ui';
/* /*
Developer Notes Developer Notes
SUPPORT EMAIL - support@woosignal.com SUPPORT EMAIL - support@woosignal.com
VERSION - 2.0.1 VERSION - 2.0.2
https://woosignal.com https://woosignal.com
*/ */
@ -22,15 +24,51 @@
const app_name = "MyApp"; const app_name = "MyApp";
const app_key = "your app key"; const app_key =
"Your app key from WooSingal";
// Your App key from WooSignal // Your App key from WooSignal
// link: https://woosignal.com/dashboard/apps // 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_terms_url = "https://yourdomain.com/terms";
const app_privacy_url = "https://yourdomain.com/privacy"; const app_privacy_url = "https://yourdomain.com/privacy";
/*<! ------ APP SETTINGS ------!>*/
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
/*<! ------ PAYMENT GATEWAYS ------!>*/
// Available: "Stripe", "CashOnDelivery",
// Add the method to the array below e.g. ["Stripe", "CashOnDelivery"]
const app_payment_methods = ["Stripe"];
/*<! ------ STRIPE (OPTIONAL) ------!>*/
// 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
/*<! ------ WP LOGIN (OPTIONAL) ------!>*/ /*<! ------ WP LOGIN (OPTIONAL) ------!>*/
// Allows customers to login/register, view account, purchase items as a user. // 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 use_wp_login = false;
const app_base_url = "https://mysite.com"; // change to your url 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 const app_wp_api_path = "/wp-json"; // By default "/wp-json" should work
/*<! ------ STRIPE (OPTIONAL) ------!>*/
// 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
/*<! ------ APP CURRENCY ------!>*/
const app_currency_symbol = "\£";
const app_currency_iso = "gbp";
const app_locales_supported = ['en'];
const app_payment_methods = ["Stripe"];
/*<! ------ DEBUGGER ENABLED ------!>*/ /*<! ------ DEBUGGER ENABLED ------!>*/

View File

@ -10,7 +10,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.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_billing_details.dart';
import 'package:label_storemax/pages/account_detail.dart'; import 'package:label_storemax/pages/account_detail.dart';
import 'package:label_storemax/pages/account_landing.dart'; import 'package:label_storemax/pages/account_landing.dart';
@ -51,13 +50,12 @@ void main() async {
DeviceOrientation.portraitUp, DeviceOrientation.portraitUp,
]); ]);
String initialRoute = (use_wp_login) ? "/account-landing" : "/home"; String initialRoute = "/home";
if (use_wp_login == true) {
WPJsonAPI.instance.initWith( WPJsonAPI.instance.initWith(
baseUrl: app_base_url, baseUrl: app_base_url,
shouldDebug: app_debug, shouldDebug: app_debug,
wpJsonPath: app_wp_api_path); wpJsonPath: app_wp_api_path);
if (await authCheck() == true) {
initialRoute = "/home";
} }
runApp( runApp(
@ -71,7 +69,6 @@ void main() async {
'/cart': (BuildContext context) => new CartPage(), '/cart': (BuildContext context) => new CartPage(),
'/error': (BuildContext context) => new ErrorPage(), '/error': (BuildContext context) => new ErrorPage(),
'/checkout': (BuildContext context) => new CheckoutConfirmationPage(), '/checkout': (BuildContext context) => new CheckoutConfirmationPage(),
'/account-landing': (BuildContext context) => new AccountLandingPage(),
'/account-register': (BuildContext context) => '/account-register': (BuildContext context) =>
new AccountRegistrationPage(), new AccountRegistrationPage(),
'/account-detail': (BuildContext context) => new AccountDetailPage(), '/account-detail': (BuildContext context) => new AccountDetailPage(),
@ -84,6 +81,12 @@ void main() async {
}, },
onGenerateRoute: (settings) { onGenerateRoute: (settings) {
switch (settings.name) { switch (settings.name) {
case '/account-landing':
return PageTransition(
child: AccountLandingPage(),
type: PageTransitionType.downToUp,
);
case '/browse-category': case '/browse-category':
if (settings.arguments != null) { if (settings.arguments != null) {
final ProductCategory category = final ProductCategory category =
@ -200,9 +203,7 @@ void main() async {
return null; return null;
} }
}, },
supportedLocales: [ supportedLocales: app_locales_supported,
Locale('en'),
],
localizationsDelegates: [ localizationsDelegates: [
AppLocalizations.delegate, AppLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,

View File

@ -142,7 +142,7 @@ class Cart {
if (taxableCartLines.length > 0) { if (taxableCartLines.length > 0) {
cartSubtotal = taxableCartLines cartSubtotal = taxableCartLines
.map<double>((m) => double.parse(m.subtotal)) .map<double>((m) => parseWcPrice(m.subtotal))
.reduce((a, b) => a + b); .reduce((a, b) => a + b);
} }
@ -155,13 +155,19 @@ class Cart {
case "flat_rate": case "flat_rate":
FlatRate flatRate = (shippingType.object as FlatRate); FlatRate flatRate = (shippingType.object as FlatRate);
if (flatRate.taxable != null && flatRate.taxable) { if (flatRate.taxable != null && flatRate.taxable) {
shippingTotal += double.parse(shippingType.cost); shippingTotal += parseWcPrice(
shippingType.cost == null || shippingType.cost == ""
? "0"
: shippingType.cost);
} }
break; break;
case "local_pickup": case "local_pickup":
LocalPickup localPickup = (shippingType.object as LocalPickup); LocalPickup localPickup = (shippingType.object as LocalPickup);
if (localPickup.taxable != null && localPickup.taxable) { if (localPickup.taxable != null && localPickup.taxable) {
shippingTotal += double.parse(localPickup.cost); shippingTotal += parseWcPrice(
(localPickup.cost == null || localPickup.cost == ""
? "0"
: localPickup.cost));
} }
break; break;
default: default:
@ -171,10 +177,10 @@ class Cart {
double total = 0; double total = 0;
if (subtotal != 0) { if (subtotal != 0) {
total += ((double.parse(taxRate.rate) * subtotal) / 100); total += ((parseWcPrice(taxRate.rate) * subtotal) / 100);
} }
if (shippingTotal != 0) { if (shippingTotal != 0) {
total += ((double.parse(taxRate.rate) * shippingTotal) / 100); total += ((parseWcPrice(taxRate.rate) * shippingTotal) / 100);
} }
return (total).toStringAsFixed(2); return (total).toStringAsFixed(2);
} }

View File

@ -8,6 +8,8 @@
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:label_storemax/helpers/tools.dart';
class CartLineItem { class CartLineItem {
String name; String name;
int productId; int productId;
@ -45,7 +47,7 @@ class CartLineItem {
this.metaData}); this.metaData});
String getCartTotal() { String getCartTotal() {
return (quantity * double.parse(subtotal)).toString(); return (quantity * parseWcPrice(subtotal)).toString();
} }
CartLineItem.fromJson(Map<String, dynamic> json) CartLineItem.fromJson(Map<String, dynamic> json)
@ -56,7 +58,10 @@ class CartLineItem {
shippingClassId = json['shipping_class_id'].toString(), shippingClassId = json['shipping_class_id'].toString(),
taxStatus = json['tax_status'], taxStatus = json['tax_status'],
stockQuantity = json['stock_quantity'], 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'], shippingIsTaxable = json['shipping_is_taxable'],
subtotal = json['subtotal'], subtotal = json['subtotal'],
total = json['total'], total = json['total'],

View File

@ -61,18 +61,18 @@ class CheckoutSession {
} }
Future<String> total({bool withFormat, TaxRate taxRate}) async { Future<String> total({bool withFormat, TaxRate taxRate}) async {
double totalCart = double.parse(await Cart.getInstance.getTotal()); double totalCart = parseWcPrice(await Cart.getInstance.getTotal());
double totalShipping = 0; double totalShipping = 0;
if (shippingType != null && shippingType.object != null) { if (shippingType != null && shippingType.object != null) {
switch (shippingType.methodId) { switch (shippingType.methodId) {
case "flat_rate": case "flat_rate":
totalShipping = double.parse(shippingType.cost); totalShipping = parseWcPrice(shippingType.cost);
break; break;
case "free_shipping": case "free_shipping":
totalShipping = double.parse(shippingType.cost); totalShipping = parseWcPrice(shippingType.cost);
break; break;
case "local_pickup": case "local_pickup":
totalShipping = double.parse(shippingType.cost); totalShipping = parseWcPrice(shippingType.cost);
break; break;
default: default:
break; break;
@ -83,12 +83,12 @@ class CheckoutSession {
if (taxRate != null) { if (taxRate != null) {
String taxAmount = await Cart.getInstance.taxAmount(taxRate); String taxAmount = await Cart.getInstance.taxAmount(taxRate);
total += double.parse(taxAmount); total += parseWcPrice(taxAmount);
} }
if (withFormat != null && withFormat == true) { if (withFormat != null && withFormat == true) {
return formatDoubleCurrency(total: total); return formatDoubleCurrency(total: total);
} }
return total.toString(); return total.toStringAsFixed(2);
} }
} }

View File

@ -42,7 +42,7 @@ class _AboutPageState extends State<AboutPage> {
}, },
), ),
title: Text(trans(context, "About"), title: Text(trans(context, "About"),
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.headline6),
centerTitle: true, centerTitle: true,
), ),
body: SafeArea( body: SafeArea(
@ -85,8 +85,9 @@ class _AboutPageState extends State<AboutPage> {
trans(context, "Version") + trans(context, "Version") +
": " + ": " +
snapshot.data.version, snapshot.data.version,
style: style: Theme.of(context)
Theme.of(context).primaryTextTheme.body2), .primaryTextTheme
.bodyText1),
padding: EdgeInsets.only(top: 15, bottom: 15), padding: EdgeInsets.only(top: 15, bottom: 15),
); );
} }

View File

@ -89,7 +89,7 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
title: Text( title: Text(
trans(context, "Billing Details"), trans(context, "Billing Details"),
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
), ),
centerTitle: true, centerTitle: true,
), ),

View File

@ -85,7 +85,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
), ),
title: Text( title: Text(
trans(context, "Account"), trans(context, "Account"),
style: Theme.of(context).primaryTextTheme.title, style: Theme.of(context).primaryTextTheme.headline6,
), ),
centerTitle: true, centerTitle: true,
), ),
@ -212,7 +212,12 @@ class _AccountDetailPageState extends State<AccountDetailPage>
leading: Icon(Icons.account_circle), leading: Icon(Icons.account_circle),
title: Text(trans(context, "Update details")), title: Text(trans(context, "Update details")),
onTap: () { 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<AccountDetailPage>
child: ListTile( child: ListTile(
leading: Icon(Icons.exit_to_app), leading: Icon(Icons.exit_to_app),
title: Text(trans(context, "Logout")), title: Text(trans(context, "Logout")),
onTap: () { onTap: () => authLogout(context),
authLogout(context);
},
), ),
), ),
], ],
@ -331,7 +334,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
formatStringCurrency(total: _orders[i].total), formatStringCurrency(total: _orders[i].total),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body1 .bodyText2
.copyWith( .copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.black), color: Colors.black),
@ -343,7 +346,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
trans(context, "items"), trans(context, "items"),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body2 .bodyText1
.copyWith( .copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.black), color: Colors.black),
@ -364,7 +367,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body2 .bodyText1
.copyWith( .copyWith(
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.black), color: Colors.black),

View File

@ -68,7 +68,7 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.display1 .headline4
.copyWith( .copyWith(
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@ -119,7 +119,7 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
Padding( Padding(
child: Text( child: Text(
trans(context, "Create an account"), trans(context, "Create an account"),
style: Theme.of(context).primaryTextTheme.body2, style: Theme.of(context).primaryTextTheme.bodyText1,
), ),
padding: EdgeInsets.only(left: 8), padding: EdgeInsets.only(left: 8),
) )
@ -133,6 +133,10 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
action: () { action: () {
launch(app_forgot_password_url); launch(app_forgot_password_url);
}), }),
Divider(),
wsLinkButton(context, title: trans(context, "Back"), action: () {
Navigator.pop(context);
}),
], ],
), ),
), ),
@ -157,7 +161,13 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
authUser(token); authUser(token);
storeUserId(wpUserLoginResponse.data.userId.toString()); 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 { } else {
showEdgeAlertWith(context, showEdgeAlertWith(context,
title: trans(context, "Oops!"), title: trans(context, "Oops!"),

View File

@ -55,7 +55,7 @@ class _AccountOrderDetailPageState extends State<AccountOrderDetailPage> {
), ),
title: Text( title: Text(
"Order #" + _orderId.toString(), "Order #" + _orderId.toString(),
style: Theme.of(context).primaryTextTheme.title, style: Theme.of(context).primaryTextTheme.headline6,
), ),
centerTitle: true, centerTitle: true,
), ),
@ -157,7 +157,7 @@ class _AccountOrderDetailPageState extends State<AccountOrderDetailPage> {
total: _order.lineItems[i].total), total: _order.lineItems[i].total),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body1 .bodyText2
.copyWith( .copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.black), color: Colors.black),
@ -169,7 +169,7 @@ class _AccountOrderDetailPageState extends State<AccountOrderDetailPage> {
.toString(), .toString(),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body2 .bodyText1
.copyWith( .copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.black), color: Colors.black),

View File

@ -16,7 +16,6 @@ import 'package:label_storemax/labelconfig.dart';
import 'package:label_storemax/widgets/buttons.dart'; import 'package:label_storemax/widgets/buttons.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
import 'package:woosignal/helpers/shared_pref.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/models/responses/WPUserRegisterResponse.dart';
import 'package:wp_json_api/wp_json_api.dart'; import 'package:wp_json_api/wp_json_api.dart';
@ -61,7 +60,7 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
), ),
title: Text( title: Text(
"Register", "Register",
style: Theme.of(context).primaryTextTheme.title, style: Theme.of(context).primaryTextTheme.headline6,
), ),
centerTitle: true, centerTitle: true,
), ),
@ -173,19 +172,25 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
WPUserRegisterResponse wpUserRegisterResponse = await WPJsonAPI.instance WPUserRegisterResponse wpUserRegisterResponse = await WPJsonAPI.instance
.api((request) => request.wpRegister( .api((request) => request.wpRegister(
email: email, password: password, username: username)); email: email.toLowerCase(),
password: password,
username: username));
if (wpUserRegisterResponse != null) { if (wpUserRegisterResponse != null) {
String token = wpUserRegisterResponse.data.userToken; String token = wpUserRegisterResponse.data.userToken;
authUser(token); authUser(token);
storeUserId(wpUserRegisterResponse.data.userId.toString()); storeUserId(wpUserRegisterResponse.data.userId.toString());
WPUserInfoUpdatedResponse wpUserInfoUpdatedResponse = await WPJsonAPI await WPJsonAPI.instance.api((request) => request
.instance .wpUpdateUserInfo(token, firstName: firstName, lastName: lastName));
.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 { } else {
setState(() { setState(() {
showEdgeAlertWith(context, showEdgeAlertWith(context,

View File

@ -90,7 +90,7 @@ class _AccountShippingDetailsPageState
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
title: Text( title: Text(
trans(context, "Shipping Details"), trans(context, "Shipping Details"),
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
), ),
centerTitle: true, centerTitle: true,
), ),

View File

@ -8,9 +8,13 @@
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/helpers/tools.dart';
import 'package:label_storemax/widgets/app_loader.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/product_category.dart';
import 'package:woosignal/models/response/products.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS;
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
@ -29,8 +33,9 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
_BrowseCategoryPageState(this._selectedCategory); _BrowseCategoryPageState(this._selectedCategory);
List<WS.Product> _products = []; List<WS.Product> _products = [];
var _productsController = ScrollController();
RefreshController _refreshController =
RefreshController(initialRefresh: false);
ProductCategory _selectedCategory; ProductCategory _selectedCategory;
bool _isLoading; bool _isLoading;
int _page; int _page;
@ -46,34 +51,17 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
_page = 1; _page = 1;
_shouldStopRequests = false; _shouldStopRequests = false;
waitForNextRequest = 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 { _fetchMoreProducts() async {
waitForNextRequest = true; waitForNextRequest = true;
List<WS.Product> products = await appWooSignal((api) { List<WS.Product> products = await appWooSignal((api) => api.getProducts(
return api.getProducts(perPage: 50, page: _page, status: "publish"); perPage: 50,
}); category: _selectedCategory.id.toString(),
page: _page,
status: "publish",
stockStatus: "instock"));
_products.addAll(products); _products.addAll(products);
waitForNextRequest = false; waitForNextRequest = false;
_page = _page + 1; _page = _page + 1;
@ -82,13 +70,6 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
if (products.length == 0) { if (products.length == 0) {
_shouldStopRequests = true; _shouldStopRequests = true;
} }
}
_fetchProductsForCategory() async {
_products = await appWooSignal((api) {
return api.getProducts(
category: _selectedCategory.id.toString(), perPage: 50);
});
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
@ -109,12 +90,18 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text(trans(context, "Browse"), Text(trans(context, "Browse"),
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
Text(_selectedCategory.name, Text(_selectedCategory.name,
style: Theme.of(context).primaryTextTheme.title) style: Theme.of(context).primaryTextTheme.headline6)
], ],
), ),
centerTitle: true, centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.tune),
onPressed: _modalSheetTune,
)
],
), ),
body: SafeArea( body: SafeArea(
minimum: safeAreaDefault(), minimum: safeAreaDefault(),
@ -122,25 +109,105 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
? Center( ? Center(
child: showAppLoader(), child: showAppLoader(),
) )
: Column( : refreshableScroll(context,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, refreshController: _refreshController,
crossAxisAlignment: CrossAxisAlignment.start, onRefresh: _onRefresh,
children: <Widget>[ onLoading: _onLoading,
Expanded( products: _products,
child: (_products.length != null && _products.length > 0 onTap: _showProduct),
? GridView.count(
crossAxisCount: 2,
controller: _productsController,
children: List.generate(_products.length, (index) {
return wsCardProductItem(context,
index: index, product: _products[index]);
}))
: wsNoResults(context)),
flex: 1,
),
],
),
), ),
); );
} }
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: <Widget>[
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);
}
} }

View File

@ -11,8 +11,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/widgets/app_loader.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:woosignal/models/response/products.dart' as WS;
import 'package:label_storemax/widgets/woosignal_ui.dart';
class BrowseSearchPage extends StatefulWidget { class BrowseSearchPage extends StatefulWidget {
final String search; final String search;
@ -25,7 +25,8 @@ class BrowseSearchPage extends StatefulWidget {
class _BrowseSearchState extends State<BrowseSearchPage> { class _BrowseSearchState extends State<BrowseSearchPage> {
_BrowseSearchState(this._search); _BrowseSearchState(this._search);
var _productsController = ScrollController(); RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<WS.Product> _products = []; List<WS.Product> _products = [];
String _search; String _search;
bool _isLoading; bool _isLoading;
@ -42,39 +43,26 @@ class _BrowseSearchState extends State<BrowseSearchPage> {
_shouldStopRequests = false; _shouldStopRequests = false;
waitForNextRequest = false; waitForNextRequest = false;
_fetchProductsForSearch(_page); _fetchProductsForSearch();
_addScrollListener();
} }
_addScrollListener() async { _fetchProductsForSearch() 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 {
waitForNextRequest = true; waitForNextRequest = true;
List<WS.Product> products = await appWooSignal((api) { List<WS.Product> products = await appWooSignal((api) => api.getProducts(
perPage: 100,
search: _search,
page: _page,
status: "publish",
stockStatus: "instock"));
_products.addAll(products);
waitForNextRequest = false;
_page = _page + 1; _page = _page + 1;
return api.getProducts(
search: _search, perPage: 100, page: page, status: "publish"); waitForNextRequest = false;
});
if (products.length == 0) { if (products.length == 0) {
_shouldStopRequests = true; _shouldStopRequests = true;
} }
setState(() { setState(() {
_products.addAll(products.toList());
_isLoading = false; _isLoading = false;
}); });
} }
@ -94,9 +82,9 @@ class _BrowseSearchState extends State<BrowseSearchPage> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Text(trans(context, "Search results for"), Text(trans(context, "Search results for"),
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
Text("\"" + _search + "\"", Text("\"" + _search + "\"",
style: Theme.of(context).primaryTextTheme.title) style: Theme.of(context).primaryTextTheme.headline6)
], ],
), ),
centerTitle: true, centerTitle: true,
@ -107,29 +95,40 @@ class _BrowseSearchState extends State<BrowseSearchPage> {
? Center( ? Center(
child: showAppLoader(), child: showAppLoader(),
) )
: Column( : refreshableScroll(context,
mainAxisAlignment: MainAxisAlignment.spaceEvenly, refreshController: _refreshController,
crossAxisAlignment: CrossAxisAlignment.start, onRefresh: _onRefresh,
children: <Widget>[ onLoading: _onLoading,
Expanded( products: _products,
child: (_products.length != null && _products.length > 0 onTap: _showProduct),
? GridView.count(
crossAxisCount: 2,
controller: _productsController,
children: List.generate(
_products.length,
(index) {
return wsCardProductItem(context,
index: index, product: _products[index]);
},
),
)
: wsNoResults(context)),
flex: 1,
),
],
),
), ),
); );
} }
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);
}
} }

View File

@ -10,7 +10,9 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.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/helpers/tools.dart';
import 'package:label_storemax/labelconfig.dart';
import 'package:label_storemax/models/cart.dart'; import 'package:label_storemax/models/cart.dart';
import 'package:label_storemax/models/cart_line_item.dart'; import 'package:label_storemax/models/cart_line_item.dart';
import 'package:label_storemax/models/checkout_session.dart'; import 'package:label_storemax/models/checkout_session.dart';
@ -67,6 +69,9 @@ class _CartPageState extends State<CartPage> {
void _actionProceedToCheckout() async { void _actionProceedToCheckout() async {
List<CartLineItem> cartLineItems = await Cart.getInstance.getCart(); List<CartLineItem> cartLineItems = await Cart.getInstance.getCart();
if (_isLoading == true) {
return;
}
if (cartLineItems.length <= 0) { if (cartLineItems.length <= 0) {
showEdgeAlertWith(context, showEdgeAlertWith(context,
title: trans(context, "Cart"), title: trans(context, "Cart"),
@ -94,6 +99,11 @@ class _CartPageState extends State<CartPage> {
CheckoutSession.getInstance.billingDetails.shippingAddress = CheckoutSession.getInstance.billingDetails.shippingAddress =
sfCustomerAddress; sfCustomerAddress;
} }
if (use_wp_login == true && !(await authCheck())) {
UserAuth.instance.redirect = "/checkout";
Navigator.pushNamed(context, "/account-landing");
return;
}
Navigator.pushNamed(context, "/checkout"); Navigator.pushNamed(context, "/checkout");
} }
@ -131,6 +141,9 @@ class _CartPageState extends State<CartPage> {
desc: trans(context, "Item removed"), desc: trans(context, "Item removed"),
style: EdgeAlertStyle.WARNING, style: EdgeAlertStyle.WARNING,
icon: Icons.remove_shopping_cart); icon: Icons.remove_shopping_cart);
if (_cartLines.length == 0) {
_isCartEmpty = true;
}
setState(() {}); setState(() {});
} }
@ -142,6 +155,7 @@ class _CartPageState extends State<CartPage> {
desc: trans(context, "Cart cleared"), desc: trans(context, "Cart cleared"),
style: EdgeAlertStyle.SUCCESS, style: EdgeAlertStyle.SUCCESS,
icon: Icons.delete_outline); icon: Icons.delete_outline);
_isCartEmpty = true;
setState(() {}); setState(() {});
} }
@ -151,7 +165,7 @@ class _CartPageState extends State<CartPage> {
resizeToAvoidBottomPadding: false, resizeToAvoidBottomPadding: false,
appBar: AppBar( appBar: AppBar(
title: Text(trans(context, "Shopping Cart"), 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, textTheme: Theme.of(context).textTheme,
elevation: 1, elevation: 1,
actions: <Widget>[ actions: <Widget>[
@ -161,7 +175,7 @@ class _CartPageState extends State<CartPage> {
child: Align( child: Align(
child: Padding( child: Padding(
child: Text(trans(context, "Clear Cart"), child: Text(trans(context, "Clear Cart"),
style: Theme.of(context).primaryTextTheme.body2), style: Theme.of(context).primaryTextTheme.bodyText1),
padding: EdgeInsets.only(right: 8), padding: EdgeInsets.only(right: 8),
), ),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -191,7 +205,8 @@ class _CartPageState extends State<CartPage> {
), ),
Padding( Padding(
child: Text(trans(context, "Empty Basket"), child: Text(trans(context, "Empty Basket"),
style: Theme.of(context).primaryTextTheme.body1), style:
Theme.of(context).primaryTextTheme.bodyText2),
padding: EdgeInsets.only(top: 10), padding: EdgeInsets.only(top: 10),
) )
], ],

View File

@ -30,19 +30,18 @@ class CheckoutConfirmationPage extends StatefulWidget {
class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> { class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
CheckoutConfirmationPageState(); CheckoutConfirmationPageState();
GlobalKey<CheckoutConfirmationPageState> _key =
GlobalKey<CheckoutConfirmationPageState>();
bool _showFullLoader; bool _showFullLoader;
List<TaxRate> _taxRates; List<TaxRate> _taxRates;
TaxRate _taxRate; TaxRate _taxRate;
bool _isProcessingPayment;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_showFullLoader = true; _showFullLoader = true;
_isProcessingPayment = false;
if (CheckoutSession.getInstance.paymentType == null) { if (CheckoutSession.getInstance.paymentType == null) {
CheckoutSession.getInstance.paymentType = arrPaymentMethods.first; CheckoutSession.getInstance.paymentType = arrPaymentMethods.first;
} }
@ -50,8 +49,6 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_getTaxes(); _getTaxes();
} }
_fetchUserId() {}
void reloadState({bool showLoader}) { void reloadState({bool showLoader}) {
setState(() { setState(() {
_showFullLoader = showLoader ?? false; _showFullLoader = showLoader ?? false;
@ -135,7 +132,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
children: <Widget>[ children: <Widget>[
Center( Center(
child: Text(trans(context, "Checkout"), child: Text(trans(context, "Checkout"),
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
), ),
Expanded( Expanded(
child: Container( child: Container(
@ -239,8 +236,10 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
], ],
), ),
wsPrimaryButton(context, wsPrimaryButton(context,
title: trans(context, "CHECKOUT"), title: _isProcessingPayment
action: _handleCheckout), ? "PROCESSING..."
: trans(context, "CHECKOUT"),
action: _isProcessingPayment ? null : _handleCheckout),
], ],
) )
: Center( : Center(
@ -252,7 +251,7 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
padding: const EdgeInsets.only(top: 15), padding: const EdgeInsets.only(top: 15),
child: Text( child: Text(
trans(context, "One moment") + "...", trans(context, "One moment") + "...",
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
), ),
) )
], ],
@ -301,7 +300,21 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
return; return;
} }
if (_isProcessingPayment == true) {
return;
}
setState(() {
_isProcessingPayment = true;
});
CheckoutSession.getInstance.paymentType CheckoutSession.getInstance.paymentType
.pay(context, state: this, taxRate: _taxRate); .pay(context, state: this, taxRate: _taxRate);
Future.delayed(Duration(milliseconds: 5000), () {
setState(() {
_isProcessingPayment = false;
});
});
} }
} }

View File

@ -85,8 +85,7 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
_showSelectCountryModal() { _showSelectCountryModal() {
wsModalBottom(context, wsModalBottom(context,
title: trans(context, "Select a country"), title: trans(context, "Select a country"),
bodyWidget: Expanded( bodyWidget: ListView.separated(
child: ListView.separated(
itemCount: appCountryOptions.length, itemCount: appCountryOptions.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
Map<String, String> strName = appCountryOptions[index]; Map<String, String> strName = appCountryOptions[index];
@ -94,7 +93,7 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
return InkWell( return InkWell(
child: Container( child: Container(
child: Text(strName["name"], child: Text(strName["name"],
style: Theme.of(context).primaryTextTheme.body2), style: Theme.of(context).primaryTextTheme.bodyText1),
padding: EdgeInsets.only(top: 25, bottom: 25), padding: EdgeInsets.only(top: 25, bottom: 25),
), ),
splashColor: Colors.grey, splashColor: Colors.grey,
@ -113,7 +112,6 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
color: Colors.black12, color: Colors.black12,
); );
}, },
),
)); ));
} }
@ -125,7 +123,7 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
title: Text( title: Text(
trans(context, "Billing & Shipping Details"), trans(context, "Billing & Shipping Details"),
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.headline6,
), ),
centerTitle: true, centerTitle: true,
), ),
@ -241,7 +239,8 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
Text(trans(context, "Remember my details"), Text(trans(context, "Remember my details"),
style: Theme.of(context).primaryTextTheme.body2), style:
Theme.of(context).primaryTextTheme.bodyText2),
Checkbox( Checkbox(
value: valRememberDetails, value: valRememberDetails,
onChanged: (bool value) { onChanged: (bool value) {

View File

@ -43,7 +43,7 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
title: Text(trans(context, "Payment Method"), title: Text(trans(context, "Payment Method"),
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.headline6),
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
centerTitle: true, centerTitle: true,
), ),
@ -74,7 +74,7 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: ListView.builder( child: ListView.separated(
itemCount: getPaymentTypes().length, itemCount: getPaymentTypes().length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return ListTile( return ListTile(
@ -84,15 +84,15 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
image: AssetImage("assets/images/" + image: AssetImage("assets/images/" +
getPaymentTypes()[index].assetImage), getPaymentTypes()[index].assetImage),
width: 60, width: 60,
fit: BoxFit.fitHeight, fit: BoxFit.contain,
alignment: Alignment.center), alignment: Alignment.center),
title: Text(getPaymentTypes()[index].desc, title: Text(getPaymentTypes()[index].desc,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.subhead), .subtitle1),
selected: true, selected: true,
trailing: (CheckoutSession trailing:
.getInstance.paymentType == (CheckoutSession.getInstance.paymentType ==
getPaymentTypes()[index] getPaymentTypes()[index]
? Icon(Icons.check) ? Icon(Icons.check)
: null), : null),
@ -102,7 +102,13 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
Navigator.pop(context); Navigator.pop(context);
}, },
); );
}), },
separatorBuilder: (cxt, i) {
return Divider(
color: Colors.black12,
);
},
),
), ),
wsLinkButton(context, title: trans(context, "CANCEL"), wsLinkButton(context, title: trans(context, "CANCEL"),
action: () { action: () {

View File

@ -17,7 +17,6 @@ import 'package:label_storemax/models/customer_address.dart';
import 'package:label_storemax/models/shipping_type.dart'; import 'package:label_storemax/models/shipping_type.dart';
import 'package:label_storemax/widgets/app_loader.dart'; import 'package:label_storemax/widgets/app_loader.dart';
import 'package:label_storemax/widgets/buttons.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:woosignal/models/response/shipping_method.dart';
import 'package:label_storemax/app_country_options.dart'; import 'package:label_storemax/app_country_options.dart';
@ -49,9 +48,8 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
} }
_getShippingMethods() async { _getShippingMethods() async {
List<WSShipping> wsShipping = await appWooSignal((api) { List<WSShipping> wsShipping =
return api.getShippingMethods(); await appWooSignal((api) => api.getShippingMethods());
});
CustomerAddress customerAddress = CustomerAddress customerAddress =
CheckoutSession.getInstance.billingDetails.shippingAddress; CheckoutSession.getInstance.billingDetails.shippingAddress;
String postalCode = customerAddress.postalCode; String postalCode = customerAddress.postalCode;
@ -70,9 +68,12 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
} }
} }
if (_shipping != null) { if (_shipping != null && _shipping.methods != null) {
if (_shipping.methods.flatRate != null) { if (_shipping.methods.flatRate != null) {
_shipping.methods.flatRate.forEach((flatRate) { _shipping.methods.flatRate
.where((t) => t != null)
.toList()
.forEach((flatRate) {
Map<String, dynamic> tmpShippingOption = {}; Map<String, dynamic> tmpShippingOption = {};
tmpShippingOption = { tmpShippingOption = {
"id": flatRate.id, "id": flatRate.id,
@ -86,7 +87,10 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
} }
if (_shipping.methods.localPickup != null) { if (_shipping.methods.localPickup != null) {
_shipping.methods.localPickup.forEach((localPickup) { _shipping.methods.localPickup
.where((t) => t != null)
.toList()
.forEach((localPickup) {
Map<String, dynamic> tmpShippingOption = {}; Map<String, dynamic> tmpShippingOption = {};
tmpShippingOption = { tmpShippingOption = {
"id": localPickup.id, "id": localPickup.id,
@ -100,7 +104,10 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
} }
if (_shipping.methods.freeShipping != null) { if (_shipping.methods.freeShipping != null) {
_shipping.methods.freeShipping.forEach((freeShipping) { _shipping.methods.freeShipping
.where((t) => t != null)
.toList()
.forEach((freeShipping) {
if (isNumeric(freeShipping.cost)) { if (isNumeric(freeShipping.cost)) {
Map<String, dynamic> tmpShippingOption = {}; Map<String, dynamic> tmpShippingOption = {};
tmpShippingOption = { tmpShippingOption = {
@ -183,7 +190,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
context, context,
"Shipping Methods", "Shipping Methods",
), ),
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.headline6,
), ),
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
centerTitle: true, centerTitle: true,
@ -234,7 +241,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
['title'], ['title'],
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.subhead), .subtitle1),
selected: true, selected: true,
subtitle: FutureBuilder<String>( subtitle: FutureBuilder<String>(
future: _getShippingPrice(index), future: _getShippingPrice(index),
@ -299,7 +306,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
"Shipping is not supported for your country, sorry"), "Shipping is not supported for your country, sorry"),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.title, .headline6,
textAlign: TextAlign.center))), textAlign: TextAlign.center))),
wsLinkButton(context, title: trans(context, "CANCEL"), wsLinkButton(context, title: trans(context, "CANCEL"),
action: () { action: () {

View File

@ -60,25 +60,25 @@ class _CheckoutStatusState extends State<CheckoutStatusPage> {
Padding( Padding(
child: Text( child: Text(
trans(context, "Order Status"), trans(context, "Order Status"),
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
), ),
padding: EdgeInsets.only(bottom: 15), padding: EdgeInsets.only(bottom: 15),
), ),
Text( Text(
trans(context, "Thank You!"), trans(context, "Thank You!"),
style: Theme.of(context).primaryTextTheme.title, style: Theme.of(context).primaryTextTheme.headline6,
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
trans(context, "Your transaction details"), trans(context, "Your transaction details"),
style: Theme.of(context).primaryTextTheme.body1, style: Theme.of(context).primaryTextTheme.bodyText2,
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
Text( Text(
trans(context, "Order Ref") + trans(context, "Order Ref") +
". #" + ". #" +
_order.id.toString(), _order.id.toString(),
style: Theme.of(context).primaryTextTheme.body2, style: Theme.of(context).primaryTextTheme.bodyText1,
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
], ],
@ -96,7 +96,9 @@ class _CheckoutStatusState extends State<CheckoutStatusPage> {
child: Image( child: Image(
image: new AssetImage("assets/images/camion.gif"), image: new AssetImage("assets/images/camion.gif"),
height: 170), height: 170),
decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
),
width: double.infinity), width: double.infinity),
], ],
), ),
@ -104,7 +106,7 @@ class _CheckoutStatusState extends State<CheckoutStatusPage> {
child: Padding( child: Padding(
child: Text( child: Text(
trans(context, "Items"), trans(context, "Items"),
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
@ -130,24 +132,28 @@ class _CheckoutStatusState extends State<CheckoutStatusPage> {
Text(lineItem.name, Text(lineItem.name,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body2, .bodyText1,
softWrap: false, softWrap: false,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis), overflow: TextOverflow.ellipsis),
Text("x" + lineItem.quantity.toString(), Text("x" + lineItem.quantity.toString(),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body1), .bodyText2),
], ],
), ),
), ),
Text( Text(
formatStringCurrency( formatStringCurrency(
total: lineItem.total.toString()), 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), padding: EdgeInsets.all(16),
margin: EdgeInsets.all(8), margin: EdgeInsets.all(8),
); );

View File

@ -46,7 +46,7 @@ class _ErrorPageState extends State<ErrorPage> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Text( child: Text(
trans(context, "Sorry, something went wrong"), trans(context, "Sorry, something went wrong"),
style: Theme.of(context).primaryTextTheme.body1, style: Theme.of(context).primaryTextTheme.bodyText2,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),

View File

@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/widgets/app_loader.dart'; import 'package:label_storemax/widgets/app_loader.dart';
import 'package:label_storemax/widgets/cart_icon.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/product_category.dart' as WS;
import 'package:woosignal/models/response/products.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS;
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
@ -26,10 +27,11 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> { class _HomePageState extends State<HomePage> {
_HomePageState(); _HomePageState();
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<WS.Product> _products = []; List<WS.Product> _products = [];
List<WS.ProductCategory> _categories = []; List<WS.ProductCategory> _categories = [];
final GlobalKey _key = GlobalKey();
var _productsController = ScrollController();
int _page; int _page;
bool _shouldStopRequests; bool _shouldStopRequests;
@ -41,115 +43,68 @@ class _HomePageState extends State<HomePage> {
super.initState(); super.initState();
_isLoading = true; _isLoading = true;
_page = 1; _page = 1;
_home(); _home();
_addScrollListener();
} }
_home() async { _home() async {
await _fetchProducts();
await _fetchCategories();
_shouldStopRequests = false; _shouldStopRequests = false;
waitForNextRequest = false; waitForNextRequest = false;
await _fetchMoreProducts();
await _fetchCategories();
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
} }
_fetchProducts() async {
_products = await appWooSignal((api) {
return api.getProducts(perPage: 50, page: _page, status: "publish");
});
}
_fetchCategories() async { _fetchCategories() async {
_categories = await appWooSignal((api) { _categories = await appWooSignal((api) {
return api.getProductCategories(); return api.getProductCategories();
}); });
} }
_addScrollListener() async { _fetchMoreProducts() async {
_productsController.addListener(() {
double maxScroll = _productsController.position.maxScrollExtent;
double currentScroll = _productsController.position.pixels;
double delta = 50.0;
if (maxScroll - currentScroll <= delta) {
if (_shouldStopRequests) { if (_shouldStopRequests) {
return; return;
} }
if (waitForNextRequest) { if (waitForNextRequest) {
return; return;
} }
_fetchMoreProducts();
}
});
}
_fetchMoreProducts() async {
waitForNextRequest = true; waitForNextRequest = true;
List<WS.Product> products = await appWooSignal((api) { List<WS.Product> products = await appWooSignal((api) => api.getProducts(
perPage: 50, page: _page, status: "publish", stockStatus: "instock"));
_page = _page + 1; _page = _page + 1;
return api.getProducts(perPage: 50, page: _page, status: "publish");
});
if (products.length == 0) { if (products.length == 0) {
_shouldStopRequests = true; _shouldStopRequests = true;
} }
waitForNextRequest = false;
setState(() { setState(() {
_products.addAll(products.toList()); _products.addAll(products.toList());
}); });
} }
void _modalBottomSheetMenu() { void _modalBottomSheetMenu() {
showModalBottomSheet( _key.currentState.setState(() {});
context: context, wsModalBottom(
backgroundColor: Colors.transparent, context,
builder: (builder) { title: trans(context, "Categories"),
return new Container( bodyWidget: ListView.separated(
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: <Widget>[
Text(trans(context, "Categories"),
style: Theme.of(context).primaryTextTheme.display1,
textAlign: TextAlign.left),
Expanded(
child: new ListView.builder(
itemCount: _categories.length, itemCount: _categories.length,
separatorBuilder: (cxt, i) {
return Divider();
},
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return InkWell( return ListTile(
child: Container( title: Text(parseHtmlString(_categories[index].name)),
child: Text(_categories[index].name),
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: HexColor("#f2f2f2"), width: 2),
),
),
),
onTap: () { onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, "/browse-category", Navigator.pushNamed(context, "/browse-category",
arguments: _categories[index]); arguments: _categories[index])
.then((value) => setState(() {}));
}, },
); );
}),
)
],
),
),
);
}, },
),
); );
} }
@ -161,9 +116,7 @@ class _HomePageState extends State<HomePage> {
leading: Container( leading: Container(
child: IconButton( child: IconButton(
icon: Icon(Icons.menu), icon: Icon(Icons.menu),
onPressed: () { onPressed: () => Navigator.pushNamed(context, "/home-menu"),
Navigator.pushNamed(context, "/home-menu");
},
), ),
margin: EdgeInsets.only(left: 0), margin: EdgeInsets.only(left: 0),
), ),
@ -177,11 +130,10 @@ class _HomePageState extends State<HomePage> {
color: Colors.black, color: Colors.black,
size: 35, size: 35,
), ),
onPressed: () { onPressed: () => Navigator.pushNamed(context, "/home-search")
Navigator.pushNamed(context, "/home-search"); .then((value) => _key.currentState.setState(() {})),
},
), ),
wsCartIcon(context) wsCartIcon(context, key: _key)
], ],
), ),
body: SafeArea( body: SafeArea(
@ -198,10 +150,10 @@ class _HomePageState extends State<HomePage> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Text(trans(context, "Shop") + " / ", Text(trans(context, "Shop") + " / ",
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
Text( Text(
trans(context, "Newest"), trans(context, "Newest"),
style: Theme.of(context).primaryTextTheme.body1, style: Theme.of(context).primaryTextTheme.bodyText2,
) )
], ],
), ),
@ -210,25 +162,21 @@ class _HomePageState extends State<HomePage> {
height: 60, height: 60,
child: Text( child: Text(
trans(context, "Browse categories"), trans(context, "Browse categories"),
style: Theme.of(context).primaryTextTheme.body2, style: Theme.of(context).primaryTextTheme.bodyText1,
), ),
onPressed: () { onPressed: _modalBottomSheetMenu,
_modalBottomSheetMenu();
},
) )
], ],
), ),
(_isLoading (_isLoading
? Expanded(child: showAppLoader()) ? Expanded(child: showAppLoader())
: Expanded( : Expanded(
child: GridView.count( child: refreshableScroll(context,
controller: _productsController, refreshController: _refreshController,
crossAxisCount: 2, onRefresh: _onRefresh,
children: List.generate(_products.length, (index) { onLoading: _onLoading,
return wsCardProductItem(context, products: _products,
index: index, product: _products[index]); onTap: _showProduct),
}),
),
flex: 1, flex: 1,
)), )),
], ],
@ -236,4 +184,32 @@ class _HomePageState extends State<HomePage> {
), ),
); );
} }
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(() {}));
}
} }

View File

@ -9,6 +9,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart'; 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/labelconfig.dart';
import 'package:label_storemax/widgets/menu_item.dart'; import 'package:label_storemax/widgets/menu_item.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
@ -37,7 +38,7 @@ class _HomeMenuPageState extends State<HomeMenuPage> {
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
elevation: 0.0, elevation: 0.0,
title: Text(trans(context, "Menu"), title: Text(trans(context, "Menu"),
style: Theme.of(context).primaryTextTheme.title), style: Theme.of(context).primaryTextTheme.headline6),
leading: IconButton( leading: IconButton(
icon: Icon(Icons.close), icon: Icon(Icons.close),
onPressed: () { onPressed: () {
@ -89,7 +90,12 @@ class _HomeMenuPageState extends State<HomeMenuPage> {
Navigator.pushNamed(context, "/about"); 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"); Navigator.pushNamed(context, "/account-detail");
} }
} }

View File

@ -61,7 +61,7 @@ class _HomeSearchPageState extends State<HomeSearchPage> {
), ),
TextField( TextField(
controller: _txtSearchController, controller: _txtSearchController,
style: Theme.of(context).primaryTextTheme.display2, style: Theme.of(context).primaryTextTheme.headline3,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
autocorrect: false, autocorrect: false,
autofocus: true, autofocus: true,

View File

@ -50,9 +50,23 @@ class _ProductDetailState extends State<ProductDetailPage> {
} }
_fetchProductVariations() async { _fetchProductVariations() async {
_productVariations = await appWooSignal((api) { List<WS.ProductVariation> tmpVariations = [];
return api.getProductVariations(_product.id); int currentPage = 1;
bool isFetching = true;
while (isFetching) {
List<WS.ProductVariation> 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(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
@ -89,14 +103,13 @@ class _ProductDetailState extends State<ProductDetailPage> {
title: trans(context, "Select a") + title: trans(context, "Select a") +
" " + " " +
_product.attributes[attributeIndex].name, _product.attributes[attributeIndex].name,
bodyWidget: Expanded( bodyWidget: ListView.separated(
child: ListView.separated(
itemCount: _product.attributes[attributeIndex].options.length, itemCount: _product.attributes[attributeIndex].options.length,
separatorBuilder: (BuildContext context, int index) => Divider(), separatorBuilder: (BuildContext context, int index) => Divider(),
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return ListTile( return ListTile(
title: Text(_product.attributes[attributeIndex].options[index], title: Text(_product.attributes[attributeIndex].options[index],
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
trailing: (_tmpAttributeObj.isNotEmpty && trailing: (_tmpAttributeObj.isNotEmpty &&
_tmpAttributeObj.containsKey(attributeIndex) && _tmpAttributeObj.containsKey(attributeIndex) &&
_tmpAttributeObj[attributeIndex]["value"] == _tmpAttributeObj[attributeIndex]["value"] ==
@ -115,8 +128,6 @@ class _ProductDetailState extends State<ProductDetailPage> {
); );
}, },
), ),
flex: 1,
),
); );
} }
@ -134,8 +145,7 @@ class _ProductDetailState extends State<ProductDetailPage> {
wsModalBottom( wsModalBottom(
context, context,
title: trans(context, "Options"), title: trans(context, "Options"),
bodyWidget: Expanded( bodyWidget: ListView.separated(
child: ListView.separated(
itemCount: _product.attributes.length, itemCount: _product.attributes.length,
separatorBuilder: (BuildContext context, int index) => Divider( separatorBuilder: (BuildContext context, int index) => Divider(
color: Colors.black12, color: Colors.black12,
@ -144,11 +154,11 @@ class _ProductDetailState extends State<ProductDetailPage> {
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return ListTile( return ListTile(
title: Text(_product.attributes[index].name, title: Text(_product.attributes[index].name,
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
subtitle: (_tmpAttributeObj.isNotEmpty && subtitle: (_tmpAttributeObj.isNotEmpty &&
_tmpAttributeObj.containsKey(index)) _tmpAttributeObj.containsKey(index))
? Text(_tmpAttributeObj[index]["value"], ? Text(_tmpAttributeObj[index]["value"],
style: Theme.of(context).primaryTextTheme.body2) style: Theme.of(context).primaryTextTheme.bodyText1)
: Text(trans(context, "Select a") + : Text(trans(context, "Select a") +
" " + " " +
_product.attributes[index].name), _product.attributes[index].name),
@ -161,7 +171,7 @@ class _ProductDetailState extends State<ProductDetailPage> {
}, },
); );
}, },
)), ),
extraWidget: Container( extraWidget: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.black12, width: 1))), border: Border(top: BorderSide(color: Colors.black12, width: 1))),
@ -179,14 +189,14 @@ class _ProductDetailState extends State<ProductDetailPage> {
findProductVariation() == null) findProductVariation() == null)
? trans(context, "This variation is unavailable") ? trans(context, "This variation is unavailable")
: trans(context, "Choose your options"))), : trans(context, "Choose your options"))),
style: Theme.of(context).primaryTextTheme.subhead), style: Theme.of(context).primaryTextTheme.subtitle1),
Text( Text(
(findProductVariation() != null (findProductVariation() != null
? findProductVariation().stockStatus != "instock" ? findProductVariation().stockStatus != "instock"
? trans(context, "Out of stock") ? 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"), wsPrimaryButton(context, title: trans(context, "Add to cart"),
action: () { action: () {
@ -255,11 +265,10 @@ class _ProductDetailState extends State<ProductDetailPage> {
wsModalBottom( wsModalBottom(
context, context,
title: trans(context, "Description"), title: trans(context, "Description"),
bodyWidget: Expanded( bodyWidget: SingleChildScrollView(
child: SingleChildScrollView( child: Text(
child: Text(parseHtmlString(_product.description)), parseHtmlString(_product.description),
), ),
flex: 1,
), ),
); );
} }
@ -312,7 +321,9 @@ class _ProductDetailState extends State<ProductDetailPage> {
Container( Container(
height: 100, height: 100,
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
vertical: 10, horizontal: 16), vertical: 10,
horizontal: 16,
),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -320,8 +331,11 @@ class _ProductDetailState extends State<ProductDetailPage> {
Flexible( Flexible(
child: Text( child: Text(
_product.name, _product.name,
style: style: Theme.of(context)
Theme.of(context).primaryTextTheme.body2, .primaryTextTheme
.bodyText1
.copyWith(
color: Colors.black87, fontSize: 20),
textAlign: TextAlign.left, textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 2,
@ -338,13 +352,24 @@ class _ProductDetailState extends State<ProductDetailPage> {
total: _product.price), total: _product.price),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.display1 .headline4
.copyWith( .copyWith(
fontSize: 20, fontSize: 20,
), ),
textAlign: TextAlign.right, 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, flex: 2,
) )
@ -352,7 +377,10 @@ class _ProductDetailState extends State<ProductDetailPage> {
), ),
), ),
Container( Container(
decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
boxShadow: wsBoxShadow(),
borderRadius: BorderRadius.circular(4)),
padding: padding:
EdgeInsets.symmetric(vertical: 4, horizontal: 16), EdgeInsets.symmetric(vertical: 4, horizontal: 16),
height: 180, height: 180,
@ -378,15 +406,13 @@ class _ProductDetailState extends State<ProductDetailPage> {
trans(context, "Full description"), trans(context, "Full description"),
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body1 .bodyText2
.copyWith(fontSize: 14), .copyWith(fontSize: 14),
textAlign: TextAlign.right, textAlign: TextAlign.right,
), ),
height: 50, height: 50,
minWidth: 60, minWidth: 60,
onPressed: () { onPressed: _modalBottomSheetMenu,
_modalBottomSheetMenu();
},
), ),
], ],
), ),
@ -432,7 +458,8 @@ class _ProductDetailState extends State<ProductDetailPage> {
children: <Widget>[ children: <Widget>[
Text( Text(
"Quantity", "Quantity",
style: Theme.of(context).primaryTextTheme.body2, style:
Theme.of(context).primaryTextTheme.bodyText1,
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
@ -451,8 +478,9 @@ class _ProductDetailState extends State<ProductDetailPage> {
), ),
Text( Text(
_quantityIndicator.toString(), _quantityIndicator.toString(),
style: style: Theme.of(context)
Theme.of(context).primaryTextTheme.body2, .primaryTextTheme
.bodyText1,
), ),
IconButton( IconButton(
icon: Icon( icon: Icon(
@ -479,11 +507,12 @@ class _ProductDetailState extends State<ProductDetailPage> {
child: Align( child: Align(
child: Text( child: Text(
formatStringCurrency( formatStringCurrency(
total: (double.parse(_product.price) * total: (parseWcPrice(_product.price) *
_quantityIndicator) _quantityIndicator)
.toString()), .toString()),
style: style: Theme.of(context)
Theme.of(context).primaryTextTheme.display1, .primaryTextTheme
.headline4,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -492,9 +521,7 @@ class _ProductDetailState extends State<ProductDetailPage> {
child: wsPrimaryButton( child: wsPrimaryButton(
context, context,
title: trans(context, "Add to cart"), title: trans(context, "Add to cart"),
action: () { action: () => _addItemToCart(),
_addItemToCart();
},
), ),
), ),
], ],

View File

@ -53,10 +53,12 @@ class _ProductImageViewerPageState extends State<ProductImageViewerPage> {
imageUrl: _arrImageSrc[index], imageUrl: _arrImageSrc[index],
placeholder: (context, url) => placeholder: (context, url) =>
new CircularProgressIndicator( new CircularProgressIndicator(
strokeWidth: 2, backgroundColor: Colors.black12), strokeWidth: 2,
errorWidget: (context, url, error) => backgroundColor: Colors.black12,
new Icon(Icons.error), ),
fit: BoxFit.contain); errorWidget: (context, url, error) => new Icon(Icons.error),
fit: BoxFit.contain,
);
}, },
itemCount: _arrImageSrc.length, itemCount: _arrImageSrc.length,
viewportFraction: 0.9, viewportFraction: 0.9,

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -25,6 +25,7 @@ import 'package:woosignal_stripe/woosignal_stripe.dart';
stripePay(context, stripePay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { {@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
try {
// CONFIGURE STRIPE // CONFIGURE STRIPE
FlutterStripePayment.setStripeSettings( FlutterStripePayment.setStripeSettings(
stripeAccount: app_stripe_account, liveMode: app_stripe_live_mode); stripeAccount: app_stripe_account, liveMode: app_stripe_live_mode);
@ -47,14 +48,12 @@ stripePay(context,
String cartShortDesc = await cart.cartShortDesc(); String cartShortDesc = await cart.cartShortDesc();
dynamic rsp = await appWooSignal((api) { dynamic rsp = await appWooSignal((api) => api.stripePaymentIntent(
return api.stripePaymentIntent(
amount: total, amount: total,
email: billingDetails.billingAddress.emailAddress, email: billingDetails.billingAddress.emailAddress,
desc: cartShortDesc, desc: cartShortDesc,
shipping: address, shipping: address,
); ));
});
if (rsp == null) { if (rsp == null) {
showEdgeAlertWith(context, showEdgeAlertWith(context,
@ -75,9 +74,7 @@ stripePay(context,
if (intentResponse.status == PaymentResponseStatus.succeeded) { if (intentResponse.status == PaymentResponseStatus.succeeded) {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate); OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
Order order = await appWooSignal((api) { Order order = await appWooSignal((api) => api.createOrder(orderWC));
return api.createOrder(orderWC);
});
if (order != null) { if (order != null) {
Cart.getInstance.clear(); Cart.getInstance.clear();
@ -88,8 +85,8 @@ stripePay(context,
title: trans(context, "Error"), title: trans(context, "Error"),
desc: trans( desc: trans(
context, context,
trans( trans(context,
context, "Something went wrong, please contact our store")), "Something went wrong, please contact our store")),
); );
state.reloadState(showLoader: false); state.reloadState(showLoader: false);
} }
@ -107,5 +104,15 @@ stripePay(context,
state.reloadState(showLoader: false); 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);
} }
} }

View File

@ -38,7 +38,7 @@ Widget wsSecondaryButton(BuildContext context,
child: RaisedButton( child: RaisedButton(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Text(title, child: Text(title,
style: Theme.of(context).primaryTextTheme.body2, style: Theme.of(context).primaryTextTheme.bodyText1,
textAlign: TextAlign.center), textAlign: TextAlign.center),
onPressed: action, onPressed: action,
color: HexColor("#f6f6f9"), color: HexColor("#f6f6f9"),
@ -54,7 +54,7 @@ Widget wsLinkButton(BuildContext context,
child: MaterialButton( child: MaterialButton(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Text(title, child: Text(title,
style: Theme.of(context).primaryTextTheme.body2, style: Theme.of(context).primaryTextTheme.bodyText1,
textAlign: TextAlign.left), textAlign: TextAlign.left),
onPressed: action, onPressed: action,
elevation: 0, elevation: 0,

View File

@ -12,13 +12,16 @@ import 'package:flutter/material.dart';
import 'package:label_storemax/models/cart.dart'; import 'package:label_storemax/models/cart.dart';
import 'package:label_storemax/models/cart_line_item.dart'; import 'package:label_storemax/models/cart_line_item.dart';
Widget wsCartIcon(BuildContext context) { Widget wsCartIcon(BuildContext context, {Key key}) {
return IconButton( return StatefulBuilder(
key: key,
builder: (BuildContext context, StateSetter setState) => IconButton(
icon: Stack( icon: Stack(
children: <Widget>[ children: <Widget>[
Positioned.fill( Positioned.fill(
child: Align( child: Align(
child: Icon(Icons.shopping_cart, size: 20, color: Colors.black87), child:
Icon(Icons.shopping_cart, size: 20, color: Colors.black87),
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
), ),
bottom: 0), bottom: 0),
@ -37,7 +40,7 @@ Widget wsCartIcon(BuildContext context) {
else else
return new Text( return new Text(
snapshot.data.length.toString(), snapshot.data.length.toString(),
style: Theme.of(context).primaryTextTheme.body2, style: Theme.of(context).primaryTextTheme.bodyText1,
textAlign: TextAlign.center, textAlign: TextAlign.center,
); );
} }
@ -51,5 +54,6 @@ Widget wsCartIcon(BuildContext context) {
onPressed: () { onPressed: () {
Navigator.pushNamed(context, "/cart"); Navigator.pushNamed(context, "/cart");
}, },
),
); );
} }

View File

@ -24,7 +24,7 @@ Widget wsMenuItem(BuildContext context,
children: <Widget>[ children: <Widget>[
leading, leading,
Text(" " + title, Text(" " + title,
style: Theme.of(context).primaryTextTheme.body1), style: Theme.of(context).primaryTextTheme.bodyText2),
], ],
), ),
), ),

View File

@ -28,7 +28,7 @@ Widget wsRow2Text(BuildContext context, {String text1, String text2}) {
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: Container( child: Container(
child: Text(text1, style: Theme.of(context).textTheme.title), child: Text(text1, style: Theme.of(context).textTheme.headline6),
), ),
flex: 3, flex: 3,
), ),
@ -37,7 +37,7 @@ Widget wsRow2Text(BuildContext context, {String text1, String text2}) {
child: Text(text2, child: Text(text2,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.body2 .bodyText1
.copyWith(fontSize: 16, color: Colors.black87)), .copyWith(fontSize: 16, color: Colors.black87)),
), ),
flex: 3, flex: 3,
@ -50,7 +50,7 @@ Widget wsNoResults(BuildContext context) {
return Column( return Column(
children: <Widget>[ children: <Widget>[
Text(trans(context, "No results"), 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: <Widget>[ children: <Widget>[
Padding( Padding(
child: Text(heading, child: Text(heading,
style: Theme.of(context).primaryTextTheme.body1), style: Theme.of(context)
.primaryTextTheme
.bodyText2
.copyWith(fontSize: 16)),
padding: EdgeInsets.only(bottom: 8), padding: EdgeInsets.only(bottom: 8),
), ),
Flexible( Flexible(
@ -87,8 +90,9 @@ Widget wsCheckoutRow(BuildContext context,
Flexible( Flexible(
child: Container( child: Container(
child: Text(leadTitle, child: Text(leadTitle,
style: style: Theme.of(context)
Theme.of(context).primaryTextTheme.subhead, .primaryTextTheme
.subtitle1,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: false), softWrap: false),
@ -131,15 +135,15 @@ Widget wsTextEditingRow(BuildContext context,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: Padding( child: Padding(
child: child: Text(heading,
Text(heading, style: Theme.of(context).primaryTextTheme.body2), style: Theme.of(context).primaryTextTheme.bodyText1),
padding: EdgeInsets.only(bottom: 2), padding: EdgeInsets.only(bottom: 2),
), ),
), ),
Flexible( Flexible(
child: TextField( child: TextField(
controller: controller, controller: controller,
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
keyboardType: keyboardType ?? TextInputType.text, keyboardType: keyboardType ?? TextInputType.text,
autocorrect: false, autocorrect: false,
autofocus: shouldAutoFocus ?? false, autofocus: shouldAutoFocus ?? false,
@ -160,13 +164,15 @@ Widget widgetCheckoutMeta(BuildContext context, {String title, String amount}) {
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: Container( child: Container(
child: Text(title, style: Theme.of(context).primaryTextTheme.body1), child:
Text(title, style: Theme.of(context).primaryTextTheme.bodyText2),
), ),
flex: 3, flex: 3,
), ),
Flexible( Flexible(
child: Container( child: Container(
child: Text(amount, style: Theme.of(context).primaryTextTheme.body2), child:
Text(amount, style: Theme.of(context).primaryTextTheme.bodyText1),
), ),
flex: 3, flex: 3,
) )
@ -188,7 +194,8 @@ List<BoxShadow> wsBoxShadow({double blurRadius}) {
]; ];
} }
Widget wsCardProductItem(BuildContext context, {int index, Product product}) { Widget wsCardProductItem(BuildContext context,
{int index, Product product, onTap}) {
return InkWell( return InkWell(
child: Container( child: Container(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
@ -196,43 +203,59 @@ Widget wsCardProductItem(BuildContext context, {int index, Product product}) {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
boxShadow: wsBoxShadow(blurRadius: 4),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[ children: <Widget>[
Flexible( Flexible(
child: CachedNetworkImage( child: CachedNetworkImage(
imageUrl: (product.images.length > 0 imageUrl:
? product.images.first.src (product.images.length > 0 ? product.images.first.src : ""),
: ""), placeholder: (context, url) => new CircularProgressIndicator(),
placeholder: (context, url) =>
new CircularProgressIndicator(),
errorWidget: (context, url, error) => new Icon(Icons.error), errorWidget: (context, url, error) => new Icon(Icons.error),
fit: BoxFit.fitWidth), fit: BoxFit.contain),
flex: 4, flex: 4,
), ),
Flexible( Flexible(
child: Text( child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
formatStringCurrency(total: product.price), formatStringCurrency(total: product.price),
style: Theme.of(context).textTheme.body2, 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, textAlign: TextAlign.left,
), ),
)
: null),
].where((t) => t != null).toList(),
),
flex: 1, flex: 1,
), ),
Expanded( Expanded(
child: Text( child: Text(
product.name, product.name,
style: Theme.of(context).textTheme.body1, style: Theme.of(context).textTheme.bodyText2,
overflow: TextOverflow.clip, overflow: TextOverflow.clip,
maxLines: 1, maxLines: 1,
), ),
flex: 1, flex: 1,
) )
], ],
)), ),
onTap: () { ),
Navigator.pushNamed(context, "/product-detail", arguments: product); onTap: () => onTap(product),
},
); );
} }
@ -245,27 +268,41 @@ void wsModalBottom(BuildContext context,
return SafeArea( return SafeArea(
child: Container( child: Container(
height: double.infinity, height: double.infinity,
width: double.infinity - 10, width: double.infinity,
color: Colors.transparent, color: Colors.transparent,
child: new Container( child: new Container(
padding: EdgeInsets.only(top: 25, left: 18, right: 18), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: new BoxDecoration( decoration: new BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: new BorderRadius.only( borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0), topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0)), topRight: const Radius.circular(10.0),
),
), ),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Text(title, Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Text(title,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.display1 .headline4
.copyWith(fontSize: 20), .copyWith(fontSize: 20),
textAlign: TextAlign.left), textAlign: TextAlign.left),
bodyWidget, ),
extraWidget ?? Container() 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: <Widget>[ children: <Widget>[
Text( Text(
cartLineItem.name, cartLineItem.name,
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subtitle1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 3, maxLines: 3,
), ),
(cartLineItem.variationOptions != null (cartLineItem.variationOptions != null
? Text(cartLineItem.variationOptions, ? Text(cartLineItem.variationOptions,
style: Theme.of(context).primaryTextTheme.body2) style:
Theme.of(context).primaryTextTheme.bodyText1)
: Container()), : Container()),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@ -449,11 +487,14 @@ Widget wsCardCartItem(BuildContext context,
: trans(context, "In Stock")), : trans(context, "In Stock")),
style: (cartLineItem.stockStatus == "outofstock" style: (cartLineItem.stockStatus == "outofstock"
? Theme.of(context).textTheme.caption ? Theme.of(context).textTheme.caption
: Theme.of(context).primaryTextTheme.body1)), : Theme.of(context)
.primaryTextTheme
.bodyText2)),
Text( Text(
formatDoubleCurrency( formatDoubleCurrency(
total: double.parse(cartLineItem.total)), total: double.parse(cartLineItem.total)),
style: Theme.of(context).primaryTextTheme.subhead, style:
Theme.of(context).primaryTextTheme.subtitle1,
textAlign: TextAlign.center) textAlign: TextAlign.center)
], ],
), ),
@ -479,7 +520,7 @@ Widget wsCardCartItem(BuildContext context,
highlightColor: Colors.transparent, highlightColor: Colors.transparent,
), ),
Text(cartLineItem.quantity.toString(), Text(cartLineItem.quantity.toString(),
style: Theme.of(context).primaryTextTheme.title), style: Theme.of(context).primaryTextTheme.headline6),
IconButton( IconButton(
icon: Icon(Icons.remove_circle_outline), icon: Icon(Icons.remove_circle_outline),
onPressed: actionDecrementQuantity, onPressed: actionDecrementQuantity,

View File

@ -7,35 +7,28 @@ packages:
name: archive name: archive
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.11" version: "2.0.13"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.2" version: "1.6.0"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.4.0" version: "2.4.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.5" version: "2.0.0"
braintree_payment:
dependency: "direct main"
description:
name: braintree_payment
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.4"
bubble_tab_indicator: bubble_tab_indicator:
dependency: "direct main" dependency: "direct main"
description: description:
@ -56,7 +49,7 @@ packages:
name: charcode name: charcode
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.2" version: "1.1.3"
clock: clock:
dependency: transitive dependency: transitive
description: description:
@ -70,7 +63,7 @@ packages:
name: collection name: collection
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.11" version: "1.14.12"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -84,7 +77,7 @@ packages:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.3" version: "2.1.4"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
@ -237,7 +230,7 @@ packages:
name: image name: image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.4" version: "2.1.12"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -350,13 +343,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" 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: quiver:
dependency: transitive dependency: transitive
description: description:
name: quiver name: quiver
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.5" version: "2.1.3"
rxdart: rxdart:
dependency: transitive dependency: transitive
description: description:
@ -403,7 +403,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.5.5" version: "1.7.0"
sqflite: sqflite:
dependency: transitive dependency: transitive
description: description:
@ -466,7 +466,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.11" version: "0.2.15"
transformer_page_view: transformer_page_view:
dependency: transitive dependency: transitive
description: description:
@ -529,7 +529,7 @@ packages:
name: woosignal name: woosignal
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.6" version: "1.0.8"
woosignal_stripe: woosignal_stripe:
dependency: "direct main" dependency: "direct main"
description: description:
@ -550,7 +550,7 @@ packages:
name: xml name: xml
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.5.0" version: "3.6.1"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,5 +1,5 @@
# Label StoreMax # Label StoreMax
# Version 2.0.0 # Version 2.0.2
#authors: - "Anthony Gordon" #authors: - "Anthony Gordon"
#documentation: https://woosignal.com/docs/app/ios/label-storemax #documentation: https://woosignal.com/docs/app/ios/label-storemax
#homepage: https://woosignal.com/ #homepage: https://woosignal.com/
@ -23,7 +23,7 @@ environment:
sdk: ">=2.1.0 <3.0.0" sdk: ">=2.1.0 <3.0.0"
dependencies: dependencies:
woosignal: ^1.0.6 woosignal: ^1.0.8
woosignal_stripe: ^0.0.4 woosignal_stripe: ^0.0.4
wp_json_api: ^0.1.2 wp_json_api: ^0.1.2
shared_preferences: ^0.5.6+3 shared_preferences: ^0.5.6+3
@ -34,6 +34,7 @@ dependencies:
flutter_money_formatter: ^0.8.3 flutter_money_formatter: ^0.8.3
platform_alert_dialog: ^1.0.0+2 platform_alert_dialog: ^1.0.0+2
flutter_web_browser: ^0.11.0 flutter_web_browser: ^0.11.0
pull_to_refresh: ^1.5.8
dio: ^3.0.9 dio: ^3.0.9
intl: ^0.16.1 intl: ^0.16.1
flutter_swiper: ^1.1.6 flutter_swiper: ^1.1.6
@ -44,7 +45,6 @@ dependencies:
flutter_spinkit: ^4.1.2+1 flutter_spinkit: ^4.1.2+1
flutter_launcher_icons: ^0.7.4 flutter_launcher_icons: ^0.7.4
html: ^0.14.0+3 html: ^0.14.0+3
braintree_payment: ^1.2.4
flutter: flutter:
sdk: flutter sdk: flutter
@ -75,7 +75,7 @@ flutter:
- assets/images/credit_cards.png - assets/images/credit_cards.png
- assets/images/shipping_icon.png - assets/images/shipping_icon.png
- assets/images/dark_powered_by_stripe.png - assets/images/dark_powered_by_stripe.png
- assets/images/cart_empty.png - assets/images/cash_on_delivery.jpeg
- lang/en.json - lang/en.json
fonts: fonts: