v5.0.0 - Major release

This commit is contained in:
Anthony Gordon 2021-04-11 23:39:35 +01:00
parent 075dfdb752
commit 1737fa1604
54 changed files with 1399 additions and 587 deletions

View File

@ -28,6 +28,13 @@ STRIPE_LIVE_MODE="false"
RAZORPAY_ID=""
# Razorpay ID from https://razorpay.com
# *<! ------ PAYPAL (OPTIONAL) ------!>*
PAYPAL_ACCOUNT_EMAIL="mystore@business.com"
# Your PayPal account email e.g. mystore@business.com
PAYPAL_LIVE_MODE="false"
# Change to 'true' for live payments
# *<! ------ EXTRAS ------!>*
PRODUCT_PLACEHOLDER_IMAGE="https://woosignal.com/images/woocommerce-placeholder.png"

View File

@ -1,3 +1,14 @@
## [5.0.0] - 2020-04-11
* Major release
# Null safety libraries added
# PayPal Payment Gateway Added
# New theme customization
# Fixed Drawer Widget when using Light/Dark mode
# New config file for currency
* Pubspec.yaml dependency updates
# Bug fixes
## [4.0.0] - 2020-03-28
* Major release

View File

@ -4,7 +4,7 @@
# WooCommerce App: Label StoreMax
### Label StoreMax - v4.0.0
### Label StoreMax - v5.0.0
[Official WooSignal WooCommerce App](https://woosignal.com)
@ -44,7 +44,7 @@ Full documentation this available [here](https://woosignal.com/docs/app/ios/labe
- Browse products, make orders, customer login (via WordPress)
- Change app name, logo, customize default language, currency + more
- Light and dark mode
- Stripe, Cash On Delivery, RazorPay
- Stripe, Cash On Delivery, RazorPay, PayPal
- Localized for en, es, pt, it, hi, fr
- Orders show as normal in WooCommerce

View File

@ -1,3 +0,0 @@
[
]

View File

@ -176,5 +176,13 @@
"Retry": "Wiederholen",
"Retry later": "Versuchen Sie es später erneut",
"Light Mode": "Lichtmodus",
"Dark Mode": "Dunkler Modus"
"Dark Mode": "Dunkler Modus",
"PayPal Checkout": "PayPal Checkout",
"Processing Payment": "Zahlung verarbeiten",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "Bitte warten Sie, Ihre Bestellung wird bearbeitet und Sie werden auf die PayPal-Website weitergeleitet.",
"If you are not automatically redirected to PayPal within 5 seconds": "Wenn Sie nicht innerhalb von 5 Sekunden automatisch zu PayPal weitergeleitet werden",
"Payment Cancelled": "Zahlung storniert",
"The payment has been cancelled": "Die Zahlung wurde storniert",
"Must have": "Haben müssen",
"Our selection of new items": "Unsere Auswahl an Neuheiten"
}

View File

@ -176,5 +176,13 @@
"Retry": "Retry",
"Retry later": "Retry later",
"Light Mode": "Light Mode",
"Dark Mode": "Dark Mode"
"Dark Mode": "Dark Mode",
"PayPal Checkout": "PayPal Checkout",
"Processing Payment": "Processing Payment",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "Please wait, your order is being processed and you will be redirected to the PayPal website.",
"If you are not automatically redirected to PayPal within 5 seconds": "If you are not automatically redirected to PayPal within 5 seconds",
"Payment Cancelled": "Payment Cancelled",
"The payment has been cancelled": "The payment has been cancelled",
"Must have": "Must have",
"Our selection of new items": "Our selection of new items"
}

View File

@ -176,5 +176,13 @@
"Retry": "Rever",
"Retry later": "Reintentar más tarde",
"Light Mode": "Modo de luz",
"Dark Mode": "Modo oscuro"
"Dark Mode": "Modo oscuro",
"PayPal Checkout": "Pago con PayPal",
"Processing Payment": "Procesando el pago",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "Espere, su pedido se está procesando y será redirigido al sitio web de PayPal.",
"If you are not automatically redirected to PayPal within 5 seconds": "Si no se le redirige automáticamente a PayPal en 5 segundos",
"Payment Cancelled": "Pago cancelado",
"The payment has been cancelled": "El pago ha sido cancelado",
"Must have": "Debe tener",
"Our selection of new items": "Nuestra selección de novedades"
}

View File

@ -176,5 +176,13 @@
"Retry": "Recommencez",
"Retry later": "Réessayer plus tard",
"Light Mode": "Mode lumière",
"Dark Mode": "Mode sombre"
"Dark Mode": "Mode sombre",
"PayPal Checkout": "Paiement PayPal",
"Processing Payment": "Traitement du paiement",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "Veuillez patienter, votre commande est en cours de traitement et vous serez redirigé vers le site PayPal.",
"If you are not automatically redirected to PayPal within 5 seconds": "Si vous n'êtes pas automatiquement redirigé vers PayPal dans les 5 secondes",
"Payment Cancelled": "Paiement annulé",
"The payment has been cancelled": "Le paiement a été annulé",
"Must have": "Doit avoir",
"Our selection of new items": "Notre sélection de nouveautés"
}

View File

@ -176,5 +176,13 @@
"Retry": "pun: prayaas karen",
"Retry later": "baad mein pun: prayaas karen",
"Light Mode": "lait mod",
"Dark Mode": "daark mod"
"Dark Mode": "daark mod",
"PayPal Checkout": "pepaal chekaut",
"Processing Payment": "sansaadhan sambandhee bhugataan",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "krpaya prateeksha karen, aapaka aadesh sansaadhit kiya ja raha hai aur aapako pepaal vebasait par punah nirdeshit kiya jaega.",
"If you are not automatically redirected to PayPal within 5 seconds": "yadi aap 5 sekand ke bheetar svachaalit roop se pepail par punarnirdeshit nahin hote hain",
"Payment Cancelled": "bhugataan radd kiya gaya",
"The payment has been cancelled": "bhugataan radd kar diya gaya hai",
"Must have": "hona aavashyak hai",
"Our selection of new items": "naee vastuon ka hamaara chayan"
}

View File

@ -176,5 +176,13 @@
"Retry": "Riprova",
"Retry later": "Riprova più tardi",
"Light Mode": "Modalità luce",
"Dark Mode": "Modalità scura"
"Dark Mode": "Modalità scura",
"PayPal Checkout": "Pagamento PayPal",
"Processing Payment": "Pagamento in elaborazione",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "Attendi, il tuo ordine è in fase di elaborazione e verrai reindirizzato al sito web di PayPal.",
"If you are not automatically redirected to PayPal within 5 seconds": "Se non vieni reindirizzato automaticamente a PayPal entro 5 secondi",
"Payment Cancelled": "Pagamento annullato",
"The payment has been cancelled": "Il pagamento è stato annullato",
"Must have": "Deve avere",
"Our selection of new items": "La nostra selezione di nuovi articoli"
}

View File

@ -176,5 +176,13 @@
"Retry": "Tentar novamente",
"Retry later": "Tentar mais tarde",
"Light Mode": "Modo de luz",
"Dark Mode": "Modo escuro"
"Dark Mode": "Modo escuro",
"PayPal Checkout": "PayPal Checkout",
"Processing Payment": "Processando o pagamento",
"Please wait, your order is being processed and you will be redirected to the PayPal website.": "Aguarde, seu pedido está sendo processado e você será redirecionado para o site do PayPal.",
"If you are not automatically redirected to PayPal within 5 seconds": "Se você não for redirecionado automaticamente para o PayPal em 5 segundos",
"Payment Cancelled": "Pagamento Cancelado",
"The payment has been cancelled": "O pagamento foi cancelado",
"Must have": "Deve ter",
"Our selection of new items": "Nossa seleção de novos itens"
}

View File

@ -47,7 +47,7 @@ class CartLineItem {
this.metaData});
String getCartTotal() {
return (quantity * parseWcPrice(subtotal)).toString();
return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2);
}
CartLineItem.fromJson(Map<String, dynamic> json)

View File

@ -30,19 +30,19 @@ cashOnDeliveryPay(context,
if (order != null) {
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Error"),
desc: trans(context,
description: trans(context,
trans(context, "Something went wrong, please contact our store")),
);
state.reloadState(showLoader: false);
}
} catch (_) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Error"),
desc: trans(context,
description: trans(context,
trans(context, "Something went wrong, please contact our store")),
);
state.reloadState(showLoader: false);

View File

@ -50,10 +50,10 @@ examplePay(context,
if (order != null) {
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Error"),
desc: trans(context,
description: trans(context,
trans(context, "Something went wrong, please contact our store")),
);
state.reloadState(showLoader: false);

View File

@ -0,0 +1,78 @@
//
// LabelCore
// Label StoreMax
//
// Created by Anthony Gordon.
// 2021, 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/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation.dart';
import 'package:flutter_app/resources/widgets/checkout_paypal.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/order.dart';
import 'package:woosignal/models/response/tax_rate.dart';
payPalPay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async {
await checkout(taxRate, (total, billingDetails, cart) async {
List<CartLineItem> cartLineItems = await cart.getCart();
String description = await cart.cartShortDesc();
state.reloadState(showLoader: true);
await Navigator.push(
context,
MaterialPageRoute(
builder: (_) => PayPalCheckout(
description: description,
amount: total,
cartLineItems: cartLineItems))).then((value) async {
if (value is Map<String, dynamic>) {
if (value.containsKey("status") && value["status"] == "success") {
OrderWC orderWC =
await buildOrderWC(taxRate: taxRate, markPaid: true);
Order order = await appWooSignal((api) => api.createOrder(orderWC));
if (order != null) {
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showToastNotification(
context,
title: trans(context, "Error"),
description: trans(
context,
trans(context,
"Something went wrong, please contact our store")),
);
state.reloadState(showLoader: false);
}
} else {
showToastNotification(
context,
title: trans(context, "Payment Cancelled"),
description: trans(
context, trans(context, "The payment has been cancelled")),
);
state.reloadState(showLoader: false);
}
} else {
showToastNotification(
context,
title: trans(context, "Payment Cancelled"),
description:
trans(context, trans(context, "The payment has been cancelled")),
);
state.reloadState(showLoader: false);
}
});
});
}

View File

@ -36,33 +36,33 @@ razorPay(context,
razorPay.clear();
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Error"),
desc: trans(
description: trans(
context,
trans(context, "Something went wrong, please contact our store"),
),
style: EdgeAlertStyle.WARNING);
style: ToastNotificationStyleType.WARNING);
razorPay.clear();
state.reloadState(showLoader: false);
}
});
razorPay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Error"),
desc: response.message,
style: EdgeAlertStyle.WARNING);
description: response.message,
style: ToastNotificationStyleType.WARNING);
razorPay.clear();
state.reloadState(showLoader: false);
});
razorPay.on(Razorpay.EVENT_EXTERNAL_WALLET,
(ExternalWalletResponse response) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Error"),
desc: trans(context, "Not supported, try a card payment"),
style: EdgeAlertStyle.WARNING);
description: trans(context, "Not supported, try a card payment"),
style: ToastNotificationStyleType.WARNING);
razorPay.clear();
state.reloadState(showLoader: false);
});

View File

@ -64,11 +64,12 @@ stripePay(context,
));
if (rsp == null) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong, please try again."),
description:
trans(context, "Something went wrong, please try again."),
icon: Icons.payment,
style: EdgeAlertStyle.WARNING);
style: ToastNotificationStyleType.WARNING);
state.reloadState(showLoader: false);
return;
}
@ -87,10 +88,10 @@ stripePay(context,
if (order != null) {
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Error"),
desc: trans(
description: trans(
context,
trans(context,
"Something went wrong, please contact our store")),
@ -101,10 +102,10 @@ stripePay(context,
if (getEnv('APP_DEBUG', defaultValue: true)) {
NyLogger.error(intentResponse.errorMessage);
}
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Error"),
desc: intentResponse.errorMessage,
description: intentResponse.errorMessage,
);
state.reloadState(showLoader: false);
} else {
@ -115,12 +116,12 @@ stripePay(context,
state.reloadState(showLoader: false);
}
} catch (ex) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong, please try again."),
description: trans(context, "Something went wrong, please try again."),
icon: Icons.payment,
style: EdgeAlertStyle.WARNING,
style: ToastNotificationStyleType.WARNING,
);
state.reloadState(showLoader: false);
}

View File

@ -13,6 +13,7 @@ import 'package:woosignal/models/response/woosignal_app.dart';
class AppHelper {
AppHelper._privateConstructor();
String themeType;
static final AppHelper instance = AppHelper._privateConstructor();
WooSignalApp appConfig;

View File

@ -15,7 +15,6 @@ import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/tax_rate.dart';
@ -50,11 +49,7 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
tmpLineItem.variationId = cartItem.variationId;
}
tmpLineItem.total =
(cartItem.quantity > 1 ? cartItem.getCartTotal() : cartItem.subtotal);
tmpLineItem.subtotal =
(parseWcPrice(cartItem.subtotal) * cartItem.quantity).toString();
tmpLineItem.subtotal = cartItem.subtotal;
lineItems.add(tmpLineItem);
});

View File

@ -0,0 +1,11 @@
// Label StoreMax
//
// Created by Anthony Gordon.
// 2021, 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 SymbolPositionType { left, right }

View File

@ -9,6 +9,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'dart:convert';
import 'package:animate_do/animate_do.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_app/app/models/billing_details.dart';
import 'package:flutter_app/app/models/cart.dart';
@ -18,18 +19,20 @@ import 'package:flutter_app/app/models/default_shipping.dart';
import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/models/user.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:flutter_app/config/app_currency.dart';
import 'package:flutter_app/config/app_payment_gateways.dart';
import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_styled_toast/flutter_styled_toast.dart';
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
import 'package:edge_alert/edge_alert.dart';
import 'package:html/parser.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:flutter_money_formatter/flutter_money_formatter.dart';
import 'package:math_expressions/math_expressions.dart';
import 'package:money_formatter/money_formatter.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:platform_alert_dialog/platform_alert_dialog.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
@ -79,92 +82,199 @@ showStatusAlert(context,
);
}
class EdgeAlertStyle {
static const int SUCCESS = 1;
static const int WARNING = 2;
static const int INFO = 3;
static const int DANGER = 4;
enum ToastNotificationStyleType {
SUCCESS,
WARNING,
INFO,
DANGER,
}
void showEdgeAlertWith(context,
{title = "",
desc = "",
int gravity = 1,
int style = 1,
IconData icon,
int duration}) {
switch (style) {
case 1: // SUCCESS
EdgeAlert.show(context,
title: title,
description: desc,
gravity: gravity,
backgroundColor: Colors.green,
icon: icon ?? Icons.check,
duration: duration ?? EdgeAlert.LENGTH_LONG);
break;
case 2: // WARNING
EdgeAlert.show(context,
title: title,
description: desc,
gravity: gravity,
backgroundColor: Colors.orange,
icon: icon ?? Icons.error_outline,
duration: duration ?? EdgeAlert.LENGTH_LONG);
break;
case 3: // INFO
EdgeAlert.show(context,
title: title,
description: desc,
gravity: gravity,
backgroundColor: Colors.teal,
icon: icon ?? Icons.info,
duration: duration ?? EdgeAlert.LENGTH_LONG);
break;
case 4: // DANGER
EdgeAlert.show(context,
title: title,
description: desc,
gravity: gravity,
backgroundColor: Colors.redAccent,
icon: icon ?? Icons.warning,
duration: duration ?? EdgeAlert.LENGTH_LONG);
break;
default:
break;
class ToastNotificationStyleMetaHelper {
static ToastMeta getValue(ToastNotificationStyleType style) {
switch (style) {
case ToastNotificationStyleType.SUCCESS:
return ToastMeta.success(action: () {
ToastManager().dismissAll(showAnim: true);
});
case ToastNotificationStyleType.WARNING:
return ToastMeta.warning(action: () {
ToastManager().dismissAll(showAnim: true);
});
case ToastNotificationStyleType.INFO:
return ToastMeta.info(action: () {
ToastManager().dismissAll(showAnim: true);
});
case ToastNotificationStyleType.DANGER:
return ToastMeta.danger(action: () {
ToastManager().dismissAll(showAnim: true);
});
default:
return ToastMeta.success(action: () {
ToastManager().dismissAll(showAnim: true);
});
}
}
}
class ToastMeta {
Widget icon;
String title;
String description;
Color color;
Function action;
Duration duration;
ToastMeta(
{this.icon,
this.title,
this.description,
this.color,
this.action,
this.duration = const Duration(seconds: 2)});
ToastMeta.success(
{this.icon = const Icon(Icons.check, color: Colors.white, size: 30),
this.title = "Success",
this.description = "",
this.color = Colors.green,
this.action,
this.duration = const Duration(seconds: 5)});
ToastMeta.info(
{this.icon = const Icon(Icons.info, color: Colors.white, size: 30),
this.title = "",
this.description = "",
this.color = Colors.teal,
this.action,
this.duration = const Duration(seconds: 5)});
ToastMeta.warning(
{this.icon =
const Icon(Icons.error_outline, color: Colors.white, size: 30),
this.title = "Oops!",
this.description = "",
this.color = Colors.orange,
this.action,
this.duration = const Duration(seconds: 6)});
ToastMeta.danger(
{this.icon = const Icon(Icons.warning, color: Colors.white, size: 30),
this.title = "Oops!",
this.description = "",
this.color = Colors.redAccent,
this.action,
this.duration = const Duration(seconds: 7)});
}
showToastNotification(BuildContext context,
{ToastNotificationStyleType style,
String title,
IconData icon,
String description = "",
Duration duration}) {
ToastMeta toastMeta = ToastNotificationStyleMetaHelper.getValue(style);
toastMeta.title = trans(context, toastMeta.title);
if (title != null) {
toastMeta.title = title;
}
toastMeta.description = description;
Widget _icon = toastMeta.icon;
if (icon != null) {
_icon = Icon(icon, color: Colors.white);
}
showToastWidget(
InkWell(
onTap: () => ToastManager().dismissAll(showAnim: true),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 18.0),
margin: EdgeInsets.symmetric(horizontal: 8.0),
height: 100,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
color: toastMeta.color,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Pulse(
child: Container(
child: Center(
child: IconButton(
onPressed: () {},
icon: _icon,
padding: EdgeInsets.only(right: 16),
),
),
),
infinite: true,
duration: Duration(milliseconds: 1500),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
toastMeta.title,
style: Theme.of(context)
.textTheme
.headline5
.copyWith(color: Colors.white),
),
Text(
toastMeta.description,
style: Theme.of(context)
.textTheme
.bodyText1
.copyWith(color: Colors.white),
),
],
),
),
],
),
),
),
context: context,
isIgnoring: false,
position: StyledToastPosition.top,
animation: StyledToastAnimation.slideFromTopFade,
duration: duration ?? toastMeta.duration,
);
}
String parseHtmlString(String htmlString) {
var document = parse(htmlString);
String parsedString = parse(document.body.text).documentElement.text;
return parsedString;
}
String formatDoubleCurrency({double total}) {
FlutterMoneyFormatter fmf = FlutterMoneyFormatter(
amount: total,
String moneyFormatter(double amount) {
MoneyFormatter fmf = MoneyFormatter(
amount: amount,
settings: MoneyFormatterSettings(
symbol: AppHelper.instance.appConfig.currencyMeta.symbolNative,
),
);
if (app_currency_symbol_position == SymbolPositionType.left) {
return fmf.output.symbolOnLeft;
} else if (app_currency_symbol_position == SymbolPositionType.right) {
return fmf.output.symbolOnRight;
}
return fmf.output.symbolOnLeft;
}
String formatDoubleCurrency({@required double total}) {
return moneyFormatter(total);
}
String formatStringCurrency({@required String total}) {
double tmpVal;
if (total == null || total == "") {
tmpVal = 0;
} else {
double tmpVal = 0;
if (total != null && total != "") {
tmpVal = parseWcPrice(total);
}
FlutterMoneyFormatter fmf = FlutterMoneyFormatter(
amount: tmpVal,
settings: MoneyFormatterSettings(
symbol: AppHelper.instance.appConfig.currencyMeta.symbolNative,
),
);
return fmf.output.symbolOnLeft;
return moneyFormatter(tmpVal);
}
String workoutSaleDiscount(
@ -562,3 +672,7 @@ Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async {
});
return shipping;
}
String truncateString(String data, int length) {
return (data.length >= length) ? '${data.substring(0, length)}...' : data;
}

View File

@ -0,0 +1,24 @@
/*
|--------------------------------------------------------------------------
| CURRENCY
|
| Configure which currency you want to use.
| Docs here: https://woosignal.com/docs/app/ios/label-storemax
|--------------------------------------------------------------------------
*/
import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
/*
|--------------------------------------------------------------------------
| APP CURRENCY
|
| Configure the currency settings. To change the currency used (e.g. "USD"),
| update the "currency" value in the WooSignal dashboard.
|--------------------------------------------------------------------------
*/
const SymbolPositionType app_currency_symbol_position = SymbolPositionType.left;
// currency_symbol_position example.
// left: $15
// right: 15

View File

@ -1,5 +1,6 @@
import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/providers/cash_on_delivery.dart';
import 'package:flutter_app/app/providers/paypal_pay.dart';
import 'package:flutter_app/app/providers/razor_pay.dart';
import 'package:flutter_app/app/providers/stripe_pay.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
@ -13,7 +14,7 @@ import 'package:flutter_app/bootstrap/helpers.dart';
|--------------------------------------------------------------------------
*/
const app_payment_gateways = ["Stripe"];
const app_payment_gateways = ["Stripe", "CashOnDelivery", "PayPal"];
// Available: "Stripe", "CashOnDelivery", "RazorPay"
// e.g. app_payment_gateways = ["Stripe", "CashOnDelivery"]; will only use Stripe and Cash on Delivery.
@ -42,10 +43,18 @@ List<PaymentType> paymentTypeList = [
pay: razorPay,
),
addPayment(
id: 4,
name: "PayPal",
desc: "Debit or Credit Card",
assetImage: "paypal_logo.png",
pay: payPalPay,
),
// e.g. add more here
// addPayment(
// id: 4,
// id: 5,
// name: "MyNewPaymentMethod",
// desc: "Debit or Credit Card",
// assetImage: "add icon image to public/assets/images/myimage.png",

View File

@ -31,6 +31,7 @@ void main() async {
if (wooSignalApp != null) {
initialRoute = "/home";
AppHelper.instance.appConfig = wooSignalApp;
AppHelper.instance.themeType = wooSignalApp.theme;
if (wooSignalApp.wpLoginEnabled == 1) {
WPJsonAPI.instance.initWith(

View File

@ -222,10 +222,10 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
billingPostcode: postalCode,
billingCountry: country));
} on Exception catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "Something went wrong"),
style: ToastNotificationStyleType.DANGER);
} finally {
setState(() {
_isUpdating = false;
@ -234,10 +234,10 @@ class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
if (wcCustomerUpdatedResponse != null &&
wcCustomerUpdatedResponse.status == 200) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Success"),
desc: trans(context, "Account updated"),
style: EdgeAlertStyle.SUCCESS);
description: trans(context, "Account updated"),
style: ToastNotificationStyleType.SUCCESS);
Navigator.pop(context);
}
}

View File

@ -72,11 +72,11 @@ class _AccountDetailPageState extends State<AccountDetailPage>
wcCustomerInfoResponse = await WPJsonAPI.instance
.api((request) => request.wcCustomerInfo(userToken));
} on Exception catch (_) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong"),
style: EdgeAlertStyle.DANGER,
description: trans(context, "Something went wrong"),
style: ToastNotificationStyleType.DANGER,
);
} finally {
setState(() {

View File

@ -163,18 +163,19 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
}
if (email == "" || password == "") {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(context, "The email and password field cannot be empty"),
style: EdgeAlertStyle.DANGER);
description:
trans(context, "The email and password field cannot be empty"),
style: ToastNotificationStyleType.DANGER);
return;
}
if (!isEmail(email)) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops"),
desc: trans(context, "That email address is not valid"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "That email address is not valid"),
style: ToastNotificationStyleType.DANGER);
return;
}
@ -188,31 +189,34 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
wpUserLoginResponse = await WPJsonAPI.instance.api(
(request) => request.wpLogin(email: email, password: password));
} on InvalidNonceException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(
description: trans(
context, "Something went wrong, please contact our store"),
style: EdgeAlertStyle.DANGER);
style: ToastNotificationStyleType.DANGER);
} on InvalidEmailException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(context, "That email does not match our records"),
style: EdgeAlertStyle.DANGER);
description:
trans(context, "That email does not match our records"),
style: ToastNotificationStyleType.DANGER);
} on InvalidUsernameException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(context, "That username does not match our records"),
style: EdgeAlertStyle.DANGER);
description:
trans(context, "That username does not match our records"),
style: ToastNotificationStyleType.DANGER);
} on IncorrectPasswordException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(context, "That password does not match our records"),
style: EdgeAlertStyle.DANGER);
description:
trans(context, "That password does not match our records"),
style: ToastNotificationStyleType.DANGER);
} on Exception catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "Invalid login credentials"),
style: EdgeAlertStyle.DANGER,
description: trans(context, "Invalid login credentials"),
style: ToastNotificationStyleType.DANGER,
icon: Icons.account_circle);
} finally {
setState(() {
@ -226,10 +230,10 @@ class _AccountLandingPageState extends State<AccountLandingPage> {
User user = User.fromUserAuthResponse(token: token, userId: userId);
user.save(SharedKey.authUser);
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Hello"),
desc: trans(context, "Welcome back"),
style: EdgeAlertStyle.SUCCESS,
description: trans(context, "Welcome back"),
style: ToastNotificationStyleType.SUCCESS,
icon: Icons.account_circle);
navigatorPush(context,
routeName: UserAuth.instance.redirect, forgetLast: 1);

View File

@ -18,10 +18,10 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:nylo_framework/widgets/stateful_page_widget.dart';
import 'package:nylo_framework/widgets/ny_stateful_widget.dart';
import 'package:woosignal/models/response/order.dart';
class AccountOrderDetailPage extends StatefulPageWidget {
class AccountOrderDetailPage extends NyStatefulWidget {
final AccountOrderDetailController controller =
AccountOrderDetailController();
AccountOrderDetailPage({Key key}) : super(key: key);

View File

@ -140,10 +140,10 @@ class _AccountProfileUpdatePageState extends State<AccountProfileUpdatePage> {
request.wpUpdateUserInfo(userToken,
firstName: firstName, lastName: lastName));
} on Exception catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(context, "Please check your email and password"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "Please check your email and password"),
style: ToastNotificationStyleType.DANGER);
} finally {
setState(() {
isLoading = false;
@ -152,10 +152,10 @@ class _AccountProfileUpdatePageState extends State<AccountProfileUpdatePage> {
if (wpUserInfoUpdatedResponse != null &&
wpUserInfoUpdatedResponse.status == 200) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Success"),
desc: trans(context, "Account updated"),
style: EdgeAlertStyle.SUCCESS);
description: trans(context, "Account updated"),
style: ToastNotificationStyleType.SUCCESS);
Navigator.pop(context);
}
}

View File

@ -148,28 +148,28 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
}
_signUpTapped() async {
String email = _tfEmailAddressController.text;
String password = _tfPasswordController.text;
String firstName = _tfFirstNameController.text;
String lastName = _tfLastNameController.text;
String email = _tfEmailAddressController.text,
password = _tfPasswordController.text,
firstName = _tfFirstNameController.text,
lastName = _tfLastNameController.text;
if (email.isNotEmpty) {
email = email.trim();
}
if (!isEmail(email)) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops"),
desc: trans(context, "That email address is not valid"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "That email address is not valid"),
style: ToastNotificationStyleType.DANGER);
return;
}
if (password.length <= 5) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops"),
desc: trans(context, "Password must be a min 6 characters"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "Password must be a min 6 characters"),
style: ToastNotificationStyleType.DANGER);
return;
}
@ -191,41 +191,41 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
),
);
} on UsernameTakenException catch (e) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, e.message),
style: EdgeAlertStyle.DANGER);
description: trans(context, e.message),
style: ToastNotificationStyleType.DANGER);
} on InvalidNonceException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Invalid details"),
desc: trans(
description: trans(
context, "Something went wrong, please contact our store"),
style: EdgeAlertStyle.DANGER);
style: ToastNotificationStyleType.DANGER);
} on ExistingUserLoginException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "A user already exists"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "A user already exists"),
style: ToastNotificationStyleType.DANGER);
} on ExistingUserEmailException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "That email is taken, try another"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "That email is taken, try another"),
style: ToastNotificationStyleType.DANGER);
} on UserAlreadyExistException catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "A user already exists"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "A user already exists"),
style: ToastNotificationStyleType.DANGER);
} on EmptyUsernameException catch (e) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, e.message),
style: EdgeAlertStyle.DANGER);
description: trans(context, e.message),
style: ToastNotificationStyleType.DANGER);
} on Exception catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "Something went wrong"),
style: ToastNotificationStyleType.DANGER);
} finally {
setState(() {
_hasTappedRegister = false;
@ -242,10 +242,10 @@ class _AccountRegistrationPageState extends State<AccountRegistrationPage> {
await WPJsonAPI.instance.api((request) => request
.wpUpdateUserInfo(token, firstName: firstName, lastName: lastName));
showEdgeAlertWith(context,
showToastNotification(context,
title: "${trans(context, "Hello")} $firstName",
desc: trans(context, "you're now logged in"),
style: EdgeAlertStyle.SUCCESS,
description: trans(context, "you're now logged in"),
style: ToastNotificationStyleType.SUCCESS,
icon: Icons.account_circle);
navigatorPush(context,
routeName: UserAuth.instance.redirect, forgetLast: 2);

View File

@ -61,11 +61,11 @@ class _AccountShippingDetailsPageState
wcCustomerInfoResponse = await WPJsonAPI.instance
.api((request) => request.wcCustomerInfo(userToken));
} on Exception catch (_) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong"),
style: EdgeAlertStyle.DANGER,
description: trans(context, "Something went wrong"),
style: ToastNotificationStyleType.DANGER,
);
Navigator.pop(context);
return;
@ -246,10 +246,10 @@ class _AccountShippingDetailsPageState
),
);
} on Exception catch (_) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops!"),
desc: trans(context, "Something went wrong"),
style: EdgeAlertStyle.DANGER);
description: trans(context, "Something went wrong"),
style: ToastNotificationStyleType.DANGER);
} finally {
setState(() {
_isUpdating = true;
@ -258,10 +258,10 @@ class _AccountShippingDetailsPageState
if (wcCustomerUpdatedResponse != null &&
wcCustomerUpdatedResponse.status == 200) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Success"),
desc: trans(context, "Account updated"),
style: EdgeAlertStyle.SUCCESS);
description: trans(context, "Account updated"),
style: ToastNotificationStyleType.SUCCESS);
Navigator.pop(context);
}
}

View File

@ -18,12 +18,12 @@ import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:nylo_framework/widgets/stateful_page_widget.dart';
import 'package:nylo_framework/widgets/ny_stateful_widget.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/products.dart' as WS;
class BrowseCategoryPage extends StatefulPageWidget {
class BrowseCategoryPage extends NyStatefulWidget {
final BrowseCategoryController controller = BrowseCategoryController();
BrowseCategoryPage({Key key}) : super(key: key);

View File

@ -14,11 +14,11 @@ import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:nylo_framework/widgets/stateful_page_widget.dart';
import 'package:nylo_framework/widgets/ny_stateful_widget.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/products.dart' as WS;
class BrowseSearchPage extends StatefulPageWidget {
class BrowseSearchPage extends NyStatefulWidget {
final BrowseSearchController controller = BrowseSearchController();
BrowseSearchPage({Key key}) : super(key: key);

View File

@ -81,11 +81,11 @@ class _CartPageState extends State<CartPage> {
}
if (cartLineItems.length <= 0) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Cart"),
desc: trans(context, "You need items in your cart to checkout"),
style: EdgeAlertStyle.WARNING,
description: trans(context, "You need items in your cart to checkout"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.shopping_cart,
);
return;
@ -93,11 +93,11 @@ class _CartPageState extends State<CartPage> {
if (!cartLineItems.every(
(c) => c.stockStatus == 'instock' || c.stockStatus == 'onbackorder')) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Cart"),
desc: trans(context, "There is an item out of stock"),
style: EdgeAlertStyle.WARNING,
description: trans(context, "There is an item out of stock"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.shopping_cart,
);
return;
@ -127,11 +127,11 @@ class _CartPageState extends State<CartPage> {
actionIncrementQuantity({CartLineItem cartLineItem}) {
if (cartLineItem.isManagedStock &&
cartLineItem.quantity + 1 > cartLineItem.stockQuantity) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Cart"),
desc: trans(context, "Maximum stock reached"),
style: EdgeAlertStyle.WARNING,
description: trans(context, "Maximum stock reached"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.shopping_cart,
);
return;
@ -155,11 +155,11 @@ class _CartPageState extends State<CartPage> {
actionRemoveItem({int index}) {
Cart.getInstance.removeCartItemForIndex(index: index);
_cartLines.removeAt(index);
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Updated"),
desc: trans(context, "Item removed"),
style: EdgeAlertStyle.WARNING,
description: trans(context, "Item removed"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.remove_shopping_cart,
);
if (_cartLines.length == 0) {
@ -171,10 +171,10 @@ class _CartPageState extends State<CartPage> {
_clearCart() {
Cart.getInstance.clear();
_cartLines = [];
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Success"),
desc: trans(context, "Cart cleared"),
style: EdgeAlertStyle.SUCCESS,
description: trans(context, "Cart cleared"),
style: ToastNotificationStyleType.SUCCESS,
icon: Icons.delete_outline);
_isCartEmpty = true;
setState(() {});

View File

@ -165,9 +165,9 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
CustomerAddress shippingAddress =
CheckoutSession.getInstance.billingDetails.shippingAddress;
if (shippingAddress == null || shippingAddress.customerCountry == null) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops"),
desc: trans(context, "Add your shipping details first"),
description: trans(context, "Add your shipping details first"),
icon: Icons.local_shipping);
return;
}
@ -362,12 +362,12 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_handleCheckout() async {
if (CheckoutSession.getInstance.billingDetails.billingAddress == null) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops"),
desc: trans(context,
description: trans(context,
"Please select add your billing/shipping address to proceed"),
style: EdgeAlertStyle.WARNING,
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping,
);
return;
@ -375,11 +375,12 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
if (CheckoutSession.getInstance.billingDetails.billingAddress
.hasMissingFields()) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops"),
desc: trans(context, "Your billing/shipping details are incomplete"),
style: EdgeAlertStyle.WARNING,
description:
trans(context, "Your billing/shipping details are incomplete"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping,
);
return;
@ -387,22 +388,24 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
if (_wooSignalApp.disableShipping == 1 &&
CheckoutSession.getInstance.shippingType == null) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops"),
desc: trans(context, "Please select a shipping method to proceed"),
style: EdgeAlertStyle.WARNING,
description:
trans(context, "Please select a shipping method to proceed"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping,
);
return;
}
if (CheckoutSession.getInstance.paymentType == null) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops"),
desc: trans(context, "Please select a payment method to proceed"),
style: EdgeAlertStyle.WARNING,
description:
trans(context, "Please select a payment method to proceed"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.payment,
);
return;
@ -419,12 +422,12 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
double.parse(CheckoutSession.getInstance.shippingType?.minimumValue);
if (doubleTotal < doubleMinimumValue) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Sorry"),
desc:
description:
"${trans(context, "Spend a minimum of")} ${formatDoubleCurrency(total: doubleMinimumValue)} ${trans(context, "for")} ${CheckoutSession.getInstance.shippingType.getTitle()}",
style: EdgeAlertStyle.INFO,
duration: 3);
style: ToastNotificationStyleType.INFO,
duration: Duration(seconds: 3));
return;
}
}
@ -432,11 +435,11 @@ class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
bool appStatus = await appWooSignal((api) => api.checkAppStatus());
if (!appStatus) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Sorry"),
desc: "${trans(context, "Retry later")}",
style: EdgeAlertStyle.INFO,
duration: 3);
description: "${trans(context, "Retry later")}",
style: ToastNotificationStyleType.INFO,
duration: Duration(seconds: 3));
return;
}

View File

@ -320,15 +320,15 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
customerCountry: _shippingCountry);
if (customerShippingAddress.hasMissingFields()) {
showEdgeAlertWith(
showToastNotification(
context,
title: trans(context, "Oops"),
desc: trans(
description: trans(
context,
trans(context,
"Invalid shipping address, please check your shipping details"),
),
style: EdgeAlertStyle.WARNING,
style: ToastNotificationStyleType.WARNING,
);
return;
}

View File

@ -36,18 +36,13 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
_CheckoutShippingTypePageState();
AppTheme _appTheme = AppTheme();
bool _isShippingSupported, _isLoading;
List<Map<String, dynamic>> _wsShippingOptions;
bool _isShippingSupported = true, _isLoading = true;
List<Map<String, dynamic>> _wsShippingOptions = [];
WSShipping _shipping;
@override
void initState() {
super.initState();
_isShippingSupported = true;
_wsShippingOptions = [];
_isLoading = true;
_getShippingMethods();
}
@ -159,7 +154,6 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
total += classTotal;
}
}
break;
default:
break;
@ -247,10 +241,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
appBar: AppBar(
backgroundColor: Colors.transparent,
title: Text(
trans(
context,
"Shipping Methods",
),
trans(context, "Shipping Methods"),
style: Theme.of(context).textTheme.headline6,
),
automaticallyImplyLeading: false,

View File

@ -16,13 +16,13 @@ import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:nylo_framework/widgets/stateful_page_widget.dart';
import 'package:nylo_framework/widgets/ny_stateful_widget.dart';
import 'package:woosignal/models/response/order.dart' as WS;
import 'package:nylo_framework/helpers/helper.dart';
import '../widgets/woosignal_ui.dart';
class CheckoutStatusPage extends StatefulPageWidget {
class CheckoutStatusPage extends NyStatefulWidget {
final CheckoutStatusController controller = CheckoutStatusController();
CheckoutStatusPage({Key key}) : super(key: key);

View File

@ -10,15 +10,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/cart_icon_widget.dart';
import 'package:flutter_app/resources/widgets/home_drawer_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/product_category.dart' as WS;
import 'package:woosignal/models/response/products.dart' as WSProduct;
import 'package:flutter_app/resources/widgets/mello_theme_widget.dart';
import 'package:flutter_app/resources/widgets/notic_theme_widget.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
class HomePage extends StatefulWidget {
@ -34,153 +27,13 @@ class _HomePageState extends State<HomePage> {
final GlobalKey _key = GlobalKey();
final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<WSProduct.Product> _products = [];
List<WS.ProductCategory> _categories = [];
int _page = 1;
bool _shouldStopRequests = false,
waitForNextRequest = false,
_isLoading = true;
@override
void initState() {
super.initState();
_home();
}
_home() async {
await _fetchMoreProducts();
await _fetchCategories();
setState(() {
_isLoading = false;
});
}
_fetchCategories() async {
_categories =
await appWooSignal((api) => api.getProductCategories(perPage: 100));
}
_fetchMoreProducts() async {
if (_shouldStopRequests) {
return;
}
if (waitForNextRequest) {
return;
}
waitForNextRequest = true;
List<WSProduct.Product> products = await appWooSignal((api) =>
api.getProducts(
perPage: 50,
page: _page,
status: "publish",
stockStatus: "instock"));
_page = _page + 1;
if (products.length == 0) {
_shouldStopRequests = true;
}
waitForNextRequest = false;
setState(() {
_products.addAll(products.toList());
});
}
_modalBottomSheetMenu() {
_key.currentState.setState(() {});
wsModalBottom(
context,
title: trans(context, "Categories"),
bodyWidget: ListView.separated(
itemCount: _categories.length,
separatorBuilder: (cxt, i) => Divider(),
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text(parseHtmlString(_categories[index].name)),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, "/browse-category",
arguments: _categories[index])
.then((value) => setState(() {}));
},
),
),
);
}
@override
Widget build(BuildContext context) {
List<String> bannerImages = _wooSignalApp.bannerImages;
return Scaffold(
drawer: HomeDrawerWidget(wooSignalApp: _wooSignalApp),
appBar: AppBar(
title: StoreLogo(height: 55),
centerTitle: true,
actions: <Widget>[
IconButton(
alignment: Alignment.centerLeft,
icon: Icon(
Icons.search,
size: 35,
),
onPressed: () => Navigator.pushNamed(context, "/home-search")
.then((value) => _key.currentState.setState(() {})),
),
CartIconWidget(key: _key),
],
),
body: SafeArea(
minimum: safeAreaDefault(),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(_isLoading
? Expanded(child: AppLoaderWidget())
: Expanded(
child: RefreshableScrollContainer(
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
products: _products,
onTap: _showProduct,
bannerHeight: MediaQuery.of(context).size.height / 3.5,
bannerImages: bannerImages,
modalBottomSheetMenu: _modalBottomSheetMenu,
),
flex: 1,
)),
],
),
),
);
}
_onRefresh() async {
_products = [];
_page = 1;
_shouldStopRequests = false;
waitForNextRequest = false;
await _fetchMoreProducts();
_refreshController.refreshCompleted();
}
_onLoading() async {
await _fetchMoreProducts();
if (mounted) {
setState(() {});
if (_shouldStopRequests) {
_refreshController.loadNoData();
} else {
_refreshController.loadComplete();
}
Widget theme =
MelloThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp);
if (AppHelper.instance.themeType == "notic") {
theme = NoticThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp);
}
return theme;
}
_showProduct(WSProduct.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.
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:nylo_framework/helpers/helper.dart';
@ -36,7 +37,9 @@ class _HomeSearchPageState extends State<HomeSearchPage> {
Navigator.pushNamed(context, "/product-search",
arguments: _txtSearchController.text)
.then((search) {
Navigator.pop(context);
if (AppHelper.instance.themeType != "notic") {
Navigator.pop(context);
}
});
}

View File

@ -68,7 +68,8 @@ class _NoConnectionPageState extends State<NoConnectionPage> {
Navigator.pushNamed(context, "/home");
return;
}
showEdgeAlertWith(context,
title: trans(context, "Oops"), desc: trans(context, "Retry later"));
showToastNotification(context,
title: trans(context, "Oops"),
description: trans(context, "Retry later"));
}
}

View File

@ -23,12 +23,12 @@ import 'package:flutter_app/resources/widgets/cart_icon_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:nylo_framework/widgets/stateful_page_widget.dart';
import 'package:nylo_framework/widgets/ny_stateful_widget.dart';
import 'package:woosignal/models/response/product_variation.dart' as WS;
import 'package:woosignal/models/response/products.dart' as WSProduct;
import 'package:flutter_swiper/flutter_swiper.dart';
class ProductDetailPage extends StatefulPageWidget {
class ProductDetailPage extends NyStatefulWidget {
final ProductDetailController controller = ProductDetailController();
ProductDetailPage({Key key}) : super(key: key);
@ -205,29 +205,30 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
action: () {
if (_product.attributes.length !=
_tmpAttributeObj.values.length) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops"),
desc:
description:
trans(context, "Please select valid options first"),
style: EdgeAlertStyle.WARNING);
style: ToastNotificationStyleType.WARNING);
return;
}
WS.ProductVariation productVariation = findProductVariation();
if (productVariation == null) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Oops"),
desc:
description:
trans(context, "Product variation does not exist"),
style: EdgeAlertStyle.WARNING);
style: ToastNotificationStyleType.WARNING);
return;
}
if (productVariation.stockStatus != "instock") {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Sorry"),
desc: trans(context, "This item is not in stock"),
style: EdgeAlertStyle.WARNING);
description:
trans(context, "This item is not in stock"),
style: ToastNotificationStyleType.WARNING);
return;
}
@ -551,10 +552,10 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
return;
}
if (_product.stockStatus != "instock") {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Sorry"),
desc: trans(context, "This item is out of stock"),
style: EdgeAlertStyle.WARNING,
description: trans(context, "This item is out of stock"),
style: ToastNotificationStyleType.WARNING,
icon: Icons.local_shipping);
return;
}
@ -580,11 +581,11 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
_addQuantityTapped() {
if (_product.manageStock != null && _product.manageStock == true) {
if (_quantityIndicator >= _product.stockQuantity) {
showEdgeAlertWith(context,
showToastNotification(context,
title: trans(context, "Maximum quantity reached"),
desc:
description:
"${trans(context, "Sorry, only")} ${_product.stockQuantity} ${trans(context, "left")}",
style: EdgeAlertStyle.INFO);
style: ToastNotificationStyleType.INFO);
return;
}
}

View File

@ -16,9 +16,9 @@ import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:nylo_framework/widgets/stateful_page_widget.dart';
import 'package:nylo_framework/widgets/ny_stateful_widget.dart';
class ProductImageViewerPage extends StatefulPageWidget {
class ProductImageViewerPage extends NyStatefulWidget {
final ProductImageViewerController controller =
ProductImageViewerController();
ProductImageViewerPage({Key key}) : super(key: key);

View File

@ -20,8 +20,8 @@ class AppLoaderWidget extends StatelessWidget {
Widget build(BuildContext context) {
AdaptiveThemeMode adaptiveThemeMode = AdaptiveTheme.of(context).mode;
return SpinKitDoubleBounce(
color: adaptiveThemeMode.isLight
? HexColor("#424242")
: HexColor("#c7c7c7"));
color:
adaptiveThemeMode.isLight ? HexColor("#424242") : HexColor("#c7c7c7"),
);
}
}

View File

@ -0,0 +1,156 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/app/models/customer_address.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'dart:async';
import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:nylo_framework/widgets/ny_state.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
class PayPalCheckout extends StatefulWidget {
final String description;
final String amount;
final List<CartLineItem> cartLineItems;
PayPalCheckout({this.description, this.amount, this.cartLineItems});
@override
WebViewState createState() => WebViewState();
}
class WebViewState extends NyState<PayPalCheckout> {
final flutterWebViewPlugin = new FlutterWebviewPlugin();
String payerId = '';
int intCount = 0;
StreamSubscription<String> _onUrlChanged;
WooSignalApp _wooSignalApp = AppHelper.instance.appConfig;
String formCheckoutShippingAddress;
setCheckoutShippingAddress(CustomerAddress customerAddress) {
String tmp = "";
if (customerAddress.firstName != null) {
tmp +=
'<input type="hidden" name="first_name" value="${customerAddress.firstName}">\n';
}
if (customerAddress.lastName != null) {
tmp +=
'<input type="hidden" name="last_name" value="${customerAddress.lastName}">\n';
}
if (customerAddress.addressLine != null) {
tmp +=
'<input type="hidden" name="address1" value="${customerAddress.addressLine}">\n';
}
if (customerAddress.city != null) {
tmp +=
'<input type="hidden" name="city" value="${customerAddress.city}">\n';
}
if (customerAddress.customerCountry.hasState() &&
customerAddress.customerCountry.state.name != null) {
tmp +=
'<input type="hidden" name="state" value="${customerAddress.customerCountry.state.name}">\n';
}
if (customerAddress.postalCode != null) {
tmp +=
'<input type="hidden" name="zip" value="${customerAddress.postalCode}">\n';
}
if (customerAddress.customerCountry.countryCode != null) {
tmp +=
'<input type="hidden" name="country" value="${customerAddress.customerCountry.countryCode}">\n';
}
formCheckoutShippingAddress = tmp;
}
String getPayPalItemName() {
return truncateString(widget.description, 124);
}
String getPayPalPaymentType() {
return Platform.isAndroid ? "PayPal - Android App" : "PayPal - IOS App";
}
String getPayPalUrl() {
bool liveMode = getEnv('PAYPAL_LIVE_MODE', defaultValue: false);
return liveMode == true
? "https://www.paypal.com/cgi-bin/webscr"
: "https://www.sandbox.paypal.com/cgi-bin/webscr";
}
@override
void initState() {
super.initState();
setCheckoutShippingAddress(
CheckoutSession.getInstance.billingDetails.shippingAddress);
setState(() {});
_onUrlChanged = flutterWebViewPlugin.onUrlChanged.listen((String url) {
if (intCount > 0) {
url = url.replaceAll("~", "_");
}
intCount = intCount + 1;
if (url.contains("payment_success")) {
var uri = Uri.dataFromString(url);
setState(() {
payerId = uri.queryParameters['PayerID'];
});
Navigator.pop(context, {"status": "success", "payerId": payerId});
} else if (url.contains("payment_failure")) {
Navigator.pop(context, {"status": "cancelled"});
}
});
}
@override
void dispose() {
_onUrlChanged.cancel();
flutterWebViewPlugin.dispose();
super.dispose();
}
String _loadHTML() {
return '''
<html><head><title>${trans(context, "Processing Payment")}...</title></head>
<body onload="document.forms['paypal_form'].submit();">
<div style="text-align:center;">
<img src="https://woosignal.com/images/paypal_logo.png" height="50" />
</div>
<center><h4>${trans(context, "Please wait, your order is being processed and you will be redirected to the PayPal website.")}</h4></center>
<form method="post" name="paypal_form" action="${getPayPalUrl()}">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="amount" value="${widget.amount}">
<input type="hidden" name="currency_code" value="${_wooSignalApp.currencyMeta.code}">
<input type="hidden" name="business" value="${getEnv('PAYPAL_ACCOUNT_EMAIL')}">
<input type="hidden" name="return" value="https://woosignal.com/paypal/payment~success">
<input type="hidden" name="cancel_return" value="https://woosignal.com/paypal/payment~failure">
<input type="hidden" name="item_name" value="${getPayPalItemName()}">
<input type="hidden" name="custom" value="${getPayPalPaymentType()}">
<input type="hidden" name="address_override" value="1">
$formCheckoutShippingAddress
<center><br><br>${trans(context, "If you are not automatically redirected to PayPal within 5 seconds")}...<br><br>
<input type="submit" value="Click Here"></center>
</form></body></html>
''';
}
@override
Widget build(BuildContext context) {
return WebviewScaffold(
url: Uri.dataFromString(_loadHTML(), mimeType: 'text/html').toString(),
appBar: AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
title: Text(
trans(context, "PayPal Checkout"),
textAlign: TextAlign.center,
),
),
);
}
}

View File

@ -87,14 +87,19 @@ class _HomeDrawerWidgetState extends State<HomeDrawerWidget> {
onTap: _actionPrivacy,
),
ListTile(
title: Text(adaptiveTheme.isDark
? trans(context, "Light Mode")
: trans(context, "Dark Mode")),
title: Text(
adaptiveTheme.isDark
? trans(context, "Light Mode")
: trans(context, "Dark Mode"),
),
leading: Icon(Icons.brightness_4_rounded),
onTap: () {
setState(() {
AdaptiveTheme.of(context).toggleThemeMode();
});
if (adaptiveTheme.isDark) {
AdaptiveTheme.of(context).setLight();
} else {
AdaptiveTheme.of(context).setDark();
}
setState(() {});
},
),
ListTile(

View File

@ -0,0 +1,174 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/cart_icon_widget.dart';
import 'package:flutter_app/resources/widgets/home_drawer_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/models/response/product_category.dart' as WS;
import 'package:woosignal/models/response/products.dart' as WSProduct;
class MelloThemeWidget extends StatefulWidget {
MelloThemeWidget(
{Key key, @required this.globalKey, @required this.wooSignalApp})
: super(key: key);
final GlobalKey globalKey;
final WooSignalApp wooSignalApp;
@override
_MelloThemeWidgetState createState() => _MelloThemeWidgetState();
}
class _MelloThemeWidgetState extends State<MelloThemeWidget> {
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<WSProduct.Product> _products = [];
List<WS.ProductCategory> _categories = [];
int _page = 1;
bool _shouldStopRequests = false,
waitForNextRequest = false,
_isLoading = true;
@override
void initState() {
super.initState();
_home();
}
_home() async {
await _fetchMoreProducts();
await _fetchCategories();
setState(() {
_isLoading = false;
});
}
_fetchCategories() async {
_categories =
await appWooSignal((api) => api.getProductCategories(perPage: 100));
}
_fetchMoreProducts() async {
if (_shouldStopRequests) {
return;
}
if (waitForNextRequest) {
return;
}
waitForNextRequest = true;
List<WSProduct.Product> products = await appWooSignal((api) =>
api.getProducts(
perPage: 50,
page: _page,
status: "publish",
stockStatus: "instock"));
_page = _page + 1;
if (products.length == 0) {
_shouldStopRequests = true;
}
waitForNextRequest = false;
setState(() {
_products.addAll(products.toList());
});
}
_modalBottomSheetMenu() {
widget.globalKey.currentState.setState(() {});
wsModalBottom(
context,
title: trans(context, "Categories"),
bodyWidget: ListView.separated(
itemCount: _categories.length,
separatorBuilder: (cxt, i) => Divider(),
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text(parseHtmlString(_categories[index].name)),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, "/browse-category",
arguments: _categories[index])
.then((value) => setState(() {}));
},
),
),
);
}
@override
Widget build(BuildContext context) {
List<String> bannerImages = widget.wooSignalApp.bannerImages;
return Scaffold(
drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp),
appBar: AppBar(
title: StoreLogo(height: 55),
centerTitle: true,
actions: <Widget>[
IconButton(
alignment: Alignment.centerLeft,
icon: Icon(
Icons.search,
size: 35,
),
onPressed: () => Navigator.pushNamed(context, "/home-search")
.then((value) => widget.globalKey.currentState.setState(() {})),
),
CartIconWidget(key: widget.globalKey),
],
),
body: SafeArea(
minimum: safeAreaDefault(),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(_isLoading
? Expanded(child: AppLoaderWidget())
: Expanded(
child: RefreshableScrollContainer(
controller: _refreshController,
onRefresh: _onRefresh,
onLoading: _onLoading,
products: _products,
onTap: _showProduct,
bannerHeight: MediaQuery.of(context).size.height / 3.5,
bannerImages: bannerImages,
modalBottomSheetMenu: _modalBottomSheetMenu,
),
flex: 1,
)),
],
),
),
);
}
_onRefresh() async {
_products = [];
_page = 1;
_shouldStopRequests = false;
waitForNextRequest = false;
await _fetchMoreProducts();
_refreshController.refreshCompleted();
}
_onLoading() async {
await _fetchMoreProducts();
if (mounted) {
setState(() {});
if (_shouldStopRequests) {
_refreshController.loadNoData();
} else {
_refreshController.loadComplete();
}
}
}
_showProduct(WSProduct.Product product) =>
Navigator.pushNamed(context, "/product-detail", arguments: product)
.then((value) => widget.globalKey.currentState.setState(() {}));
}

View File

@ -0,0 +1,257 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/cached_image_widget.dart';
import 'package:flutter_app/resources/widgets/home_drawer_widget.dart';
import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_swiper/flutter_swiper.dart';
import 'package:nylo_framework/helpers/helper.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/models/response/product_category.dart' as WS;
import 'package:woosignal/models/response/products.dart' as WSProduct;
class NoticHomeWidget extends StatefulWidget {
NoticHomeWidget({Key key, @required this.wooSignalApp}) : super(key: key);
final WooSignalApp wooSignalApp;
@override
_NoticHomeWidgetState createState() => _NoticHomeWidgetState();
}
class _NoticHomeWidgetState extends State<NoticHomeWidget> {
Widget activeWidget;
RefreshController _refreshController =
RefreshController(initialRefresh: false);
List<WSProduct.Product> _products = [];
List<WS.ProductCategory> _categories = [];
int _page = 1;
bool _shouldStopRequests = false,
waitForNextRequest = false,
_isLoading = true;
@override
void initState() {
super.initState();
_home();
}
_home() async {
await _fetchMoreProducts();
await _fetchCategories();
setState(() {
_isLoading = false;
});
}
_fetchCategories() async {
_categories =
await appWooSignal((api) => api.getProductCategories(perPage: 100));
}
_fetchMoreProducts() async {
if (_shouldStopRequests) {
return;
}
if (waitForNextRequest) {
return;
}
waitForNextRequest = true;
List<WSProduct.Product> products = await appWooSignal((api) =>
api.getProducts(
perPage: 50,
page: _page,
status: "publish",
stockStatus: "instock"));
_page = _page + 1;
if (products.length == 0) {
_shouldStopRequests = true;
}
waitForNextRequest = false;
setState(() {
_products.addAll(products.toList());
});
}
_modalBottomSheetMenu() {
wsModalBottom(
context,
title: trans(context, "Categories"),
bodyWidget: ListView.separated(
itemCount: _categories.length,
separatorBuilder: (cxt, i) => Divider(),
itemBuilder: (BuildContext context, int index) => ListTile(
title: Text(parseHtmlString(_categories[index].name)),
onTap: () {
Navigator.pop(context);
Navigator.pushNamed(context, "/browse-category",
arguments: _categories[index])
.then((value) => setState(() {}));
},
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp),
appBar: AppBar(
title: StoreLogo(height: 55),
centerTitle: true,
actions: [
Center(
child: Container(
margin: EdgeInsets.only(right: 8),
child: InkWell(
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
onTap: _modalBottomSheetMenu,
child: Text(
trans(context, "Categories"),
),
),
),
),
],
),
body: SafeArea(
minimum: safeAreaDefault(),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
(_isLoading
? Expanded(child: AppLoaderWidget())
: Expanded(
child: ListView(
shrinkWrap: true,
children: [
Container(
margin: EdgeInsets.only(bottom: 15),
child: Swiper(
itemBuilder: (BuildContext context, int index) {
return CachedImageWidget(
image: widget.wooSignalApp.bannerImages[index],
fit: BoxFit.cover,
);
},
itemCount: widget.wooSignalApp.bannerImages.length,
viewportFraction: 0.8,
scale: 0.9,
),
height: MediaQuery.of(context).size.height / 2.5,
),
Container(
height: 80,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(trans(context, "Must have")),
Text(
trans(context, "Our selection of new items"),
style: Theme.of(context).textTheme.headline4,
)
],
),
),
Container(
height: 250,
child: SmartRefresher(
enablePullDown: true,
enablePullUp: true,
footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) {
Widget body;
if (mode == LoadStatus.idle) {
body = Text(trans(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
? StaggeredGridView.countBuilder(
crossAxisCount: 2,
scrollDirection: Axis.horizontal,
itemCount: _products.length,
itemBuilder:
(BuildContext context, int index) {
return Container(
height: 250,
child: ProductItemContainer(
index: index,
product: _products[index],
onTap: _showProduct,
),
);
},
staggeredTileBuilder: (int index) {
return new StaggeredTile.fit(2);
},
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
)
: NoResultsForProductsWidget()),
),
)
],
),
flex: 1,
)),
],
),
),
);
}
_onRefresh() async {
_products = [];
_page = 1;
_shouldStopRequests = false;
waitForNextRequest = false;
await _fetchMoreProducts();
_refreshController.refreshCompleted();
}
_onLoading() async {
await _fetchMoreProducts();
if (mounted) {
setState(() {});
if (_shouldStopRequests) {
_refreshController.loadNoData();
} else {
_refreshController.loadComplete();
}
}
}
_showProduct(WSProduct.Product product) =>
Navigator.pushNamed(context, "/product-detail", arguments: product);
}

View File

@ -0,0 +1,95 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/resources/pages/account_landing.dart';
import 'package:flutter_app/resources/pages/cart.dart';
import 'package:flutter_app/resources/pages/home_search.dart';
import 'package:flutter_app/resources/widgets/notic_home_widget.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
class NoticThemeWidget extends StatefulWidget {
NoticThemeWidget(
{Key key, @required this.globalKey, @required this.wooSignalApp})
: super(key: key);
final GlobalKey globalKey;
final WooSignalApp wooSignalApp;
@override
_NoticThemeWidgetState createState() => _NoticThemeWidgetState();
}
class _NoticThemeWidgetState extends State<NoticThemeWidget> {
Widget activeWidget;
int _currentIndex = 0;
@override
void initState() {
super.initState();
_changeMainWidget();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: activeWidget,
bottomNavigationBar: BottomNavigationBar(
onTap: _onTabTapped,
currentIndex: _currentIndex,
unselectedItemColor: Colors.black54,
fixedColor: Colors.black87,
selectedLabelStyle: TextStyle(color: Colors.black),
unselectedLabelStyle: TextStyle(
color: Colors.black87,
),
showSelectedLabels: false,
showUnselectedLabels: false,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Search',
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_cart), label: 'Cart'),
if (AppHelper.instance.appConfig.wpLoginEnabled == 1)
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Account')
],
),
);
}
_onTabTapped(int i) {
_currentIndex = i;
_changeMainWidget();
setState(() {});
}
_changeMainWidget() {
switch (_currentIndex) {
case 0:
{
activeWidget = NoticHomeWidget(wooSignalApp: widget.wooSignalApp);
break;
}
case 1:
{
activeWidget = HomeSearchPage();
break;
}
case 2:
{
activeWidget = CartPage();
break;
}
case 3:
{
activeWidget = AccountLandingPage();
break;
}
}
}
}

View File

@ -12,6 +12,7 @@ import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/app/models/checkout_session.dart';

View File

@ -19,6 +19,7 @@ import 'package:flutter_app/resources/pages/home_search.dart';
import 'package:flutter_app/resources/pages/no_connection_page.dart';
import 'package:flutter_app/resources/pages/product_detail.dart';
import 'package:flutter_app/resources/pages/product_image_viewer_page.dart';
import 'package:flutter_app/resources/widgets/checkout_paypal.dart';
import 'package:nylo_framework/router/router.dart';
import 'package:page_transition/page_transition.dart';
@ -68,6 +69,8 @@ buildRouter() => nyCreateRoutes((router) {
router.route("/home-search", (context) => HomeSearchPage(),
transition: PageTransitionType.bottomToTop);
router.route('/paypal', (context) => PayPalCheckout());
router.route("/customer-countries", (context) => CustomerCountriesPage(),
transition: PageTransitionType.bottomToTop);

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,34 +1,48 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
_fe_analyzer_shared:
dependency: transitive
description:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "20.0.0"
adaptive_theme:
dependency: "direct main"
description:
name: adaptive_theme
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "2.1.1"
analyzer:
dependency: "direct main"
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.38.5"
version: "1.4.0"
animate_do:
dependency: "direct main"
description:
name: animate_do
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
version: "3.1.2"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
version: "2.0.0"
async:
dependency: transitive
description:
@ -63,7 +77,7 @@ packages:
name: cached_network_image
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.1"
version: "3.0.0"
characters:
dependency: transitive
description:
@ -78,6 +92,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
cli_util:
dependency: transitive
description:
name: cli_util
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
clock:
dependency: transitive
description:
@ -98,21 +119,21 @@ packages:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "3.0.0"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
version: "3.0.1"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.16.1"
version: "0.17.0"
cupertino_icons:
dependency: "direct main"
description:
@ -120,48 +141,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
device_info:
dependency: transitive
description:
name: device_info
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "2.0.0"
device_info_platform_interface:
dependency: transitive
description:
name: device_info_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "2.0.1"
dio:
dependency: transitive
description:
name: dio
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.10"
edge_alert:
dependency: "direct main"
description:
name: edge_alert
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1"
equatable:
dependency: transitive
description:
name: equatable
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.5"
version: "4.0.0"
eventify:
dependency: transitive
description:
@ -209,53 +209,39 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_application_id:
dependency: "direct dev"
description:
name: flutter_application_id
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
flutter_blurhash:
dependency: transitive
description:
name: flutter_blurhash
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.0"
version: "0.6.0"
flutter_cache_manager:
dependency: transitive
description:
name: flutter_cache_manager
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "3.0.1"
flutter_dotenv:
dependency: transitive
description:
name: flutter_dotenv
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "4.0.0-nullsafety.0"
flutter_launcher_icons:
dependency: "direct main"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.1"
version: "0.9.0"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_money_formatter:
dependency: "direct main"
description:
name: flutter_money_formatter
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.3"
flutter_page_indicator:
dependency: transitive
description:
@ -269,7 +255,7 @@ packages:
name: flutter_secure_storage
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.5"
version: "4.1.0"
flutter_spinkit:
dependency: "direct main"
description:
@ -284,6 +270,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.4"
flutter_styled_toast:
dependency: "direct main"
description:
name: flutter_styled_toast
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
flutter_swiper:
dependency: "direct main"
description:
@ -308,34 +301,27 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
front_end:
dependency: transitive
flutter_webview_plugin:
dependency: "direct main"
description:
name: front_end
name: flutter_webview_plugin
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.27"
version: "0.3.11"
glob:
dependency: transitive
description:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "2.0.1"
google_fonts:
dependency: "direct main"
description:
name: google_fonts
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
grapheme_splitter:
dependency: transitive
description:
name: grapheme_splitter
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "2.0.0"
hexcolor:
dependency: "direct main"
description:
@ -349,28 +335,28 @@ packages:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.14.0+4"
version: "0.15.0"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
version: "0.13.1"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
version: "4.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.19"
version: "3.0.2"
intl:
dependency: "direct main"
description:
@ -385,34 +371,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
json_ast:
dependency: transitive
description:
name: json_ast
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
json_to_dart:
dependency: transitive
description:
name: json_to_dart
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
kernel:
dependency: transitive
description:
name: kernel
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.27"
logger:
dependency: transitive
description:
name: logger
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4"
version: "1.0.0"
matcher:
dependency: transitive
description:
@ -434,41 +399,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
node_interop:
dependency: transitive
money_formatter:
dependency: "direct main"
description:
name: node_interop
name: money_formatter
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "0.0.3"
nylo_framework:
dependency: "direct main"
description:
name: nylo_framework
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0+1"
version: "0.8.2"
octo_image:
dependency: transitive
description:
name: octo_image
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.0"
version: "1.0.0+1"
package_config:
dependency: transitive
description:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
version: "2.0.0"
package_info:
dependency: "direct main"
description:
@ -482,7 +440,7 @@ packages:
name: page_transition
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.7+6"
version: "2.0.1-nullsafety.0"
path:
dependency: transitive
description:
@ -496,49 +454,49 @@ packages:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.27"
version: "2.0.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+2"
version: "2.0.0"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+3"
version: "2.0.0"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "2.0.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.5"
version: "2.0.0"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.0"
version: "1.11.0"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.4"
version: "4.1.0"
platform:
dependency: transitive
description:
@ -559,21 +517,21 @@ packages:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "2.0.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
version: "4.2.1"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.4"
version: "2.0.0"
pull_to_refresh:
dependency: "direct main"
description:
@ -587,7 +545,7 @@ packages:
name: queue
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7+2"
version: "3.1.0"
razorpay_flutter:
dependency: "direct main"
description:
@ -601,49 +559,49 @@ packages:
name: rxdart
url: "https://pub.dartlang.org"
source: hosted
version: "0.25.0"
version: "0.26.0"
shared_preferences:
dependency: transitive
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.12+4"
version: "2.0.5"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2+4"
version: "2.0.0"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+10"
version: "2.0.0"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "2.0.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2+7"
version: "2.0.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2+3"
version: "2.0.0"
sky_engine:
dependency: transitive
description: flutter
@ -662,7 +620,7 @@ packages:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0+2"
version: "2.0.0+3"
sqflite_common:
dependency: transitive
description:
@ -739,7 +697,7 @@ packages:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.2"
version: "3.0.4"
vector_math:
dependency: transitive
description:
@ -753,21 +711,21 @@ packages:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.7+15"
version: "1.0.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
version: "2.0.5"
woosignal:
dependency: "direct main"
description:
name: woosignal
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.1+1"
version: "2.0.2"
woosignal_stripe:
dependency: "direct main"
description:
@ -781,28 +739,28 @@ packages:
name: wp_json_api
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
version: "3.0.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.2.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.0"
version: "5.1.0"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "3.1.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=2.0.0"

View File

@ -1,7 +1,7 @@
# Official WooSignal App Template for WooCommerce
# Label StoreMax
# Version: 4.0.0
# Version: 5.0.0
# Author: Anthony Gordon
# Homepage: https://woosignal.com
# Documentation: https://woosignal.com/docs/app/ios/label-storemax
@ -25,32 +25,34 @@ environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
google_fonts: ^1.1.2
analyzer: ^0.38.2
adaptive_theme: ^1.1.0
google_fonts: ^2.0.0
analyzer: ^1.3.0
adaptive_theme: ^2.0.0
intl: ^0.17.0
page_transition: ^1.1.7+6
nylo_framework: ^0.7.0+1
woosignal: ^1.5.1+1
page_transition: ^2.0.1-nullsafety.0
nylo_framework: ^0.8.2
woosignal: ^2.0.2
woosignal_stripe: ^0.1.0
razorpay_flutter: ^1.2.5
wp_json_api: ^2.0.0
cached_network_image: ^2.5.0
wp_json_api: ^3.0.0
cached_network_image: ^3.0.0
package_info: ^2.0.0
flutter_money_formatter: ^0.8.3
money_formatter: ^0.0.3
platform_alert_dialog: ^1.0.0+2
flutter_web_browser: ^0.14.0
flutter_webview_plugin: ^0.3.11
pull_to_refresh: 1.6.4
flutter_swiper: ^1.1.6
edge_alert: ^0.0.1
flutter_styled_toast: ^2.0.0
animate_do: ^2.0.0
bubble_tab_indicator: ^0.1.5
status_alert: ^0.1.3
math_expressions: ^2.1.0
hexcolor: ^2.0.3
flutter_spinkit: ^5.0.0
flutter_launcher_icons: ^0.8.1
flutter_launcher_icons: ^0.9.0
auto_size_text: ^2.1.0
html: ^0.14.0+4
html: ^0.15.0
flutter_staggered_grid_view: ^0.3.4
flutter:
sdk: flutter
@ -62,7 +64,6 @@ dependencies:
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_application_id: "^1.0.0"
flutter_test:
sdk: flutter
@ -73,7 +74,7 @@ flutter_icons:
image_path: "public/assets/app_icon/appicon.png"
dependency_overrides:
intl: ^0.17.0-nullsafety.2
intl: ^0.17.0
flutter:
@ -91,6 +92,7 @@ flutter:
- public/assets/images/dark_powered_by_stripe.png
- public/assets/images/cash_on_delivery.jpeg
- public/assets/images/razorpay.png
- public/assets/images/paypal_logo.png
- public/assets/json/default_shipping.json
- lang/en.json
- lang/es.json