From 5c4addcc6651e445d9dc7a3671e02083f24dafb3 Mon Sep 17 00:00:00 2001 From: Anthony Date: Mon, 3 Jan 2022 17:58:52 +0000 Subject: [PATCH] v5.6.0 - update --- LabelStoreMax/.env | 2 +- LabelStoreMax/CHANGELOG.md | 12 + LabelStoreMax/LICENSE | 2 +- LabelStoreMax/README.md | 2 +- LabelStoreMax/analysis_options.yaml | 30 + LabelStoreMax/lang/de.json | 21 +- LabelStoreMax/lang/en.json | 21 +- LabelStoreMax/lang/es.json | 21 +- LabelStoreMax/lang/fr.json | 21 +- LabelStoreMax/lang/hi.json | 21 +- LabelStoreMax/lang/it.json | 21 +- LabelStoreMax/lang/nl.json | 214 ++++++++ LabelStoreMax/lang/pt.json | 21 +- LabelStoreMax/lang/tr.json | 214 ++++++++ LabelStoreMax/lang/zh.json | 21 +- .../account_order_detail_controller.dart | 2 +- .../browse_category_controller.dart | 2 +- .../controllers/browse_search_controller.dart | 2 +- .../checkout_status_controller.dart | 2 +- .../lib/app/controllers/controller.dart | 8 +- .../customer_orders_loader_controller.dart | 29 + ...uct_category_search_loader_controller.dart | 34 ++ .../product_detail_controller.dart | 2 +- .../product_image_viewer_controller.dart | 2 +- .../product_loader_controller.dart | 32 ++ .../product_search_loader_controller.dart | 34 ++ .../woosignal_api_loader_controller.dart | 53 ++ .../lib/app/models/billing_details.dart | 2 +- .../lib/app/models/bottom_nav_item.dart | 19 + LabelStoreMax/lib/app/models/cart.dart | 108 +++- .../lib/app/models/cart_line_item.dart | 66 ++- .../lib/app/models/checkout_session.dart | 5 +- .../lib/app/models/customer_address.dart | 49 +- .../lib/app/models/customer_country.dart | 15 +- .../lib/app/models/default_shipping.dart | 8 +- .../lib/app/models/payment_type.dart | 2 +- .../lib/app/models/shipping_type.dart | 38 +- LabelStoreMax/lib/app/models/user.dart | 8 +- .../lib/app/networking/api_service.dart | 2 +- .../lib/app/providers/cash_on_delivery.dart | 2 +- .../lib/app/providers/example_pay.dart | 2 +- .../lib/app/providers/paypal_pay.dart | 42 +- .../lib/app/providers/stripe_pay.dart | 37 +- LabelStoreMax/lib/bootstrap/app.dart | 17 +- LabelStoreMax/lib/bootstrap/app_helper.dart | 2 +- .../lib/bootstrap/base_theme_config.dart | 17 +- LabelStoreMax/lib/bootstrap/boot.dart | 12 +- .../lib/bootstrap/data/order_wc.dart | 19 +- .../lib/bootstrap/enums/sort_enums.dart | 10 +- .../enums/symbol_position_enums.dart | 2 +- LabelStoreMax/lib/bootstrap/helpers.dart | 113 ++-- .../lib/bootstrap/shared_pref/shared_key.dart | 3 +- .../lib/bootstrap/shared_pref/sp_auth.dart | 2 +- LabelStoreMax/lib/config/app_font.dart | 2 +- .../lib/config/app_localization.dart | 2 +- LabelStoreMax/lib/config/app_theme.dart | 43 +- .../lib/generated_plugin_registrant.dart | 20 + LabelStoreMax/lib/main.dart | 4 +- .../pages/account_billing_details.dart | 17 +- .../lib/resources/pages/account_detail.dart | 131 +++-- .../lib/resources/pages/account_landing.dart | 52 +- .../resources/pages/account_order_detail.dart | 23 +- .../pages/account_profile_update.dart | 4 +- .../lib/resources/pages/account_register.dart | 31 +- .../pages/account_shipping_details.dart | 17 +- .../lib/resources/pages/browse_category.dart | 115 ++-- .../lib/resources/pages/browse_search.dart | 88 ++- LabelStoreMax/lib/resources/pages/cart.dart | 20 +- .../pages/checkout_confirmation.dart | 372 +++++-------- .../lib/resources/pages/checkout_details.dart | 25 +- .../pages/checkout_payment_type.dart | 120 ++-- .../pages/checkout_shipping_type.dart | 31 +- .../lib/resources/pages/checkout_status.dart | 24 +- .../lib/resources/pages/coupon_page.dart | 223 ++++++++ .../resources/pages/customer_countries.dart | 29 +- LabelStoreMax/lib/resources/pages/home.dart | 6 +- .../lib/resources/pages/home_search.dart | 7 +- .../resources/pages/no_connection_page.dart | 9 +- .../lib/resources/pages/product_detail.dart | 137 ++--- .../pages/product_image_viewer_page.dart | 10 +- .../resources/pages/wishlist_page_widget.dart | 150 +++++ .../lib/resources/themes/dark_theme.dart | 18 +- .../lib/resources/themes/light_theme.dart | 17 +- .../resources/themes/styles/base_styles.dart | 2 +- .../themes/styles/dark_theme_colors.dart | 36 +- .../themes/styles/light_theme_colors.dart | 34 +- .../resources/widgets/app_loader_widget.dart | 6 +- .../resources/widgets/app_version_widget.dart | 5 +- .../lib/resources/widgets/buttons.dart | 17 +- .../widgets/cached_image_widget.dart | 11 +- .../resources/widgets/cart_icon_widget.dart | 4 +- .../category_subcategory_scroll_widget.dart | 15 + .../checkout_coupon_amount_widget.dart | 42 ++ .../widgets/checkout_payment_type_widget.dart | 43 ++ .../resources/widgets/checkout_paypal.dart | 47 +- .../checkout_select_coupon_widget.dart | 80 +++ .../checkout_shipping_type_widget.dart | 54 ++ .../checkout_store_heading_widget.dart | 23 + .../widgets/checkout_user_details_widget.dart | 45 ++ .../resources/widgets/compo_home_widget.dart | 186 +++++++ .../resources/widgets/compo_theme_widget.dart | 143 +++++ .../widgets/customer_address_input.dart | 2 +- .../resources/widgets/home_drawer_widget.dart | 161 ++++-- .../resources/widgets/mello_theme_widget.dart | 91 ++- .../no_results_for_products_widget.dart | 2 +- .../resources/widgets/notic_home_widget.dart | 132 ++--- .../resources/widgets/notic_theme_widget.dart | 23 +- .../resources/widgets/safearea_widget.dart | 2 +- .../resources/widgets/switch_address_tab.dart | 4 +- .../resources/widgets/text_row_widget.dart | 5 +- .../lib/resources/widgets/top_nav_widget.dart | 3 +- .../lib/resources/widgets/woosignal_ui.dart | 518 +++++++++--------- LabelStoreMax/lib/routes/router.dart | 8 + LabelStoreMax/pubspec.lock | 29 +- LabelStoreMax/pubspec.yaml | 17 +- README.md | 2 +- 116 files changed, 3522 insertions(+), 1465 deletions(-) create mode 100644 LabelStoreMax/analysis_options.yaml create mode 100644 LabelStoreMax/lang/nl.json create mode 100644 LabelStoreMax/lang/tr.json create mode 100644 LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart create mode 100644 LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart create mode 100644 LabelStoreMax/lib/app/controllers/product_loader_controller.dart create mode 100644 LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart create mode 100644 LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart create mode 100644 LabelStoreMax/lib/app/models/bottom_nav_item.dart create mode 100644 LabelStoreMax/lib/generated_plugin_registrant.dart create mode 100644 LabelStoreMax/lib/resources/pages/coupon_page.dart create mode 100644 LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/checkout_coupon_amount_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/compo_home_widget.dart create mode 100644 LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart diff --git a/LabelStoreMax/.env b/LabelStoreMax/.env index 8e1c592..0d67197 100644 --- a/LabelStoreMax/.env +++ b/LabelStoreMax/.env @@ -15,7 +15,7 @@ DEFAULT_LOCALE=null # ** -APP_KEY="your app key" +APP_KEY="app_affb6434339b34443a297c2e40a3edab7102137e6d67de9abfe612b749bd" # App key from WooSignal link: https://woosignal.com/dashboard/apps # ** diff --git a/LabelStoreMax/CHANGELOG.md b/LabelStoreMax/CHANGELOG.md index 6fa2fc2..3ae465b 100644 --- a/LabelStoreMax/CHANGELOG.md +++ b/LabelStoreMax/CHANGELOG.md @@ -1,3 +1,15 @@ +## [5.6.0] - 2022-01-03 + +* Fix bug with banner in Mello theme +* Support new languages - Dutch (nl) and Turkish (tr) +* Refactor as per dart analysis +* Ability to add coupons +* Wishlist +* New theme "Compo" +* Analysis options added +* Code cleanup +* Pubspec.yaml dependency updates + ## [5.5.2] - 2021-12-18 * Fix continuous loading on categories screen diff --git a/LabelStoreMax/LICENSE b/LabelStoreMax/LICENSE index 541ae49..adb4f6b 100644 --- a/LabelStoreMax/LICENSE +++ b/LabelStoreMax/LICENSE @@ -1,6 +1,6 @@ BSD 2-Clause License -Copyright (c) 2021, WooSignal Ltd +Copyright (c) 2022, WooSignal Ltd All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/LabelStoreMax/README.md b/LabelStoreMax/README.md index fa032d8..ae33cb0 100644 --- a/LabelStoreMax/README.md +++ b/LabelStoreMax/README.md @@ -4,7 +4,7 @@ # WooCommerce App: Label StoreMax -### Label StoreMax - v5.5.2 +### Label StoreMax - v5.6.0 [Official WooSignal WooCommerce App](https://woosignal.com) diff --git a/LabelStoreMax/analysis_options.yaml b/LabelStoreMax/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/LabelStoreMax/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/LabelStoreMax/lang/de.json b/LabelStoreMax/lang/de.json index c655290..f1cd593 100644 --- a/LabelStoreMax/lang/de.json +++ b/LabelStoreMax/lang/de.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "Bitte geben Sie eine gültige Versand-E-Mail ein", "Free postage": "Portofrei", "PROCESSING": "WIRD BEARBEITET", - "Social": "Sozial" + "Social": "Sozial", + "Please enter coupon to redeem": "Bitte Coupon zum Einlösen eingeben", + "Coupon": "Coupon", + "Apply": "Sich bewerben", + "Apply Coupon": "Gutschein anwenden", + "Added to checkout": "Zur Kasse hinzugefügt", + "Redeem Coupon": "Gutschein einlösen", + "Add coupon code": "Gutscheincode hinzufügen", + "Coupon not found": "Gutschein nicht gefunden", + "Sorry, this coupon can not be used with your cart": "Dieser Gutschein kann leider nicht mit Ihrem Warenkorb verwendet werden", + "You cannot redeem this coupon": "Sie können diesen Gutschein nicht einlösen", + "This coupon has expired": "Dieser Gutschein ist abgelaufen", + "Usage limit has been reached": "Nutzungslimit wurde erreicht", + "View All": "Alle ansehen", + "Wishlist": "Wunschzettel", + "No items found": "Keine Elemente gefunden", + "This product has been removed from your wishlist": "Dieses Produkt wurde von Ihrer Wunschliste entfernt", + "This product has been added to your wishlist": "Dieses Produkt wurde Ihrer Wunschliste hinzugefügt", + "Spend a minimum of minimumAmount to redeem": "Verbringen Sie mindestens {{minimumAmount}} einlösen", + "Spend less than maximumAmount to redeem": "Geben Sie weniger aus als {{maximumAmount}} einlösen" } \ No newline at end of file diff --git a/LabelStoreMax/lang/en.json b/LabelStoreMax/lang/en.json index 3f36bc3..1fc7819 100644 --- a/LabelStoreMax/lang/en.json +++ b/LabelStoreMax/lang/en.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "Please enter a valid shipping email", "Free postage": "Free postage", "PROCESSING": "PROCESSING", - "Social": "Social" + "Social": "Social", + "Please enter coupon to redeem": "Please enter coupon to redeem", + "Coupon": "Coupon", + "Apply": "Apply", + "Apply Coupon": "Apply Coupon", + "Spend a minimum of minimumAmount to redeem": "Spend a minimum of {{minimumAmount}} to redeem", + "Spend less than maximumAmount to redeem": "Spend less than {{maximumAmount}} to redeem", + "Added to checkout": "Added to checkout", + "Redeem Coupon": "Redeem Coupon", + "Add coupon code": "Add coupon code", + "Coupon not found": "Coupon not found", + "Sorry, this coupon can not be used with your cart": "Sorry, this coupon can not be used with your cart", + "You cannot redeem this coupon": "You cannot redeem this coupon", + "This coupon has expired": "This coupon has expired", + "Usage limit has been reached": "Usage limit has been reached", + "View All": "View All", + "Wishlist": "Wishlist", + "No items found": "No items found", + "This product has been removed from your wishlist": "This product has been removed from your wishlist", + "This product has been added to your wishlist": "This product has been added to your wishlist" } \ No newline at end of file diff --git a/LabelStoreMax/lang/es.json b/LabelStoreMax/lang/es.json index 480a5c7..9749517 100644 --- a/LabelStoreMax/lang/es.json +++ b/LabelStoreMax/lang/es.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "Ingrese un correo electrónico de envío válido", "Free postage": "Gastos de envío gratis", "PROCESSING": "PROCESANDO", - "Social": "Social" + "Social": "Social", + "Please enter coupon to redeem": "Ingrese el cupón para canjear", + "Coupon": "Cupón", + "Apply": "Solicitar", + "Apply Coupon": "Aplicar cupón", + "Added to checkout": "Agregado al pago", + "Redeem Coupon": "Canjear cupón", + "Add coupon code": "Agregar código de cupón", + "Coupon not found": "Cupón no encontrado", + "Sorry, this coupon can not be used with your cart": "Lo sentimos, este cupón no se puede utilizar con su carrito", + "You cannot redeem this coupon": "No puedes canjear este cupón", + "This coupon has expired": "Este cupón ha caducado", + "Usage limit has been reached": "Se alcanzó el límite de uso", + "View All": "Ver todo", + "Wishlist": "Lista de deseos", + "No items found": "No se encontraron artículos", + "This product has been removed from your wishlist": "Este producto ha sido eliminado de tu lista de deseos.", + "This product has been added to your wishlist": "Este producto ha sido añadido a su lista de deseos", + "Spend a minimum of minimumAmount to redeem": "Gasta un mínimo de {{minimumAmount}} para redimir", + "Spend less than maximumAmount to redeem": "Gasta menos de {{maximumAmount}} para redimir" } \ No newline at end of file diff --git a/LabelStoreMax/lang/fr.json b/LabelStoreMax/lang/fr.json index a8002df..509155c 100644 --- a/LabelStoreMax/lang/fr.json +++ b/LabelStoreMax/lang/fr.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "Veuillez saisir un e-mail de livraison valide", "Free postage": "Sans frais de port", "PROCESSING": "EN TRAITEMENT", - "Social": "Social" + "Social": "Social", + "Please enter coupon to redeem": "Veuillez entrer le coupon pour l'utiliser", + "Coupon": "Coupon", + "Apply": "Appliquer", + "Apply Coupon": "Appliquer Coupon", + "Added to checkout": "Ajouté à la caisse", + "Redeem Coupon": "Échanger le coupon", + "Add coupon code": "Ajouter un code promo", + "Coupon not found": "Coupon introuvable", + "Sorry, this coupon can not be used with your cart": "Désolé, ce coupon ne peut pas être utilisé avec votre panier", + "You cannot redeem this coupon": "Vous ne pouvez pas utiliser ce coupon", + "This coupon has expired": "Ce coupon a expiré", + "Usage limit has been reached": "La limite d'utilisation a été atteinte", + "View All": "Voir tout", + "Wishlist": "Liste de souhaits", + "No items found": "Aucun élément trouvé", + "This product has been removed from your wishlist": "Ce produit a été supprimé de votre liste de souhaits", + "This product has been added to your wishlist": "Ce produit a été ajouté à votre liste de souhaits", + "Spend a minimum of minimumAmount to redeem": "Dépensez un minimum de {{minimumAmount}} de racheter", + "Spend less than maximumAmount to redeem": "Dépensez moins de {{maximumAmount}} de racheter" } \ No newline at end of file diff --git a/LabelStoreMax/lang/hi.json b/LabelStoreMax/lang/hi.json index 87dcd1f..51048b7 100644 --- a/LabelStoreMax/lang/hi.json +++ b/LabelStoreMax/lang/hi.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "krpaya ek maany shiping eemel darj karen", "Free postage": "mupht daak", "PROCESSING": "prasanskaran", - "Social": "saamaajik" + "Social": "saamaajik", + "Please enter coupon to redeem": "rideem karane ke lie krpaya koopan darj karen", + "Coupon": "koopan", + "Apply": "laagoo karana", + "Apply Coupon": "koopan laagoo karen", + "Added to checkout": "chekaut mein joda gaya", + "Redeem Coupon": "koopan rideem karaen", + "Add coupon code": "koopan kod joden", + "Coupon not found": "koopan nahin mila", + "Sorry, this coupon can not be used with your cart": "kshama karen, is koopan ka upayog aapake kaart ke saath nahin kiya ja sakata", + "You cannot redeem this coupon": "aap is koopan ko rideem nahin kar sakate", + "This coupon has expired": "yah koopan samaapt ho gaya hai", + "Usage limit has been reached": "upayog kee seema pooree ho chukee hai", + "View All": "sabhee ko dekhen", + "Wishlist": "ichchha-soochee", + "No items found": "kuchh nahin mila", + "This product has been removed from your wishlist": "yah utpaad aapakee ichchha soochee se hata diya gaya hai", + "This product has been added to your wishlist": "is utpaad ko aapakee vish - list mein jod diya gaya hai", + "Spend a minimum of minimumAmount to redeem": "kam se kam kharch karen {{minimumAmount}} ke evaj mein lena", + "Spend less than maximumAmount to redeem": "se kam kharch karen {{maximumAmount}} ke evaj mein lena" } \ No newline at end of file diff --git a/LabelStoreMax/lang/it.json b/LabelStoreMax/lang/it.json index 6cdf235..8e3ad5b 100644 --- a/LabelStoreMax/lang/it.json +++ b/LabelStoreMax/lang/it.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "Si prega di inserire un'e-mail di spedizione valida", "Free postage": "Spedizione gratuita", "PROCESSING": "IN LAVORAZIONE", - "Social": "Sociale" + "Social": "Sociale", + "Please enter coupon to redeem": "Inserisci il coupon per riscattare", + "Coupon": "Buono", + "Apply": "Applicare", + "Apply Coupon": "Applicare il coupon", + "Added to checkout": "Aggiunto al checkout", + "Redeem Coupon": "Utilizza il coupon", + "Add coupon code": "Aggiungi il codice coupon", + "Coupon not found": "Coupon non trovato", + "Sorry, this coupon can not be used with your cart": "Spiacenti, questo coupon non può essere utilizzato con il carrello", + "You cannot redeem this coupon": "Non puoi riscattare questo coupon", + "This coupon has expired": "Questo coupon è scaduto", + "Usage limit has been reached": "È stato raggiunto il limite di utilizzo", + "View All": "Mostra tutto", + "Wishlist": "Lista dei desideri", + "No items found": "Nessun articolo trovato", + "This product has been removed from your wishlist": "Questo prodotto è stato rimosso dalla tua lista dei desideri", + "This product has been added to your wishlist": "Questo prodotto è stato aggiunto alla tua lista dei desideri", + "Spend a minimum of minimumAmount to redeem": "Spendi un minimo di {{minimumAmount}} riscattare", + "Spend less than maximumAmount to redeem": "Spendi meno di {{maximumAmount}} riscattare" } \ No newline at end of file diff --git a/LabelStoreMax/lang/nl.json b/LabelStoreMax/lang/nl.json new file mode 100644 index 0000000..3d16e25 --- /dev/null +++ b/LabelStoreMax/lang/nl.json @@ -0,0 +1,214 @@ +{ + "Categories": "Categorieën", + "Shop": "Winkel", + "Newest": "Nieuwste", + "Browse categories": "Bladeren door rubrieken", + "Cart": "winkelwagentje", + "You need items in your cart to checkout": "Je hebt artikelen in je winkelwagen nodig om af te rekenen", + "Updated": "Bijgewerkt", + "Item removed": "Artikel verwijderd", + "Success": "succes", + "Cart cleared": "winkelwagen leeggemaakt", + "Shopping Cart": "Winkelwagen", + "Clear Cart": "Winkelwagen leegmaken", + "Empty Basket": "Lege mand", + "PROCEED TO CHECKOUT": "GA NAAR DE KASSA", + "Browse": "Bladeren", + "Search results for": "zoekresultaten voor", + "Select a": "Selecteer een", + "Added to cart": "Toegevoegd aan winkelwagen", + "Options": "Opties", + "Price": "prijs", + "Choose your options": "Kies je opties", + "Out of stock": "Uitverkocht", + "In Stock": "op voorraad", + "Add to cart": "Voeg toe aan winkelmandje", + "Oops": "oeps", + "Please select valid options first": "Selecteer eerst geldige opties", + "Sorry": "Sorry", + "This item is not in stock": "Dit artikel is niet op voorraad", + "Description": "Beschrijving", + "Full description": "Volledige beschrijving", + "ADD TO CART": "VOEG TOE AAN WINKELMANDJE", + "This item is out of stock": "Dit product is niet meer op voorraad", + "Add your shipping details first": "Voeg eerst uw verzendgegevens toe", + "Checkout": "uitchecken", + "Billing/shipping details": "Factuur-/verzendgegevens", + "Add billing & shipping details": "Facturerings- en verzendgegevens toevoegen", + "Payment method": "Betalingsmiddel", + "Pay with": "betaal met", + "Select a payment method": "Kies een betalingsmethode", + "Shipping selected": "Verzending geselecteerd", + "Select shipping": "Selecteer verzending", + "Select a shipping option": "Selecteer een verzendoptie", + "Shipping fee": "Verzendkosten", + "Subtotal": "subtotaal", + "Total": "Totaal", + "CHECKOUT": "UITCHECKEN", + "One moment": "een moment", + "Please select add your billing/shipping address to proceed": "Selecteer uw factuur-/verzendadres toevoegen om door te gaan", + "Your billing/shipping details are incomplete": "Uw factuur-/verzendgegevens zijn onvolledig", + "Please select a shipping method to proceed": "Selecteer een verzendmethode om verder te gaan", + "Please select a payment method to proceed": "Selecteer een betaalmethode om door te gaan", + "Something went wrong, please contact our store": "Er is iets misgegaan, neem contact op met onze winkel!", + "Error": "Fout", + "Order Status": "Bestelstatus", + "Thank You!": "Dank u!", + "Your transaction details": "Uw transactiegegevens", + "Order Ref": "Bestelreferentie", + "Items": "Artikelen", + "Back to Home": "Terug naar huis", + "Orders": "bestellingen", + "Billing & Shipping Details": "Facturerings- en verzendgegevens", + "First Name": "Voornaam", + "Last Name": "Achternaam", + "Address Line": "Adresregel", + "City": "Stad", + "Postal code": "Postcode", + "Email address": "E-mailadres", + "Selected": "Geselecteerd", + "Select country": "Selecteer land", + "Remember my details": "Onthoud mijn gegevens", + "USE SHIPPING ADDRESS": "VERZENDADRES GEBRUIKEN", + "About": "Over", + "Privacy policy": "Privacybeleid", + "Terms and conditions": "Voorwaarden", + "Version": "versie", + "Payment Method": "Betalingsmiddel", + "CANCEL": "ANNULEREN", + "Shipping Methods": "Verzendmethoden:", + "Shipping is not supported for your country, sorry": "Verzending wordt niet ondersteund voor uw land, sorry", + "Search": "Zoekopdracht", + "Debit or Credit Card": "Debet- of creditcard", + "Oops, something went wrong": "Oeps! Er is iets misgegaan", + "Tax": "Belasting", + "No results": "Geen resultaten", + "There is an item out of stock": "Er is een artikel niet op voorraad", + "Maximum stock reached": "Maximale voorraad bereikt", + "Select a country": "Selecteer een land", + "Menu": "Menu", + "About Us": "Over ons", + "Something went wrong": "Er is iets fout gegaan", + "Product variation does not exist": "Productvariatie bestaat niet", + "This variation is unavailable": "Deze variant is niet beschikbaar", + "Sorry, something went wrong": "Sorry, er ging iets mis", + "Back": "Rug", + "Profile": "Profiel", + "Forgot Password": "Wachtwoord vergeten", + "Create an account": "Account aanmaken", + "Login": "Log in", + "Password": "Wachtwoord", + "Oops!": "Oeps!", + "Invalid login credentials": "Ongeldige inloggegevens", + "That email address is not valid": "Dat e-mailadres is niet geldig", + "Password must be a min 6 characters": "Wachtwoord moet minimaal 6 tekens lang zijn", + "Please check your details": "Kijk alsjeblieft je gegevens na", + "Invalid": "Invalide", + "Actions": "Acties", + "View Terms and Conditions or Privacy policy": "Bekijk de algemene voorwaarden of het privacybeleid", + "Terms and Conditions": "Voorwaarden", + "Privacy Policy": "Privacybeleid", + "terms and conditions": "voorwaarden", + "and": "en", + "By tapping \"Register\" you agree to ": "Door op \"Registreren\" te tikken, gaat u akkoord met:", + "privacy policy": "privacybeleid", + "Sign up": "Inschrijven", + "Email": "E-mail", + "Update details": "Gegevens bijwerken", + "Settings": "Instellingen", + "Account": "Rekening", + "Logout": "Uitloggen", + "No orders found": "Geen bestellingen gevonden", + "items": "artikelen", + "Update Details": "Gegevens bijwerken", + "Invalid details": "Ongeldige gegevens", + "Please check your email and password": "Controleer uw e-mail en wachtwoord", + "Something went wrong, please try again.": "Er is iets mis gegaan, probeer het alstublieft nogmaals.", + "Done": "Gedaan", + "Billing Details": "Factureringsgegevens", + "Shipping Details": "Verzendgegevens", + "Shipping Address": "Verzendingsadres", + "State": "Staat", + "Country": "Land", + "UPDATE DETAILS": "DETAILS BIJWERKEN", + "No more products": "Geen producten meer", + "release to load more": "laat los om meer te laden", + "Load Failed! Click retry!": "Laden mislukt! Klik opnieuw!", + "pull up load": "trek de lading omhoog", + "Sort: Low to high": "Sorteren: laag naar hoog", + "Sort: High to low": "Sorteren: hoog naar laag", + "Sort: Name A-Z": "Sorteren: Naam A-Z", + "Sort: Name Z-A": "Sorteren: Naam Z-A", + "Cancel": "Annuleren", + "Sort results": "Sorteer resultaten", + "you're now logged in": "Je bent nu ingelogd", + "Hello": "Hallo", + "Welcome back": "Welkom terug", + "Quantity": "Hoeveelheid", + "Select a state": "Selecteer een staat", + "Select state": "Selecteer staat", + "Ship to a different address?": "Verzend naar een ander adres?", + "USE DETAILS": "GEBRUIK DETAILS", + "Not supported, try a card payment": "Niet ondersteund, probeer een kaartbetaling", + "Invalid shipping address, please check your shipping details": "Ongeldig verzendadres, controleer uw verzendgegevens", + "Was": "Was", + "off": "uit", + "Maximum quantity reached": "Maximale hoeveelheid bereikt", + "Sorry, only": "Sorry, alleen", + "left": "links", + "Billing address is incomplete": "Factuuradres is onvolledig", + "Order": "Volgorde", + "Date Ordered": "Datum besteld", + "Ships to": "wordt verzonden naar", + "That email does not match our records": "Dat e-mailadres komt niet overeen met onze gegevens", + "That username does not match our records": "Die gebruikersnaam komt niet overeen met onze gegevens", + "That password does not match our records": "Dat wachtwoord komt niet overeen met onze gegevens", + "The email and password field cannot be empty": "Het veld voor e-mail en wachtwoord mag niet leeg zijn", + "Username taken, try another.": "Die gebruikersnaam is in gebruik, probeer een andere.", + "A user already exists": "Er bestaat al een gebruiker", + "That email is taken, try another": "Die e-mail is in gebruik, probeer een andere", + "The email field is empty": "Het e-mailveld is leeg", + "No more orders": "Geen bestellingen meer", + "Account updated": "Account bijgewerkt", + "Spend a minimum of": "Besteed minimaal €", + "for": "voor", + "Buy Product": "Koop product", + "Retry": "Opnieuw proberen", + "Retry later": "Probeer het later opnieuw", + "Light Mode": "Lichtmodus", + "Dark Mode": "Donkere modus", + "PayPal Checkout": "PayPal Afrekenen", + "Processing Payment": "Betaling verwerken", + "Please wait, your order is being processed and you will be redirected to the PayPal website.": "Een ogenblik geduld, uw bestelling wordt verwerkt en u wordt doorgestuurd naar de PayPal-website.", + "If you are not automatically redirected to PayPal within 5 seconds": "Als u niet binnen 5 seconden automatisch wordt doorgestuurd naar PayPal", + "Payment Cancelled": "Betaling geannuleerd", + "The payment has been cancelled": "De betaling is geannuleerd", + "Must have": "Hebbeding", + "Our selection of new items": "Onze selectie van nieuwe items", + "Register": "Register", + "No payment methods are available": "Er zijn geen betaalmethoden beschikbaar", + "Please enter a valid billing email": "Voer een geldig e-mailadres voor facturering in", + "Please enter a valid shipping email": "Voer een geldig verzend-e-mailadres in", + "Free postage": "Gratis verzending", + "PROCESSING": "VERWERKEN", + "Social": "sociaal", + "Please enter coupon to redeem": "Voer de coupon in om deze in te wisselen", + "Coupon": "Coupon", + "Apply": "Van toepassing zijn", + "Apply Coupon": "gebruik coupon", + "Added to checkout": "Toegevoegd aan afrekenen", + "Redeem Coupon": "coupon inwisselen", + "Add coupon code": "Voeg couponcode toe", + "Coupon not found": "Coupon niet gevonden", + "Sorry, this coupon can not be used with your cart": "Sorry, deze coupon kan niet worden gebruikt met uw winkelwagentje", + "You cannot redeem this coupon": "U kunt deze coupon niet inwisselen", + "This coupon has expired": "Deze coupon is verlopen", + "Usage limit has been reached": "Gebruikslimiet is bereikt", + "View All": "Bekijk alles", + "Wishlist": "verlanglijst", + "No items found": "Geen items gevonden", + "This product has been removed from your wishlist": "Dit product is van je verlanglijst verwijderd", + "This product has been added to your wishlist": "Dit product is toegevoegd aan je verlanglijst", + "Spend a minimum of minimumAmount to redeem": "Besteed minimaal € {{minimumAmount}} verlossen", + "Spend less than maximumAmount to redeem": "Minder uitgeven dan {{maximumAmount}} verlossen" +} \ No newline at end of file diff --git a/LabelStoreMax/lang/pt.json b/LabelStoreMax/lang/pt.json index d34bdeb..0357246 100644 --- a/LabelStoreMax/lang/pt.json +++ b/LabelStoreMax/lang/pt.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "Por favor, insira um e-mail de envio válido", "Free postage": "Postagem grátis", "PROCESSING": "EM PROCESSAMENTO", - "Social": "Social" + "Social": "Social", + "Please enter coupon to redeem": "Por favor, insira o cupom para resgatar", + "Coupon": "Cupom", + "Apply": "Aplicar", + "Apply Coupon": "Aplicar cupom", + "Added to checkout": "Adicionado ao checkout", + "Redeem Coupon": "Resgatar cupom", + "Add coupon code": "Adicionar código de cupom", + "Coupon not found": "Cupom não encontrado", + "Sorry, this coupon can not be used with your cart": "Desculpe, este cupom não pode ser usado com seu carrinho", + "You cannot redeem this coupon": "Você não pode resgatar este cupom", + "This coupon has expired": "Este cupom expirou", + "Usage limit has been reached": "O limite de uso foi atingido", + "View All": "Ver tudo", + "Wishlist": "Lista de Desejos", + "No items found": "Nenhum item encontrado", + "This product has been removed from your wishlist": "Este produto foi removido da sua lista de desejos", + "This product has been added to your wishlist": "Este produto foi adicionado à sua lista de desejos", + "Spend a minimum of minimumAmount to redeem": "Gaste um mínimo de {{minimumAmount}} redimir", + "Spend less than maximumAmount to redeem": "Gaste menos que {{maximumAmount}} redimir" } \ No newline at end of file diff --git a/LabelStoreMax/lang/tr.json b/LabelStoreMax/lang/tr.json new file mode 100644 index 0000000..11f42c6 --- /dev/null +++ b/LabelStoreMax/lang/tr.json @@ -0,0 +1,214 @@ +{ + "Categories": "Kategoriler", + "Shop": "Mağaza", + "Newest": "en yeni", + "Browse categories": "Kategorilere Gözat", + "Cart": "Araba", + "You need items in your cart to checkout": "Ödeme yapmak için sepetinizdeki öğelere ihtiyacınız var", + "Updated": "Güncellenmiş", + "Item removed": "Öğe kaldırıldı", + "Success": "Başarı", + "Cart cleared": "Sepet temizlendi", + "Shopping Cart": "Alışveriş Sepeti", + "Clear Cart": "Sepeti Temizle", + "Empty Basket": "Boş sepet", + "PROCEED TO CHECKOUT": "ÇIKIŞA DOĞRU DEVAM ET", + "Browse": "Araştır", + "Search results for": "için arama sonuçları", + "Select a": "Bir seçin", + "Added to cart": "Sepete eklendi", + "Options": "Seçenekler", + "Price": "Fiyat", + "Choose your options": "Seçeneklerinizi seçin", + "Out of stock": "Stoklar tükendi", + "In Stock": "Stokta var", + "Add to cart": "Sepete ekle", + "Oops": "ayy", + "Please select valid options first": "Lütfen önce geçerli seçenekleri seçin", + "Sorry": "Üzgünüm", + "This item is not in stock": "Bu ürün stokta yok", + "Description": "Açıklama", + "Full description": "Tam tanım", + "ADD TO CART": "SEPETE EKLE", + "This item is out of stock": "Bu ürün stokta yok", + "Add your shipping details first": "Önce gönderim bilgilerinizi ekleyin", + "Checkout": "Ödeme", + "Billing/shipping details": "Fatura/gönderim ayrıntıları", + "Add billing & shipping details": "Fatura ve gönderim ayrıntılarını ekleyin", + "Payment method": "Ödeme şekli", + "Pay with": "İle ödemek", + "Select a payment method": "Bir ödeme şekli seçin", + "Shipping selected": "Sevkiyat seçildi", + "Select shipping": "Gönderim seç", + "Select a shipping option": "Bir nakliye seçeneği seçin", + "Shipping fee": "Nakliye ücreti", + "Subtotal": "ara toplam", + "Total": "Toplam", + "CHECKOUT": "ÖDEME", + "One moment": "Bir dakika", + "Please select add your billing/shipping address to proceed": "Devam etmek için lütfen fatura/gönderim adresinizi ekleyin'i seçin", + "Your billing/shipping details are incomplete": "Faturalandırma/gönderim bilgileriniz eksik", + "Please select a shipping method to proceed": "Lütfen devam etmek için bir gönderim yöntemi seçin", + "Please select a payment method to proceed": "Lütfen devam etmek için bir ödeme yöntemi seçin", + "Something went wrong, please contact our store": "Bir şeyler ters gitti, lütfen mağazamızla iletişime geçin", + "Error": "Hata", + "Order Status": "Sipariş durumu", + "Thank You!": "Teşekkürler!", + "Your transaction details": "İşlem ayrıntılarınız", + "Order Ref": "Sipariş Referansı", + "Items": "Öğeler", + "Back to Home": "Eve geri dön", + "Orders": "Emirler", + "Billing & Shipping Details": "Faturalandırma ve Gönderim Ayrıntıları", + "First Name": "İlk adı", + "Last Name": "Soyadı", + "Address Line": "Adres satırı", + "City": "Şehir", + "Postal code": "Posta kodu", + "Email address": "E", + "Selected": "Seçildi", + "Select country": "Ülke seçin", + "Remember my details": "Ayrıntılarımı hatırla", + "USE SHIPPING ADDRESS": "NAKLİYE ADRESİNİ KULLAN", + "About": "Hakkında", + "Privacy policy": "Gizlilik Politikası", + "Terms and conditions": "Şartlar ve koşullar", + "Version": "sürüm", + "Payment Method": "Ödeme şekli", + "CANCEL": "İPTAL ET", + "Shipping Methods": "Nakliye Yöntemleri", + "Shipping is not supported for your country, sorry": "Ülkeniz için gönderim desteklenmiyor, üzgünüm", + "Search": "Aramak", + "Debit or Credit Card": "Banka veya Kredi Kartı", + "Oops, something went wrong": "Hoop! Birşeyler yanlış gitti", + "Tax": "Vergi", + "No results": "Sonuç yok", + "There is an item out of stock": "Stokta olmayan bir ürün var", + "Maximum stock reached": "Maksimum stoka ulaşıldı", + "Select a country": "Bir ülke seçin", + "Menu": "Menü", + "About Us": "Hakkımızda", + "Something went wrong": "Bir şeyler yanlış gitti", + "Product variation does not exist": "Ürün varyasyonu mevcut değil", + "This variation is unavailable": "Bu varyasyon kullanılamıyor", + "Sorry, something went wrong": "Üzgünüm, bir şeyler ters gitti", + "Back": "Geri", + "Profile": "Profil", + "Forgot Password": "Parolanızı mı unuttunuz", + "Create an account": "Bir hesap oluşturun", + "Login": "Giriş yapmak", + "Password": "Parola", + "Oops!": "Hata!", + "Invalid login credentials": "Geçersiz giriş bilgileri", + "That email address is not valid": "Bu e-posta adresi geçerli değil", + "Password must be a min 6 characters": "Şifre en az 6 karakter olmalıdır", + "Please check your details": "Lütfen bilgilerinizi kontrol edin", + "Invalid": "Geçersiz", + "Actions": "Hareketler", + "View Terms and Conditions or Privacy policy": "Hüküm ve Koşulları veya Gizlilik Politikasını Görüntüle", + "Terms and Conditions": "Şartlar ve koşullar", + "Privacy Policy": "Gizlilik Politikası", + "terms and conditions": "Şartlar ve koşullar", + "and": "ve", + "By tapping \"Register\" you agree to ": "\"Kaydol\"a dokunarak şunları kabul etmiş olursunuz:", + "privacy policy": "Gizlilik Politikası", + "Sign up": "Üye olmak", + "Email": "E-posta", + "Update details": "Ayrıntıları güncelle", + "Settings": "Ayarlar", + "Account": "Hesap", + "Logout": "Çıkış Yap", + "No orders found": "sipariş bulunamadı", + "items": "öğeler", + "Update Details": "Ayrıntıları Güncelle", + "Invalid details": "Geçersiz ayrıntılar", + "Please check your email and password": "Lütfen e-posta adresinizi ve şifrenizi kontrol edin", + "Something went wrong, please try again.": "Bir şeyler ters gitti lütfen tekrar deneyin.", + "Done": "Tamamlandı", + "Billing Details": "Fatura Detayları", + "Shipping Details": "Nakliye ayrıntıları", + "Shipping Address": "Teslimat Adresi", + "State": "Belirtmek, bildirmek", + "Country": "Ülke", + "UPDATE DETAILS": "GÜNCELLEME DETAYLARI", + "No more products": "Daha fazla ürün yok", + "release to load more": "daha fazla yüklemek için bırakın", + "Load Failed! Click retry!": "Yükleme başarısız! Yeniden dene'yi tıklayın!", + "pull up load": "yükü yukarı çekmek", + "Sort: Low to high": "Sıralama: Düşükten yükseğe", + "Sort: High to low": "Sıralama: Yüksekten düşüğe", + "Sort: Name A-Z": "Sırala: İsim A-Z", + "Sort: Name Z-A": "Sıralama: İsim Z-A", + "Cancel": "İptal etmek", + "Sort results": "Sonuçları sırala", + "you're now logged in": "şimdi giriş yaptınız", + "Hello": "Merhaba", + "Welcome back": "Tekrar hoşgeldiniz", + "Quantity": "Miktar", + "Select a state": "Bir eyalet seçin", + "Select state": "Eyalet seç", + "Ship to a different address?": "Farklı bir adrese mi gönderiyorsunuz?", + "USE DETAILS": "KULLANIM DETAYLARI", + "Not supported, try a card payment": "Desteklenmiyor, kartla ödeme yapmayı deneyin", + "Invalid shipping address, please check your shipping details": "Geçersiz gönderim adresi, lütfen gönderim ayrıntılarınızı kontrol edin", + "Was": "Oldu", + "off": "kapalı", + "Maximum quantity reached": "Maksimum miktara ulaşıldı", + "Sorry, only": "Üzgünüm, sadece", + "left": "ayrıldı", + "Billing address is incomplete": "Fatura adresi eksik", + "Order": "Emir", + "Date Ordered": "Sipariş Tarihi", + "Ships to": "Şuraya gönderilir:", + "That email does not match our records": "Bu e-posta kayıtlarımızla eşleşmiyor", + "That username does not match our records": "Bu kullanıcı adı kayıtlarımızla eşleşmiyor", + "That password does not match our records": "Bu şifre kayıtlarımızla eşleşmiyor", + "The email and password field cannot be empty": "E-posta ve şifre alanı boş olamaz", + "Username taken, try another.": "Bu kullanıcı adı alınmış, başka bir tane deneyin.", + "A user already exists": "Bir kullanıcı zaten var", + "That email is taken, try another": "Bu e-posta alındı, başka bir tane deneyin", + "The email field is empty": "E-posta alanı boş", + "No more orders": "Başka sipariş yok", + "Account updated": "Hesap güncellendi", + "Spend a minimum of": "Minimum harcamak", + "for": "için", + "Buy Product": "Ürün Satın Al", + "Retry": "yeniden dene", + "Retry later": "daha sonra tekrar dene", + "Light Mode": "Işık Modu", + "Dark Mode": "Karanlık Mod", + "PayPal Checkout": "PayPal Ödemesi", + "Processing Payment": "Ödeme İşlemi", + "Please wait, your order is being processed and you will be redirected to the PayPal website.": "Lütfen bekleyin, siparişiniz işleniyor ve PayPal web sitesine yönlendirileceksiniz.", + "If you are not automatically redirected to PayPal within 5 seconds": "5 saniye içinde otomatik olarak PayPal'a yönlendirilmezseniz", + "Payment Cancelled": "Ödeme İptal Edildi", + "The payment has been cancelled": "ödeme iptal edildi", + "Must have": "sahip olmalı", + "Our selection of new items": "Yeni ürün seçimimiz", + "Register": "Kayıt olmak", + "No payment methods are available": "Ödeme yöntemi yok", + "Please enter a valid billing email": "Lütfen geçerli bir fatura e-postası girin", + "Please enter a valid shipping email": "Lütfen geçerli bir gönderim e-postası girin", + "Free postage": "Bedava posta", + "PROCESSING": "İŞLEME", + "Social": "Sosyal", + "Please enter coupon to redeem": "Lütfen kullanmak için kupon girin", + "Coupon": "Kupon", + "Apply": "Uygulamak", + "Apply Coupon": "kuponu onayla", + "Added to checkout": "ödemeye eklendi", + "Redeem Coupon": "Kuponu Kullan", + "Add coupon code": "Kupon kodu ekle", + "Coupon not found": "Kupon bulunamadı", + "Sorry, this coupon can not be used with your cart": "Üzgünüz, bu kupon sepetinizle kullanılamaz", + "You cannot redeem this coupon": "Bu kuponu kullanamazsınız", + "This coupon has expired": "Bu kuponun süresi doldu", + "Usage limit has been reached": "Kullanım sınırına ulaşıldı", + "View All": "Hepsini gör", + "Wishlist": "istek listesi", + "No items found": "hiç bir öğe bulunamadı", + "This product has been removed from your wishlist": "Bu ürün istek listenizden kaldırıldı", + "This product has been added to your wishlist": "Bu ürün istek listenize eklendi", + "Spend a minimum of minimumAmount to redeem": "Minimum harcamak {{minimumAmount}} rehinden kurtarmak", + "Spend less than maximumAmount to redeem": "Şundan daha az harcayın: {{maximumAmount}} rehinden kurtarmak" +} \ No newline at end of file diff --git a/LabelStoreMax/lang/zh.json b/LabelStoreMax/lang/zh.json index 33f961e..c7e3c62 100644 --- a/LabelStoreMax/lang/zh.json +++ b/LabelStoreMax/lang/zh.json @@ -191,5 +191,24 @@ "Please enter a valid shipping email": "请输入有效的送货电子邮件", "Free postage": "免邮费", "PROCESSING": "加工", - "Social": "社会的" + "Social": "社会的", + "Please enter coupon to redeem": "请输入优惠券进行兑换", + "Coupon": "优惠券", + "Apply": "申请", + "Apply Coupon": "申请优惠券", + "Added to checkout": "添加到结帐", + "Redeem Coupon": "兑换优惠券", + "Add coupon code": "添加优惠券代码", + "Coupon not found": "未找到优惠券", + "Sorry, this coupon can not be used with your cart": "抱歉,此优惠券不能与您的购物车一起使用", + "You cannot redeem this coupon": "您无法兑换此优惠券", + "This coupon has expired": "此优惠券已过期", + "Usage limit has been reached": "已达到使用限制", + "View All": "查看全部", + "Wishlist": "愿望清单", + "No items found": "未找到任何项目", + "This product has been removed from your wishlist": "该产品已从您的愿望清单中删除", + "This product has been added to your wishlist": "本产品已经被加入你的心愿单", + "Spend a minimum of minimumAmount to redeem": "至少花费 {{minimumAmount}} 赎回", + "Spend less than maximumAmount to redeem": "花费少于 {{maximumAmount}} 赎回" } \ No newline at end of file diff --git a/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart b/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart index 4fac185..697a715 100644 --- a/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart +++ b/LabelStoreMax/lib/app/controllers/account_order_detail_controller.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/controllers/browse_category_controller.dart b/LabelStoreMax/lib/app/controllers/browse_category_controller.dart index 0bbfcc0..4ed3d45 100644 --- a/LabelStoreMax/lib/app/controllers/browse_category_controller.dart +++ b/LabelStoreMax/lib/app/controllers/browse_category_controller.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/controllers/browse_search_controller.dart b/LabelStoreMax/lib/app/controllers/browse_search_controller.dart index e2e0bd7..3c53c24 100644 --- a/LabelStoreMax/lib/app/controllers/browse_search_controller.dart +++ b/LabelStoreMax/lib/app/controllers/browse_search_controller.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart b/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart index a98fef7..1ebcd69 100644 --- a/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart +++ b/LabelStoreMax/lib/app/controllers/checkout_status_controller.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/controllers/controller.dart b/LabelStoreMax/lib/app/controllers/controller.dart index 0ee065f..9b0a405 100644 --- a/LabelStoreMax/lib/app/controllers/controller.dart +++ b/LabelStoreMax/lib/app/controllers/controller.dart @@ -1,23 +1,17 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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:nylo_support/controllers/controller.dart'; /// Base Controller for the Nylo /// See more on controllers here - https://nylo.dev/docs/2.x/controllers class Controller extends BaseController { Controller(); - - @override - construct(BuildContext context) { - super.construct(context); - } } diff --git a/LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart b/LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart new file mode 100644 index 0000000..546132e --- /dev/null +++ b/LabelStoreMax/lib/app/controllers/customer_orders_loader_controller.dart @@ -0,0 +1,29 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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/cupertino.dart'; +import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; +import 'package:woosignal/models/response/order.dart'; + +class CustomerOrdersLoaderController + extends WooSignalApiLoaderController { + CustomerOrdersLoaderController(); + + Future loadOrders( + {@required bool Function(bool hasProducts) hasResults, + @required void Function() didFinish, + @required String userId}) async { + await load( + hasResults: hasResults, + didFinish: didFinish, + apiQuery: (api) => api.getOrders( + customer: int.parse(userId), page: page, perPage: 50)); + } +} diff --git a/LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart new file mode 100644 index 0000000..00f48b6 --- /dev/null +++ b/LabelStoreMax/lib/app/controllers/product_category_search_loader_controller.dart @@ -0,0 +1,34 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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/cupertino.dart'; +import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; +import 'package:woosignal/models/response/product_category.dart'; +import 'package:woosignal/models/response/products.dart'; + +class ProductCategorySearchLoaderController + extends WooSignalApiLoaderController { + ProductCategorySearchLoaderController(); + + Future loadProducts( + {@required bool Function(bool hasProducts) hasResults, + @required void Function() didFinish, + @required ProductCategory productCategory}) async { + await load( + hasResults: hasResults, + didFinish: didFinish, + apiQuery: (api) => api.getProducts( + perPage: 50, + category: productCategory.id.toString(), + page: page, + status: "publish", + stockStatus: "instock")); + } +} diff --git a/LabelStoreMax/lib/app/controllers/product_detail_controller.dart b/LabelStoreMax/lib/app/controllers/product_detail_controller.dart index cf15f02..716988d 100644 --- a/LabelStoreMax/lib/app/controllers/product_detail_controller.dart +++ b/LabelStoreMax/lib/app/controllers/product_detail_controller.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart b/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart index a596851..f4d99e3 100644 --- a/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart +++ b/LabelStoreMax/lib/app/controllers/product_image_viewer_controller.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/controllers/product_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_loader_controller.dart new file mode 100644 index 0000000..aa43e75 --- /dev/null +++ b/LabelStoreMax/lib/app/controllers/product_loader_controller.dart @@ -0,0 +1,32 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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/cupertino.dart'; +import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; +import 'package:woosignal/models/response/products.dart'; + +class ProductLoaderController extends WooSignalApiLoaderController { + ProductLoaderController(); + + Future loadProducts({ + @required bool Function(bool hasProducts) hasResults, + @required void Function() didFinish, + }) async { + await load( + hasResults: hasResults, + didFinish: didFinish, + apiQuery: (api) => api.getProducts( + perPage: 50, + page: page, + status: "publish", + stockStatus: "instock", + )); + } +} diff --git a/LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart b/LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart new file mode 100644 index 0000000..00ec955 --- /dev/null +++ b/LabelStoreMax/lib/app/controllers/product_search_loader_controller.dart @@ -0,0 +1,34 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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/cupertino.dart'; +import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; +import 'package:woosignal/models/response/products.dart'; + +class ProductSearchLoaderController + extends WooSignalApiLoaderController { + ProductSearchLoaderController(); + + Future loadProducts( + {@required bool Function(bool hasProducts) hasResults, + @required void Function() didFinish, + @required String search}) async { + await load( + hasResults: hasResults, + didFinish: didFinish, + apiQuery: (api) => api.getProducts( + perPage: 100, + search: search, + page: page, + status: "publish", + stockStatus: "instock", + )); + } +} diff --git a/LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart b/LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart new file mode 100644 index 0000000..b7d45a2 --- /dev/null +++ b/LabelStoreMax/lib/app/controllers/woosignal_api_loader_controller.dart @@ -0,0 +1,53 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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/cupertino.dart'; +import 'package:flutter_app/bootstrap/helpers.dart'; +import 'package:woosignal/woosignal.dart'; + +class WooSignalApiLoaderController { + List _results = []; + int page = 1; + bool _waitForNextRequest = false; + + WooSignalApiLoaderController(); + + Future load( + {@required bool Function(bool hasProducts) hasResults, + @required void Function() didFinish, + @required Future> Function(WooSignal query) apiQuery}) async { + if (_waitForNextRequest) { + return; + } + _waitForNextRequest = true; + + List apiResults = await appWooSignal((api) => apiQuery(api)); + + if (!hasResults(apiResults.isNotEmpty)) { + return; + } + + _results.addAll(apiResults); + + page = page + 1; + _waitForNextRequest = false; + didFinish(); + } + + List getResults() { + return _results; + } + + void clear() { + _results = []; + _waitForNextRequest = false; + page = 1; + } +} diff --git a/LabelStoreMax/lib/app/models/billing_details.dart b/LabelStoreMax/lib/app/models/billing_details.dart index 9343593..400aeba 100644 --- a/LabelStoreMax/lib/app/models/billing_details.dart +++ b/LabelStoreMax/lib/app/models/billing_details.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/models/bottom_nav_item.dart b/LabelStoreMax/lib/app/models/bottom_nav_item.dart new file mode 100644 index 0000000..ab339e7 --- /dev/null +++ b/LabelStoreMax/lib/app/models/bottom_nav_item.dart @@ -0,0 +1,19 @@ +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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'; + +class BottomNavItem { + int id; + BottomNavigationBarItem bottomNavigationBarItem; + Widget tabWidget; + + BottomNavItem({this.id, this.bottomNavigationBarItem, this.tabWidget}); +} diff --git a/LabelStoreMax/lib/app/models/cart.dart b/LabelStoreMax/lib/app/models/cart.dart index 1b00f35..4b26a90 100644 --- a/LabelStoreMax/lib/app/models/cart.dart +++ b/LabelStoreMax/lib/app/models/cart.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -70,9 +70,15 @@ class Cart { Future getTotal({bool withFormat = false}) async { List cartLineItems = await getCart(); double total = 0; - cartLineItems.forEach((cartItem) { + for (var cartItem in cartLineItems) { total += (parseWcPrice(cartItem.total) * cartItem.quantity); - }); + } + + CheckoutSession checkoutSession = CheckoutSession.getInstance; + if (checkoutSession.coupon != null) { + String discountAmount = await Cart.getInstance.couponDiscountAmount(); + total = total - double.parse(discountAmount); + } if (withFormat != null && withFormat == true) { return formatDoubleCurrency(total: total); @@ -83,9 +89,9 @@ class Cart { Future getSubtotal({bool withFormat = false}) async { List cartLineItems = await getCart(); double subtotal = 0; - cartLineItems.forEach((cartItem) { + for (var cartItem in cartLineItems) { subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity); - }); + } if (withFormat != null && withFormat == true) { return formatDoubleCurrency(total: subtotal); } @@ -97,7 +103,7 @@ class Cart { @required int incrementQuantity}) async { List cartLineItems = await getCart(); List tmpCartItem = []; - cartLineItems.forEach((cartItem) { + for (var cartItem in cartLineItems) { if (cartItem.variationId == cartLineItem.variationId && cartItem.productId == cartLineItem.productId) { if ((cartItem.quantity + incrementQuantity) > 0) { @@ -105,7 +111,7 @@ class Cart { } } tmpCartItem.add(cartItem); - }); + } await saveCartToPref(cartLineItems: tmpCartItem); } @@ -145,10 +151,14 @@ class Cart { double cartSubtotal = 0; if (AppHelper.instance.appConfig.productPricesIncludeTax == 1 && - taxableCartLines.length > 0) { + taxableCartLines.isNotEmpty) { cartSubtotal = taxableCartLines .map((m) => parseWcPrice(m.subtotal) * m.quantity) .reduce((a, b) => a + b); + if (CheckoutSession.getInstance.coupon != null) { + String discountAmount = await Cart.getInstance.couponDiscountAmount(); + cartSubtotal = cartSubtotal - double.parse(discountAmount); + } } subtotal = cartSubtotal; @@ -189,4 +199,86 @@ class Cart { } return (total).toStringAsFixed(2); } + + Future couponDiscountAmount() async { + CheckoutSession checkoutSession = CheckoutSession.getInstance; + + if (checkoutSession.coupon == null) { + return "0"; + } + + List cartLineItems = await getCart(); + List eligibleCartLineItems = []; + double subtotal = 0; + for (var cartItem in cartLineItems) { + bool canContinue = true; + + if (checkoutSession.coupon.excludedProductCategories.isNotEmpty) { + for (var excludedProductCategory + in checkoutSession.coupon.excludedProductCategories) { + if (cartItem.categories + .map((category) => category.id) + .contains(excludedProductCategory)) { + canContinue = false; + break; + } + } + } + + if (checkoutSession.coupon.productCategories.isNotEmpty) { + for (var productCategories + in checkoutSession.coupon.productCategories) { + if (cartItem.categories + .map((category) => category.id) + .contains(productCategories) == + false) { + canContinue = false; + break; + } + } + } + + if (canContinue == false) { + continue; + } + + if (checkoutSession.coupon.excludeSaleItems == true && + cartItem.onSale == true) { + continue; + } + + if (checkoutSession.coupon.excludedProductIds.isNotEmpty && + checkoutSession.coupon.excludedProductIds + .contains(cartItem.productId)) { + continue; + } + + if (checkoutSession.coupon.productIds.isNotEmpty && + !checkoutSession.coupon.productIds.contains(cartItem.productId)) { + continue; + } + subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity); + eligibleCartLineItems.add(cartItem); + } + + String discountType = checkoutSession.coupon.discountType; + String amount = checkoutSession.coupon.amount; + + // Percentage + if (discountType == 'percent') { + return ((subtotal * double.parse(amount)) / 100).toStringAsFixed(2); + } + + // Fixed cart + if (discountType == 'fixed_cart') { + return (double.parse(amount)).toStringAsFixed(2); + } + + // Fixed product + if (discountType == 'fixed_product') { + return (eligibleCartLineItems.length * double.parse(amount)) + .toStringAsFixed(2); + } + return "0"; + } } diff --git a/LabelStoreMax/lib/app/models/cart_line_item.dart b/LabelStoreMax/lib/app/models/cart_line_item.dart index 6f7c5e2..68d55e5 100644 --- a/LabelStoreMax/lib/app/models/cart_line_item.dart +++ b/LabelStoreMax/lib/app/models/cart_line_item.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -9,6 +9,9 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter_app/bootstrap/helpers.dart'; +import 'package:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/models/response/product_variation.dart'; +import 'package:woosignal/models/response/products.dart' as ws_product; class CartLineItem { String name; @@ -25,6 +28,8 @@ class CartLineItem { String total; String imageSrc; String variationOptions; + List categories; + bool onSale; String stockStatus; Object metaData = {}; @@ -39,10 +44,12 @@ class CartLineItem { this.shippingClassId, this.taxStatus, this.taxClass, + this.categories, this.shippingIsTaxable, this.variationOptions, this.imageSrc, this.subtotal, + this.onSale, this.total, this.metaData}); @@ -50,6 +57,53 @@ class CartLineItem { return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2); } + CartLineItem.fromProduct({int quantityAmount, ws_product.Product product}) { + name = product.name; + productId = product.id; + quantity = quantityAmount; + taxStatus = product.taxStatus; + shippingClassId = product.shippingClassId.toString(); + subtotal = product.price; + taxClass = product.taxClass; + categories = product.categories; + isManagedStock = product.manageStock; + stockQuantity = product.stockQuantity; + shippingIsTaxable = product.shippingTaxable; + imageSrc = product.images.isEmpty + ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") + : product.images.first.src; + total = product.price; + } + + CartLineItem.fromProductVariation( + {int quantityAmount, + List options, + ws_product.Product product, + ProductVariation productVariation}) { + String imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE"); + if (product.images.isNotEmpty) { + imageSrc = product.images.first.src; + } + if (productVariation.image != null) { + imageSrc = productVariation.image.src; + } + name = product.name; + productId = product.id; + variationId = productVariation.id; + quantity = quantityAmount; + taxStatus = productVariation.taxStatus; + shippingClassId = productVariation.shippingClassId.toString(); + subtotal = productVariation.price; + stockQuantity = productVariation.stockQuantity; + isManagedStock = productVariation.manageStock; + categories = product.categories; + taxClass = productVariation.taxClass; + this.imageSrc = imageSrc; + shippingIsTaxable = product.shippingTaxable; + variationOptions = options.join("; "); + total = productVariation.price; + } + CartLineItem.fromJson(Map json) : name = json['name'], productId = json['product_id'], @@ -68,6 +122,12 @@ class CartLineItem { taxClass = json['tax_class'], stockStatus = json['stock_status'], imageSrc = json['image_src'], + categories = json['categories'] == null + ? null + : List.of(json['categories'] as List) + .map((e) => ws_product.Category.fromJson(e)) + .toList(), + onSale = json['on_sale'], variationOptions = json['variation_options'], metaData = json['metaData']; @@ -84,8 +144,12 @@ class CartLineItem { 'stock_quantity': stockQuantity, 'shipping_is_taxable': shippingIsTaxable, 'image_src': imageSrc, + 'categories': categories != null + ? categories.map((e) => e.toJson()).toList() + : [], 'variation_options': variationOptions, 'subtotal': subtotal, + 'on_sale': onSale, 'total': total, 'meta_data': metaData, }; diff --git a/LabelStoreMax/lib/app/models/checkout_session.dart b/LabelStoreMax/lib/app/models/checkout_session.dart index 9f25ccf..58239a2 100644 --- a/LabelStoreMax/lib/app/models/checkout_session.dart +++ b/LabelStoreMax/lib/app/models/checkout_session.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -17,6 +17,7 @@ import 'package:flutter_app/app/models/shipping_type.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart'; import 'package:nylo_support/helpers/helper.dart'; +import 'package:woosignal/models/response/coupon.dart'; import 'package:woosignal/models/response/tax_rate.dart'; class CheckoutSession { @@ -29,6 +30,7 @@ class CheckoutSession { BillingDetails billingDetails; ShippingType shippingType; PaymentType paymentType; + Coupon coupon; void initSession() { billingDetails = BillingDetails(); @@ -39,6 +41,7 @@ class CheckoutSession { billingDetails = null; shippingType = null; paymentType = null; + coupon = null; } void saveBillingAddress() async { diff --git a/LabelStoreMax/lib/app/models/customer_address.dart b/LabelStoreMax/lib/app/models/customer_address.dart index 19f5c9f..8ab6f7a 100644 --- a/LabelStoreMax/lib/app/models/customer_address.dart +++ b/LabelStoreMax/lib/app/models/customer_address.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -39,13 +39,13 @@ class CustomerAddress { } bool hasMissingFields() => - (this.firstName.isEmpty || - this.lastName.isEmpty || - this.addressLine.isEmpty || - this.city.isEmpty || - this.postalCode.isEmpty) || - (this.customerCountry.hasState() == true - ? (this.customerCountry?.state?.name ?? "").isEmpty + (firstName.isEmpty || + lastName.isEmpty || + addressLine.isEmpty || + city.isEmpty || + postalCode.isEmpty) || + (customerCountry.hasState() == true + ? (customerCountry?.state?.name ?? "").isEmpty : false); String addressFull() { @@ -59,12 +59,11 @@ class CustomerAddress { if (postalCode != null && postalCode != "") { tmpArrAddress.add(postalCode); } - if (this.customerCountry != null && - this.customerCountry?.state?.name != null) { - tmpArrAddress.add(this.customerCountry?.state?.name); + if (customerCountry != null && customerCountry?.state?.name != null) { + tmpArrAddress.add(customerCountry?.state?.name); } - if (this.customerCountry != null && this.customerCountry?.name != null) { - tmpArrAddress.add(this.customerCountry.name); + if (customerCountry != null && customerCountry?.name != null) { + tmpArrAddress.add(customerCountry.name); } return tmpArrAddress.join(", "); } @@ -86,23 +85,23 @@ class CustomerAddress { addressLine = json['address_line']; city = json['city']; postalCode = json['postal_code']; - this.customerCountry = CustomerCountry.fromJson(json['customer_country']); + customerCountry = CustomerCountry.fromJson(json['customer_country']); emailAddress = json['email_address']; } Map toJson() { - final Map data = new Map(); - data['first_name'] = this.firstName; - data['last_name'] = this.lastName; - data['address_line'] = this.addressLine; - data['city'] = this.city; - data['postal_code'] = this.postalCode; - data['state'] = this.customerCountry.state; - data['country'] = this.customerCountry.name; - data['email_address'] = this.emailAddress; + final Map data = {}; + data['first_name'] = firstName; + data['last_name'] = lastName; + data['address_line'] = addressLine; + data['city'] = city; + data['postal_code'] = postalCode; + data['state'] = customerCountry.state; + data['country'] = customerCountry.name; + data['email_address'] = emailAddress; data['customer_country'] = null; - if (this.customerCountry != null) { - data['customer_country'] = this.customerCountry.toJson(); + if (customerCountry != null) { + data['customer_country'] = customerCountry.toJson(); } return data; } diff --git a/LabelStoreMax/lib/app/models/customer_country.dart b/LabelStoreMax/lib/app/models/customer_country.dart index 2bf5c64..95bd807 100644 --- a/LabelStoreMax/lib/app/models/customer_country.dart +++ b/LabelStoreMax/lib/app/models/customer_country.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -40,16 +40,15 @@ class CustomerCountry { } } - bool hasState() => - (this.state != null && this.state.name != null ? true : false); + bool hasState() => (state != null && state.name != null ? true : false); Map toJson() { - final Map data = new Map(); - data['country_code'] = this.countryCode; - data['name'] = this.name; + final Map data = {}; + data['country_code'] = countryCode; + data['name'] = name; data['state'] = null; - if (this.state != null) { - data['state'] = this.state.toJson(); + if (state != null) { + data['state'] = state.toJson(); } return data; } diff --git a/LabelStoreMax/lib/app/models/default_shipping.dart b/LabelStoreMax/lib/app/models/default_shipping.dart index 6f3c9af..4d8ab6b 100644 --- a/LabelStoreMax/lib/app/models/default_shipping.dart +++ b/LabelStoreMax/lib/app/models/default_shipping.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -25,14 +25,14 @@ class DefaultShippingState { DefaultShippingState({@required this.code, @required this.name}); Map toJson() { - final Map data = new Map(); + final Map data = {}; data['code'] = code; data['name'] = name; return data; } DefaultShippingState.fromJson(Map json) { - this.code = json['code']; - this.name = json['name']; + code = json['code']; + name = json['name']; } } diff --git a/LabelStoreMax/lib/app/models/payment_type.dart b/LabelStoreMax/lib/app/models/payment_type.dart index d78654e..dd30de7 100644 --- a/LabelStoreMax/lib/app/models/payment_type.dart +++ b/LabelStoreMax/lib/app/models/payment_type.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/models/shipping_type.dart b/LabelStoreMax/lib/app/models/shipping_type.dart index 6aa3b21..b3a3b68 100644 --- a/LabelStoreMax/lib/app/models/shipping_type.dart +++ b/LabelStoreMax/lib/app/models/shipping_type.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -32,20 +32,20 @@ class ShippingType { }; String getTotal({bool withFormatting = false}) { - if (this.object != null) { - switch (this.methodId) { + if (object != null) { + switch (methodId) { case "flat_rate": - FlatRate flatRate = (this.object as FlatRate); + FlatRate flatRate = (object as FlatRate); return (withFormatting == true ? formatStringCurrency(total: cost) : flatRate.cost); case "free_shipping": - FreeShipping freeShipping = (this.object as FreeShipping); + FreeShipping freeShipping = (object as FreeShipping); return (withFormatting == true ? formatStringCurrency(total: cost) : freeShipping.cost); case "local_pickup": - LocalPickup localPickup = (this.object as LocalPickup); + LocalPickup localPickup = (object as LocalPickup); return (withFormatting == true ? formatStringCurrency(total: cost) : localPickup.cost); @@ -57,16 +57,16 @@ class ShippingType { } String getTitle() { - if (this.object != null) { - switch (this.methodId) { + if (object != null) { + switch (methodId) { case "flat_rate": - FlatRate flatRate = (this.object as FlatRate); + FlatRate flatRate = (object as FlatRate); return flatRate.title; case "free_shipping": - FreeShipping freeShipping = (this.object as FreeShipping); + FreeShipping freeShipping = (object as FreeShipping); return freeShipping.title; case "local_pickup": - LocalPickup localPickup = (this.object as LocalPickup); + LocalPickup localPickup = (object as LocalPickup); return localPickup.title; default: return ""; @@ -76,27 +76,27 @@ class ShippingType { } Map toShippingLineFee() { - if (this.object != null) { + if (object != null) { Map tmpShippingLinesObj = {}; - switch (this.methodId) { + switch (methodId) { case "flat_rate": - FlatRate flatRate = (this.object as FlatRate); + FlatRate flatRate = (object as FlatRate); tmpShippingLinesObj["method_title"] = flatRate.title; tmpShippingLinesObj["method_id"] = flatRate.methodId; - tmpShippingLinesObj["total"] = this.cost; + tmpShippingLinesObj["total"] = cost; break; case "free_shipping": - FreeShipping freeShipping = (this.object as FreeShipping); + FreeShipping freeShipping = (object as FreeShipping); tmpShippingLinesObj["method_title"] = freeShipping.title; tmpShippingLinesObj["method_id"] = freeShipping.methodId; - tmpShippingLinesObj["total"] = this.cost; + tmpShippingLinesObj["total"] = cost; break; case "local_pickup": - LocalPickup localPickup = (this.object as LocalPickup); + LocalPickup localPickup = (object as LocalPickup); tmpShippingLinesObj["method_title"] = localPickup.title; tmpShippingLinesObj["method_id"] = localPickup.methodId; - tmpShippingLinesObj["total"] = this.cost; + tmpShippingLinesObj["total"] = cost; break; default: return null; diff --git a/LabelStoreMax/lib/app/models/user.dart b/LabelStoreMax/lib/app/models/user.dart index 087919f..25fdbfe 100644 --- a/LabelStoreMax/lib/app/models/user.dart +++ b/LabelStoreMax/lib/app/models/user.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -18,11 +18,11 @@ class User extends Storable { User.fromUserAuthResponse({this.userId, this.token}); @override - toStorage() => {"token": this.token, "user_id": this.userId}; + toStorage() => {"token": token, "user_id": userId}; @override fromStorage(dynamic data) { - this.token = data['token']; - this.userId = data['user_id']; + token = data['token']; + userId = data['user_id']; } } diff --git a/LabelStoreMax/lib/app/networking/api_service.dart b/LabelStoreMax/lib/app/networking/api_service.dart index b538257..e391760 100644 --- a/LabelStoreMax/lib/app/networking/api_service.dart +++ b/LabelStoreMax/lib/app/networking/api_service.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/providers/cash_on_delivery.dart b/LabelStoreMax/lib/app/providers/cash_on_delivery.dart index a269c27..4015f41 100644 --- a/LabelStoreMax/lib/app/providers/cash_on_delivery.dart +++ b/LabelStoreMax/lib/app/providers/cash_on_delivery.dart @@ -3,7 +3,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/providers/example_pay.dart b/LabelStoreMax/lib/app/providers/example_pay.dart index 61f818c..3fdbe35 100644 --- a/LabelStoreMax/lib/app/providers/example_pay.dart +++ b/LabelStoreMax/lib/app/providers/example_pay.dart @@ -3,7 +3,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app/providers/paypal_pay.dart b/LabelStoreMax/lib/app/providers/paypal_pay.dart index 1eddab4..f19027f 100644 --- a/LabelStoreMax/lib/app/providers/paypal_pay.dart +++ b/LabelStoreMax/lib/app/providers/paypal_pay.dart @@ -3,7 +3,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -39,38 +39,36 @@ payPalPay(context, showToastNotification( context, title: trans("Payment Cancelled"), - description: - trans("The payment has been cancelled"), + description: trans("The payment has been cancelled"), ); state.reloadState(showLoader: false); return; } - state.reloadState(showLoader: true); - if (value.containsKey("status") && value["status"] == "success") { - OrderWC orderWC = - await buildOrderWC(taxRate: taxRate, markPaid: true); - Order order = await appWooSignal((api) => api.createOrder(orderWC)); + state.reloadState(showLoader: true); + if (value.containsKey("status") && value["status"] == "success") { + OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true); + Order order = await appWooSignal((api) => api.createOrder(orderWC)); - if (order == null) { - showToastNotification( - context, - title: trans("Error"), - description: trans("Something went wrong, please contact our store"), - ); - return; - } - Navigator.pushNamed(context, "/checkout-status", arguments: order); - return; - } else { + if (order == null) { showToastNotification( context, - title: trans("Payment Cancelled"), - description: trans("The payment has been cancelled"), + title: trans("Error"), + description: + trans("Something went wrong, please contact our store"), ); + return; } + Navigator.pushNamed(context, "/checkout-status", arguments: order); + return; + } else { + showToastNotification( + context, + title: trans("Payment Cancelled"), + description: trans("The payment has been cancelled"), + ); } - ); + }); state.reloadState(showLoader: false); }); } diff --git a/LabelStoreMax/lib/app/providers/stripe_pay.dart b/LabelStoreMax/lib/app/providers/stripe_pay.dart index 7c1a6fc..0740f98 100644 --- a/LabelStoreMax/lib/app/providers/stripe_pay.dart +++ b/LabelStoreMax/lib/app/providers/stripe_pay.dart @@ -3,7 +3,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -32,13 +32,17 @@ stripePay(context, : getEnv('STRIPE_LIVE_MODE', defaultValue: false); // CONFIGURE STRIPE - Stripe.stripeAccountId = getEnv('STRIPE_ACCOUNT') == null ? wooSignalApp.stripeAccount : getEnv('STRIPE_ACCOUNT'); + Stripe.stripeAccountId = + getEnv('STRIPE_ACCOUNT') ?? wooSignalApp.stripeAccount; - Stripe.publishableKey = liveMode ? "pk_live_IyS4Vt86L49jITSfaUShumzi" : "pk_test_0jMmpBntJ6UkizPkfiB8ZJxH"; // Don't change this value + Stripe.publishableKey = liveMode + ? "pk_live_IyS4Vt86L49jITSfaUShumzi" + : "pk_test_0jMmpBntJ6UkizPkfiB8ZJxH"; // Don't change this value await Stripe.instance.applySettings(); if (Stripe.stripeAccountId == '') { - NyLogger.error('You need to connect your Stripe account to WooSignal via the dashboard https://woosignal.com/dashboard'); + NyLogger.error( + 'You need to connect your Stripe account to WooSignal via the dashboard https://woosignal.com/dashboard'); return; } @@ -51,14 +55,12 @@ stripePay(context, "line1": billingDetails.shippingAddress.addressLine, "city": billingDetails.shippingAddress.city, "postal_code": billingDetails.shippingAddress.postalCode, - "country": - (billingDetails.shippingAddress?.customerCountry?.name ?? "") + "country": (billingDetails.shippingAddress?.customerCountry?.name ?? "") }; String cartShortDesc = await cart.cartShortDesc(); - rsp = await appWooSignal((api) => - api.stripePaymentIntent( + rsp = await appWooSignal((api) => api.stripePaymentIntent( amount: total, email: billingDetails.billingAddress.emailAddress, desc: cartShortDesc, @@ -69,21 +71,25 @@ stripePay(context, if (rsp == null) { showToastNotification(context, title: trans("Oops!"), - description: - trans("Something went wrong, please try again."), + description: trans("Something went wrong, please try again."), icon: Icons.payment, style: ToastNotificationStyleType.WARNING); state.reloadState(showLoader: false); return; } - await Stripe.instance.initPaymentSheet(paymentSheetParameters: SetupPaymentSheetParameters( + await Stripe.instance.initPaymentSheet( + paymentSheetParameters: SetupPaymentSheetParameters( applePay: false, googlePay: false, - style: Theme.of(state.context).brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark, + style: Theme.of(state.context).brightness == Brightness.light + ? ThemeMode.light + : ThemeMode.dark, testEnv: liveMode, - merchantCountryCode: envVal('STRIPE_COUNTRY_CODE', defaultValue: wooSignalApp.stripeCountryCode), - merchantDisplayName: envVal('APP_NAME', defaultValue: wooSignalApp.appName), + merchantCountryCode: envVal('STRIPE_COUNTRY_CODE', + defaultValue: wooSignalApp.stripeCountryCode), + merchantDisplayName: + envVal('APP_NAME', defaultValue: wooSignalApp.appName), paymentIntentClientSecret: rsp['client_secret'], )); @@ -105,8 +111,7 @@ stripePay(context, } Navigator.pushNamed(context, "/checkout-status", arguments: order); - - } on StripeException catch(e) { + } on StripeException catch (e) { if (getEnv('APP_DEBUG', defaultValue: true)) { NyLogger.error(e.error.message); } diff --git a/LabelStoreMax/lib/bootstrap/app.dart b/LabelStoreMax/lib/bootstrap/app.dart index 2042eac..d3314f9 100644 --- a/LabelStoreMax/lib/bootstrap/app.dart +++ b/LabelStoreMax/lib/bootstrap/app.dart @@ -62,11 +62,17 @@ class AppBuild extends StatelessWidget { Widget build(BuildContext context) { return LocalizedApp( child: ThemeProvider( - themes: appThemes.map((appTheme) => appTheme.toAppTheme(defaultTheme: appTheme.theme.brightness == Brightness.light ? lightTheme : darkTheme)).toList(), + themes: appThemes + .map((appTheme) => appTheme.toAppTheme( + defaultTheme: appTheme.theme.brightness == Brightness.light + ? lightTheme + : darkTheme)) + .toList(), child: ThemeConsumer( child: Builder( builder: (themeContext) => ValueListenableBuilder( - valueListenable: ValueNotifier(locale ?? NyLocalization.instance.locale), + valueListenable: + ValueNotifier(locale ?? NyLocalization.instance.locale), builder: (context, Locale locale, _) => MaterialApp( navigatorKey: navigatorKey, themeMode: themeMode, @@ -86,8 +92,8 @@ class AppBuild extends StatelessWidget { actions: actions, title: title ?? "", initialRoute: initialRoute, - onGenerateRoute: this.onGenerateRoute, - darkTheme: this.darkTheme == null ? ThemeConfig.dark().theme : this.darkTheme, + onGenerateRoute: onGenerateRoute, + darkTheme: darkTheme ?? ThemeConfig.dark().theme, theme: themeData ?? ThemeProvider.themeOf(context).data, localeResolutionCallback: (Locale locale, Iterable supportedLocales) { @@ -95,7 +101,8 @@ class AppBuild extends StatelessWidget { }, localizationsDelegates: NyLocalization.instance.delegates, locale: NyLocalization.instance.locale, - supportedLocales: supportedLocales ?? NyLocalization.instance.locals(), + supportedLocales: + supportedLocales ?? NyLocalization.instance.locals(), ), ), ), diff --git a/LabelStoreMax/lib/bootstrap/app_helper.dart b/LabelStoreMax/lib/bootstrap/app_helper.dart index 1486c10..92474df 100644 --- a/LabelStoreMax/lib/bootstrap/app_helper.dart +++ b/LabelStoreMax/lib/bootstrap/app_helper.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/bootstrap/base_theme_config.dart b/LabelStoreMax/lib/bootstrap/base_theme_config.dart index 0ece194..1c700a8 100644 --- a/LabelStoreMax/lib/bootstrap/base_theme_config.dart +++ b/LabelStoreMax/lib/bootstrap/base_theme_config.dart @@ -9,11 +9,16 @@ class BaseThemeConfig { final BaseColorStyles colors; final dynamic meta; - BaseThemeConfig({this.id, this.description, this.theme, this.colors, this.meta = const {}}); + BaseThemeConfig( + {this.id, + this.description, + this.theme, + this.colors, + this.meta = const {}}); AppTheme toAppTheme({ThemeData defaultTheme}) => AppTheme( - id: this.id, - data: defaultTheme == null ? this.theme : defaultTheme, - description: this.description, - ); -} \ No newline at end of file + id: id, + data: defaultTheme ?? theme, + description: description, + ); +} diff --git a/LabelStoreMax/lib/bootstrap/boot.dart b/LabelStoreMax/lib/bootstrap/boot.dart index f6250e8..838075b 100644 --- a/LabelStoreMax/lib/bootstrap/boot.dart +++ b/LabelStoreMax/lib/bootstrap/boot.dart @@ -12,12 +12,12 @@ import 'package:wp_json_api/wp_json_api.dart'; /// boot application Future boot() async { - await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); - await WooSignal.instance.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG')); + await WooSignal.instance + .init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG')); // Notifications /// await Firebase.initializeApp( @@ -78,7 +78,8 @@ Future boot() async { ); } - if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null && wooSignalApp.locale != null) { + if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null && + wooSignalApp.locale != null) { locale = Locale(wooSignalApp.locale); } else { locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en')); @@ -91,6 +92,5 @@ Future boot() async { languageCode: locale.languageCode, languagesList: languagesList, assetsDirectory: assetsDirectory, - valuesAsMap: valuesAsMap - ); -} \ No newline at end of file + valuesAsMap: valuesAsMap); +} diff --git a/LabelStoreMax/lib/bootstrap/data/order_wc.dart b/LabelStoreMax/lib/bootstrap/data/order_wc.dart index 92e3c12..8904fcf 100644 --- a/LabelStoreMax/lib/bootstrap/data/order_wc.dart +++ b/LabelStoreMax/lib/bootstrap/data/order_wc.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -21,10 +21,11 @@ import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/woosignal_app.dart'; Future buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { + CheckoutSession checkoutSession = CheckoutSession.getInstance; OrderWC orderWC = OrderWC(); WooSignalApp wooSignalApp = AppHelper.instance.appConfig; - String paymentMethodName = CheckoutSession.getInstance.paymentType.name ?? ""; + String paymentMethodName = checkoutSession.paymentType.name ?? ""; orderWC.paymentMethod = Platform.isAndroid ? "$paymentMethodName - Android App" @@ -40,7 +41,7 @@ Future buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { List lineItems = []; List cartItems = await Cart.getInstance.getCart(); - cartItems.forEach((cartItem) { + for (var cartItem in cartItems) { LineItems tmpLineItem = LineItems(); tmpLineItem.quantity = cartItem.quantity; tmpLineItem.name = cartItem.name; @@ -51,11 +52,11 @@ Future buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { tmpLineItem.subtotal = cartItem.subtotal; lineItems.add(tmpLineItem); - }); + } orderWC.lineItems = lineItems; - BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails; + BillingDetails billingDetails = checkoutSession.billingDetails; Billing billing = Billing(); billing.firstName = billingDetails.billingAddress.firstName; @@ -88,7 +89,7 @@ Future buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { orderWC.shippingLines = []; if (wooSignalApp.disableShipping != 1) { Map shippingLineFeeObj = - CheckoutSession.getInstance.shippingType.toShippingLineFee(); + checkoutSession.shippingType.toShippingLineFee(); if (shippingLineFeeObj != null) { ShippingLines shippingLine = ShippingLines(); shippingLine.methodId = shippingLineFeeObj['method_id']; @@ -108,5 +109,11 @@ Future buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { orderWC.feeLines.add(feeLines); } + if (checkoutSession.coupon != null) { + orderWC.couponLines = []; + CouponLines couponLine = CouponLines(code: checkoutSession.coupon.code); + orderWC.couponLines.add(couponLine); + } + return orderWC; } diff --git a/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart b/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart index 49f63ef..b001c12 100644 --- a/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart +++ b/LabelStoreMax/lib/bootstrap/enums/sort_enums.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -9,8 +9,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. enum SortByType { - LowToHigh, - HighToLow, - NameAZ, - NameZA, + lowToHigh, + highToLow, + nameAZ, + nameZA, } diff --git a/LabelStoreMax/lib/bootstrap/enums/symbol_position_enums.dart b/LabelStoreMax/lib/bootstrap/enums/symbol_position_enums.dart index 35498ee..c016f4f 100644 --- a/LabelStoreMax/lib/bootstrap/enums/symbol_position_enums.dart +++ b/LabelStoreMax/lib/bootstrap/enums/symbol_position_enums.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/bootstrap/helpers.dart b/LabelStoreMax/lib/bootstrap/helpers.dart index e4b8a0b..9b8537a 100644 --- a/LabelStoreMax/lib/bootstrap/helpers.dart +++ b/LabelStoreMax/lib/bootstrap/helpers.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -44,53 +44,70 @@ import 'package:woosignal/woosignal.dart'; Future getUser() async => (await NyStorage.read(SharedKey.authUser, model: User())); -appWooSignal(Function(WooSignal) api) async { +Future appWooSignal(Function(WooSignal) api) async { return await api(WooSignal.instance); } /// helper to find correct color from the [context]. class ThemeColor { static BaseColorStyles get(BuildContext context) { - return ((Theme.of(context).brightness == Brightness.light) ? ThemeConfig.light().colors : ThemeConfig.dark().colors); + return ((Theme.of(context).brightness == Brightness.light) + ? ThemeConfig.light().colors + : ThemeConfig.dark().colors); } } /// helper to set colors on TextStyle extension ColorsHelper on TextStyle { - TextStyle setColor(BuildContext context, Color Function(BaseColorStyles color) newColor) { - return this.copyWith(color: newColor(ThemeColor.get(context))); + TextStyle setColor( + BuildContext context, Color Function(BaseColorStyles color) newColor) { + return copyWith(color: newColor(ThemeColor.get(context))); } } List getPaymentTypes() { List paymentTypes = []; - app_payment_gateways.forEach((element) { - if (paymentTypes.firstWhere((paymentType) => paymentType.name != element, orElse: () => null) == null) { - paymentTypes.add(paymentTypeList.firstWhere((paymentTypeList) => paymentTypeList.name == element, orElse: () => null)); + for (var appPaymentGateway in app_payment_gateways) { + if (paymentTypes.firstWhere( + (paymentType) => paymentType.name != appPaymentGateway, + orElse: () => null) == + null) { + paymentTypes.add(paymentTypeList.firstWhere( + (paymentTypeList) => paymentTypeList.name == appPaymentGateway, + orElse: () => null)); } - }); + } - if (!app_payment_gateways.contains('Stripe') && AppHelper.instance.appConfig.stripeEnabled == true) { - paymentTypes.add(paymentTypeList.firstWhere((element) => element.name == "Stripe", orElse: () => null)); + if (!app_payment_gateways.contains('Stripe') && + AppHelper.instance.appConfig.stripeEnabled == true) { + paymentTypes.add(paymentTypeList + .firstWhere((element) => element.name == "Stripe", orElse: () => null)); } - if (!app_payment_gateways.contains('PayPal') && AppHelper.instance.appConfig.paypalEnabled == true) { - paymentTypes.add(paymentTypeList.firstWhere((element) => element.name == "PayPal", orElse: () => null)); + if (!app_payment_gateways.contains('PayPal') && + AppHelper.instance.appConfig.paypalEnabled == true) { + paymentTypes.add(paymentTypeList + .firstWhere((element) => element.name == "PayPal", orElse: () => null)); } - if (!app_payment_gateways.contains('CashOnDelivery') && AppHelper.instance.appConfig.codEnabled == true) { - paymentTypes.add(paymentTypeList.firstWhere((element) => element.name == "CashOnDelivery", orElse: () => null)); + if (!app_payment_gateways.contains('CashOnDelivery') && + AppHelper.instance.appConfig.codEnabled == true) { + paymentTypes.add(paymentTypeList.firstWhere( + (element) => element.name == "CashOnDelivery", + orElse: () => null)); } return paymentTypes.where((v) => v != null).toList(); } -dynamic envVal(String envVal, {dynamic defaultValue}) => (getEnv(envVal) == null ? defaultValue : getEnv(envVal)); +dynamic envVal(String envVal, {dynamic defaultValue}) => + (getEnv(envVal) == null ? defaultValue : getEnv(envVal)); PaymentType addPayment( {@required int id, @required String name, @required String desc, @required String assetImage, - @required Function pay}) => PaymentType( + @required Function pay}) => + PaymentType( id: id, name: name, desc: desc, @@ -333,7 +350,7 @@ RegExp defaultRegex( String pattern, { bool strict, }) { - return new RegExp( + return RegExp( pattern, caseSensitive: strict ?? false, multiLine: false, @@ -343,17 +360,10 @@ RegExp defaultRegex( bool isEmail(String em) { String p = r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; - RegExp regExp = new RegExp(p); + RegExp regExp = RegExp(p); return regExp.hasMatch(em); } -// 6 LENGTH, 1 DIGIT -bool validPassword(String pw) { - String p = r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{6,}$'; - RegExp regExp = new RegExp(p); - return regExp.hasMatch(pw); -} - navigatorPush(BuildContext context, {@required String routeName, Object arguments, @@ -391,8 +401,7 @@ showPlatformAlertDialog(BuildContext context, List actions, bool showDoneAction = true}) { if (showDoneAction) { - actions - .add(dialogAction(context, title: trans("Done"), action: () { + actions.add(dialogAction(context, title: trans("Done"), action: () { Navigator.of(context).pop(); })); } @@ -422,22 +431,22 @@ String dateFormatted({@required String date, @required String formatType}) => formatDateTime(formatType).format(parseDateTime(date)); enum FormatType { - DateTime, - Date, - Time, + dateTime, + date, + time, } String formatForDateTime(FormatType formatType) { switch (formatType) { - case FormatType.Date: + case FormatType.date: { return "yyyy-MM-dd"; } - case FormatType.DateTime: + case FormatType.dateTime: { return "dd-MM-yyyy hh:mm a"; } - case FormatType.Time: + case FormatType.time: { return "hh:mm a"; } @@ -450,9 +459,6 @@ String formatForDateTime(FormatType formatType) { double parseWcPrice(String price) => (double.tryParse(price ?? "0") ?? 0); -void appLogOutput(dynamic message) => - (getEnv('APP_DEBUG', defaultValue: true) ? NyLogger.debug(message) : null); - Widget refreshableScroll(context, {@required refreshController, @required VoidCallback onRefresh, @@ -486,7 +492,7 @@ Widget refreshableScroll(context, controller: refreshController, onRefresh: onRefresh, onLoading: onLoading, - child: (products.length != null && products.length > 0 + child: (products.length != null && products.isNotEmpty ? StaggeredGridView.countBuilder( crossAxisCount: 2, itemCount: products.length, @@ -494,13 +500,12 @@ Widget refreshableScroll(context, return Container( height: 200, child: ProductItemContainer( - index: (index), product: products[index], onTap: onTap, ), ); }, - staggeredTileBuilder: (int index) => new StaggeredTile.fit(1), + staggeredTileBuilder: (int index) => StaggeredTile.fit(1), mainAxisSpacing: 4.0, crossAxisSpacing: 4.0, ) @@ -538,3 +543,31 @@ Future> getDefaultShipping(BuildContext context) async { String truncateString(String data, int length) { return (data.length >= length) ? '${data.substring(0, length)}...' : data; } + +Future> getWishlistProducts() async { + List favouriteProducts = []; + String currentProductsJSON = await NyStorage.read(SharedKey.wishlistProducts); + if (currentProductsJSON != null) { + favouriteProducts = + (jsonDecode(currentProductsJSON) as List).toList(); + } + return favouriteProducts; +} + +saveWishlistProduct({@required Product product}) async { + List products = await getWishlistProducts(); + if (products.any((wishListProduct) => wishListProduct['id'] == product.id) == + false) { + products.add({"id": product.id}); + } + String json = jsonEncode(products.map((i) => {"id": i['id']}).toList()); + await NyStorage.store(SharedKey.wishlistProducts, json); +} + +removeWishlistProduct({@required Product product}) async { + List products = await getWishlistProducts(); + products.removeWhere((element) => element['id'] == product.id); + + String json = jsonEncode(products.map((i) => {"id": i['id']}).toList()); + await NyStorage.store(SharedKey.wishlistProducts, json); +} diff --git a/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart b/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart index f4d923e..92818c3 100644 --- a/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart +++ b/LabelStoreMax/lib/bootstrap/shared_pref/shared_key.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -13,4 +13,5 @@ class SharedKey { static const String cart = "CART_SESSION"; static const String customerBillingDetails = "CS_BILLING_DETAILS"; static const String customerShippingDetails = "CS_SHIPPING_DETAILS"; + static const String wishlistProducts = "CS_WISHLIST_PRODUCTS"; } diff --git a/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart b/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart index 98baba0..ddac8b2 100644 --- a/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart +++ b/LabelStoreMax/lib/bootstrap/shared_pref/sp_auth.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/config/app_font.dart b/LabelStoreMax/lib/config/app_font.dart index 171c945..2ef2974 100644 --- a/LabelStoreMax/lib/config/app_font.dart +++ b/LabelStoreMax/lib/config/app_font.dart @@ -16,4 +16,4 @@ import 'package:google_fonts/google_fonts.dart'; TextStyle appFont = GoogleFonts.poppins(); // e.g. custom font in pubspec.yaml - https://flutter.dev/docs/cookbook/design/fonts -// final TextStyle appThemeFont = TextStyle(fontFamily: "ZenTokyoZoo"); \ No newline at end of file +// final TextStyle appThemeFont = TextStyle(fontFamily: "ZenTokyoZoo"); diff --git a/LabelStoreMax/lib/config/app_localization.dart b/LabelStoreMax/lib/config/app_localization.dart index f2158b3..156fe65 100644 --- a/LabelStoreMax/lib/config/app_localization.dart +++ b/LabelStoreMax/lib/config/app_localization.dart @@ -54,4 +54,4 @@ final String assetsDirectory = 'lang/'; | the asset json files. |-------------------------------------------------------------------------- */ -final Map valuesAsMap = {}; \ No newline at end of file +final Map valuesAsMap = {}; diff --git a/LabelStoreMax/lib/config/app_theme.dart b/LabelStoreMax/lib/config/app_theme.dart index 1324f2b..036df2e 100644 --- a/LabelStoreMax/lib/config/app_theme.dart +++ b/LabelStoreMax/lib/config/app_theme.dart @@ -13,9 +13,7 @@ import 'package:flutter_app/resources/themes/styles/light_theme_colors.dart'; // App Themes final appThemes = [ - ThemeConfig.light(), - ThemeConfig.dark(), ]; @@ -39,46 +37,45 @@ BaseColorStyles darkColors = DarkThemeColors(); // Preset Themes class ThemeConfig { - // LIGHT static BaseThemeConfig light() => BaseThemeConfig( - id: "default_light_theme", - description: "Light theme", - theme: lightTheme(lightColors), - colors: lightColors, - ); + id: "default_light_theme", + description: "Light theme", + theme: lightTheme(lightColors), + colors: lightColors, + ); // DARK static BaseThemeConfig dark() => BaseThemeConfig( - id: "default_dark_theme", - description: "Dark theme", - theme: darkTheme(darkColors), - colors: darkColors, - ); + id: "default_dark_theme", + description: "Dark theme", + theme: darkTheme(darkColors), + colors: darkColors, + ); // E.G. CUSTOM THEME -/// Run: "flutter pub run nylo_framework:main make:theme bright_theme" // example bright_theme + /// Run: "flutter pub run nylo_framework:main make:theme bright_theme" // example bright_theme // Creates a basic theme in /resources/themes/bright_theme.dart // Creates the themes colors in /resources/themes/styles/bright_theme_colors.dart // First add the colors which was created into the above section like the following: // Bright Colors -/// BaseColorStyles brightColors = BrightThemeColors(); + /// BaseColorStyles brightColors = BrightThemeColors(); // Next, uncomment the below: -/// static BaseThemeConfig bright() => BaseThemeConfig( -/// id: "default_bright_theme", -/// description: "Bright theme", -/// theme: brightTheme(brightColors), -/// colors: brightColors, -/// ); + /// static BaseThemeConfig bright() => BaseThemeConfig( + /// id: "default_bright_theme", + /// description: "Bright theme", + /// theme: brightTheme(brightColors), + /// colors: brightColors, + /// ); // To then use this theme, add it to the [appThemes] above like the following: // final appThemes = [ -/// ThemeConfig.bright(), // new theme + /// ThemeConfig.bright(), // new theme // // ThemeConfig.light(), // // ThemeConfig.dark(), // ]; -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/generated_plugin_registrant.dart b/LabelStoreMax/lib/generated_plugin_registrant.dart new file mode 100644 index 0000000..b3657a6 --- /dev/null +++ b/LabelStoreMax/lib/generated_plugin_registrant.dart @@ -0,0 +1,20 @@ +// +// Generated file. Do not edit. +// + +// ignore_for_file: directives_ordering +// ignore_for_file: lines_longer_than_80_chars + +import 'package:flutter_secure_storage_web/flutter_secure_storage_web.dart'; +import 'package:shared_preferences_web/shared_preferences_web.dart'; +import 'package:url_launcher_web/url_launcher_web.dart'; + +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + +// ignore: public_member_api_docs +void registerPlugins(Registrar registrar) { + FlutterSecureStorageWeb.registerWith(registrar); + SharedPreferencesPlugin.registerWith(registrar); + UrlLauncherPlugin.registerWith(registrar); + registrar.registerMessageHandler(); +} diff --git a/LabelStoreMax/lib/main.dart b/LabelStoreMax/lib/main.dart index 7d84b60..462c7ed 100644 --- a/LabelStoreMax/lib/main.dart +++ b/LabelStoreMax/lib/main.dart @@ -9,7 +9,9 @@ void main() async { WidgetsFlutterBinding.ensureInitialized(); Nylo nylo = await Nylo.init(router: appRouter(), setup: boot); - String initialRoute = AppHelper.instance.appConfig.appStatus != null ? '/home' : '/no-connection'; + String initialRoute = AppHelper.instance.appConfig.appStatus != null + ? '/home' + : '/no-connection'; runApp( AppBuild( diff --git a/LabelStoreMax/lib/resources/pages/account_billing_details.dart b/LabelStoreMax/lib/resources/pages/account_billing_details.dart index e03fad2..526261f 100644 --- a/LabelStoreMax/lib/resources/pages/account_billing_details.dart +++ b/LabelStoreMax/lib/resources/pages/account_billing_details.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -32,7 +32,7 @@ class _AccountBillingDetailsPageState extends State { _AccountBillingDetailsPageState(); // BILLING TEXT CONTROLLERS - TextEditingController _txtShippingFirstName = TextEditingController(), + final TextEditingController _txtShippingFirstName = TextEditingController(), _txtShippingLastName = TextEditingController(), _txtShippingAddressLine = TextEditingController(), _txtShippingCity = TextEditingController(), @@ -71,18 +71,15 @@ class _AccountBillingDetailsPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - title: Text( - trans("Billing Details") - ), + title: Text(trans("Billing Details")), centerTitle: true, ), body: SafeAreaWidget( child: GestureDetector( - onTap: () => FocusScope.of(context).requestFocus(new FocusNode()), + onTap: () => FocusScope.of(context).requestFocus(FocusNode()), child: _isLoading ? AppLoaderWidget() : LayoutBuilder( @@ -160,8 +157,10 @@ class _AccountBillingDetailsPageState extends State { decoration: BoxDecoration( color: ThemeColor.get(context).surfaceBackground, borderRadius: BorderRadius.circular(10), - boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + boxShadow: (Theme.of(context).brightness == + Brightness.light) + ? wsBoxShadow() + : null, ), padding: EdgeInsets.all(8), ), diff --git a/LabelStoreMax/lib/resources/pages/account_detail.dart b/LabelStoreMax/lib/resources/pages/account_detail.dart index 2f1784f..d488caa 100644 --- a/LabelStoreMax/lib/resources/pages/account_detail.dart +++ b/LabelStoreMax/lib/resources/pages/account_detail.dart @@ -1,17 +1,17 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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:bubble_tab_indicator/bubble_tab_indicator.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app/app/controllers/customer_orders_loader_controller.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart'; import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; @@ -33,15 +33,14 @@ class AccountDetailPage extends StatefulWidget { class _AccountDetailPageState extends State with SingleTickerProviderStateMixin { - RefreshController _refreshController = + final RefreshController _refreshController = RefreshController(initialRefresh: false); - bool _shouldStopRequests = false, - waitForNextRequest = false, - _isLoading = true, - _isLoadingOrders = true; + final CustomerOrdersLoaderController _customerOrdersLoaderController = + CustomerOrdersLoaderController(); - int _page = 1, _currentTabIndex = 0; - List _orders = []; + bool _shouldStopRequests = false, _isLoading = true, _isLoadingOrders = true; + + int _currentTabIndex = 0; WCCustomerInfoResponse _wcCustomerInfoResponse; Widget _activeBody; @@ -51,20 +50,18 @@ class _AccountDetailPageState extends State @override void initState() { super.initState(); - _page = 1; - _orders = []; _tabs = [ - new Tab(text: ""), - new Tab(text: ""), + Tab(text: ""), + Tab(text: ""), ]; _tabController = TabController(vsync: this, length: _tabs.length); _activeBody = AppLoaderWidget(); - this.init(); + init(); } init() async { await _fetchWpUserData(); - await _fetchOrders(); + await fetchOrders(); } _fetchWpUserData() async { @@ -98,22 +95,22 @@ class _AccountDetailPageState extends State @override Widget build(BuildContext context) { _tabs = [ - new Tab(text: trans("Orders")), - new Tab(text: trans("Settings")), + Tab(text: trans("Orders")), + Tab(text: trans("Settings")), ]; return Scaffold( appBar: AppBar( - leading: widget.showLeadingBackButton ? Container( - child: IconButton( - icon: Icon(Icons.arrow_back_ios), - onPressed: () => Navigator.pop(context), - ), - margin: EdgeInsets.only(left: 0), - ) : Container(), - title: Text( - trans("Account") - ), + leading: widget.showLeadingBackButton + ? Container( + child: IconButton( + icon: Icon(Icons.arrow_back_ios), + onPressed: () => Navigator.pop(context), + ), + margin: EdgeInsets.only(left: 0), + ) + : Container(), + title: Text(trans("Account")), centerTitle: true, ), resizeToAvoidBottomInset: false, @@ -191,7 +188,7 @@ class _AccountDetailPageState extends State indicatorSize: TabBarIndicatorSize.tab, labelColor: Colors.white, unselectedLabelColor: Colors.black87, - indicator: new BubbleTabIndicator( + indicator: BubbleTabIndicator( indicatorHeight: 25.0, indicatorColor: Colors.black87, tabBarIndicatorSize: TabBarIndicatorSize.tab, @@ -204,7 +201,10 @@ class _AccountDetailPageState extends State ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), - boxShadow: (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + boxShadow: + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, color: ThemeColor.get(context).backgroundContainer, ), ), @@ -275,38 +275,34 @@ class _AccountDetailPageState extends State ); } - _fetchOrders() async { + fetchOrders() async { String userId = await readUserId(); - - if (userId == null || _shouldStopRequests == true) { + if (userId == null) { setState(() { _isLoadingOrders = false; _activeBody = _widgetOrders(); }); return; } - - List orders = await appWooSignal((api) => - api.getOrders(customer: int.parse(userId), page: _page, perPage: 50)); - - if (orders.length <= 0) { - setState(() { - _isLoadingOrders = false; - _shouldStopRequests = true; - _activeBody = _widgetOrders(); - }); - return; - } - - setState(() { - _page += 1; - _orders.addAll(orders); - _isLoadingOrders = false; - _activeBody = _widgetOrders(); - }); + await _customerOrdersLoaderController.loadOrders( + hasResults: (result) { + if (result == false) { + _isLoadingOrders = false; + _shouldStopRequests = true; + _activeBody = _widgetOrders(); + return false; + } + return true; + }, + didFinish: () => setState(() { + _isLoadingOrders = false; + _activeBody = _widgetOrders(); + }), + userId: userId); } Widget _widgetOrders() { + List orders = _customerOrdersLoaderController.getResults(); return _isLoadingOrders ? AppLoaderWidget() : SmartRefresher( @@ -335,9 +331,10 @@ class _AccountDetailPageState extends State controller: _refreshController, onRefresh: _onRefresh, onLoading: _onLoading, - child: (_orders.length > 0 + child: (orders.isNotEmpty ? ListView.builder( itemBuilder: (cxt, i) { + Order order = orders[i]; return Card( child: ListTile( contentPadding: EdgeInsets.only( @@ -356,12 +353,12 @@ class _AccountDetailPageState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - "#${_orders[i].id.toString()}", + "#${order.id.toString()}", maxLines: 1, overflow: TextOverflow.ellipsis, ), Text( - _orders[i].status.capitalize(), + order.status.capitalize(), maxLines: 1, overflow: TextOverflow.ellipsis, ), @@ -379,8 +376,7 @@ class _AccountDetailPageState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - formatStringCurrency( - total: _orders[i].total), + formatStringCurrency(total: order.total), style: Theme.of(context) .textTheme .bodyText2 @@ -389,7 +385,7 @@ class _AccountDetailPageState extends State textAlign: TextAlign.left, ), Text( - _orders[i].lineItems.length.toString() + + order.lineItems.length.toString() + " " + trans("items"), style: Theme.of(context) @@ -403,15 +399,15 @@ class _AccountDetailPageState extends State ), Text( dateFormatted( - date: _orders[i].dateCreated, + date: order.dateCreated, formatType: - formatForDateTime(FormatType.Date), + formatForDateTime(FormatType.date), ) + "\n" + dateFormatted( - date: _orders[i].dateCreated, + date: order.dateCreated, formatType: - formatForDateTime(FormatType.Time), + formatForDateTime(FormatType.time), ), textAlign: TextAlign.right, style: Theme.of(context) @@ -434,7 +430,7 @@ class _AccountDetailPageState extends State ), ); }, - itemCount: _orders.length, + itemCount: orders.length, ) : Center( child: Column( @@ -456,16 +452,15 @@ class _AccountDetailPageState extends State } void _onRefresh() async { - _orders = []; - _page = 1; + _customerOrdersLoaderController.clear(); _shouldStopRequests = false; - waitForNextRequest = false; - await _fetchOrders(); + + await fetchOrders(); _refreshController.refreshCompleted(); } void _onLoading() async { - await _fetchOrders(); + await fetchOrders(); if (mounted) { setState(() {}); @@ -480,6 +475,6 @@ class _AccountDetailPageState extends State _viewProfileDetail(int i) => Navigator.pushNamed( context, "/account-order-detail", - arguments: _orders[i].id, + arguments: _customerOrdersLoaderController.getResults()[i].id, ); } diff --git a/LabelStoreMax/lib/resources/pages/account_landing.dart b/LabelStoreMax/lib/resources/pages/account_landing.dart index 33fb283..b0cbc5a 100644 --- a/LabelStoreMax/lib/resources/pages/account_landing.dart +++ b/LabelStoreMax/lib/resources/pages/account_landing.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -33,7 +33,7 @@ class AccountLandingPage extends StatefulWidget { class _AccountLandingPageState extends State { bool _hasTappedLogin = false; - TextEditingController _tfEmailController = TextEditingController(), + final TextEditingController _tfEmailController = TextEditingController(), _tfPasswordController = TextEditingController(); @override @@ -75,7 +75,10 @@ class _AccountLandingPageState extends State { Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), - boxShadow: (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + boxShadow: + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, color: ThemeColor.get(context).backgroundContainer, ), padding: EdgeInsets.symmetric(vertical: 18, horizontal: 8), @@ -110,8 +113,9 @@ class _AccountLandingPageState extends State { children: [ Icon( Icons.account_circle, - color: - (Theme.of(context).brightness == Brightness.light) ? Colors.black38 : Colors.white70, + color: (Theme.of(context).brightness == Brightness.light) + ? Colors.black38 + : Colors.white70, ), Padding( child: Text( @@ -137,16 +141,19 @@ class _AccountLandingPageState extends State { "No URL found for \"forgot password\".\nAdd your forgot password URL here https://woosignal.com/dashboard/apps"); } }), - widget.showBackButton ? Column( - children: [ - Divider(), - LinkButton( - title: trans("Back"), - action: () => Navigator.pop(context), - ), - ], - ) : Padding(padding: EdgeInsets.only(bottom: 20),) - + widget.showBackButton + ? Column( + children: [ + Divider(), + LinkButton( + title: trans("Back"), + action: () => Navigator.pop(context), + ), + ], + ) + : Padding( + padding: EdgeInsets.only(bottom: 20), + ) ].where((element) => element != null).toList(), ), ), @@ -164,8 +171,7 @@ class _AccountLandingPageState extends State { if (email == "" || password == "") { showToastNotification(context, title: trans("Invalid details"), - description: - trans("The email and password field cannot be empty"), + description: trans("The email and password field cannot be empty"), style: ToastNotificationStyleType.DANGER); return; } @@ -190,25 +196,23 @@ class _AccountLandingPageState extends State { } on InvalidNonceException catch (_) { showToastNotification(context, title: trans("Invalid details"), - description: trans("Something went wrong, please contact our store"), + description: + trans("Something went wrong, please contact our store"), style: ToastNotificationStyleType.DANGER); } on InvalidEmailException catch (_) { showToastNotification(context, title: trans("Invalid details"), - description: - trans("That email does not match our records"), + description: trans("That email does not match our records"), style: ToastNotificationStyleType.DANGER); } on InvalidUsernameException catch (_) { showToastNotification(context, title: trans("Invalid details"), - description: - trans("That username does not match our records"), + description: trans("That username does not match our records"), style: ToastNotificationStyleType.DANGER); } on IncorrectPasswordException catch (_) { showToastNotification(context, title: trans("Invalid details"), - description: - trans("That password does not match our records"), + description: trans("That password does not match our records"), style: ToastNotificationStyleType.DANGER); } on Exception catch (_) { showToastNotification(context, diff --git a/LabelStoreMax/lib/resources/pages/account_order_detail.dart b/LabelStoreMax/lib/resources/pages/account_order_detail.dart index 2c3cf6a..0306c9a 100644 --- a/LabelStoreMax/lib/resources/pages/account_order_detail.dart +++ b/LabelStoreMax/lib/resources/pages/account_order_detail.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -43,7 +43,6 @@ class _AccountOrderDetailPageState extends NyState { @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( leading: Container( @@ -53,9 +52,7 @@ class _AccountOrderDetailPageState extends NyState { ), margin: EdgeInsets.only(left: 0), ), - title: Text( - "${trans("Order").capitalize()} #${_orderId.toString()}" - ), + title: Text("${trans("Order").capitalize()} #${_orderId.toString()}"), centerTitle: true, ), resizeToAvoidBottomInset: false, @@ -66,10 +63,13 @@ class _AccountOrderDetailPageState extends NyState { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("${trans("Date Ordered").capitalize()}: " + - dateFormatted( + Text( + "${trans("Date Ordered").capitalize()}: " + + dateFormatted( date: _order.dateCreated, - formatType: formatForDateTime(FormatType.Date))), + formatType: formatForDateTime(FormatType.date), + ), + ), Container( margin: EdgeInsets.only(top: 10, bottom: 10), padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16), @@ -78,8 +78,7 @@ class _AccountOrderDetailPageState extends NyState { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( - child: Text( - "${trans("Ships to").capitalize()}:"), + child: Text("${trans("Ships to").capitalize()}:"), ), Flexible( child: Text( @@ -106,7 +105,9 @@ class _AccountOrderDetailPageState extends NyState { decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, color: (Theme.of(context).brightness == Brightness.light) ? Colors.white : Color(0xFF2C2C2C), diff --git a/LabelStoreMax/lib/resources/pages/account_profile_update.dart b/LabelStoreMax/lib/resources/pages/account_profile_update.dart index b89daf2..3cbf9be 100644 --- a/LabelStoreMax/lib/resources/pages/account_profile_update.dart +++ b/LabelStoreMax/lib/resources/pages/account_profile_update.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -30,7 +30,7 @@ class _AccountProfileUpdatePageState extends State { _AccountProfileUpdatePageState(); bool isLoading = true; - TextEditingController _tfFirstName = TextEditingController(), + final TextEditingController _tfFirstName = TextEditingController(), _tfLastName = TextEditingController(); @override diff --git a/LabelStoreMax/lib/resources/pages/account_register.dart b/LabelStoreMax/lib/resources/pages/account_register.dart index 7215dcb..06f373f 100644 --- a/LabelStoreMax/lib/resources/pages/account_register.dart +++ b/LabelStoreMax/lib/resources/pages/account_register.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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 'dart:math'; import 'package:flutter/material.dart'; @@ -42,12 +41,13 @@ class _AccountRegistrationPageState extends State { _AccountRegistrationPageState(); bool _hasTappedRegister = false; - TextEditingController _tfEmailAddressController = TextEditingController(), + final TextEditingController _tfEmailAddressController = + TextEditingController(), _tfPasswordController = TextEditingController(), _tfFirstNameController = TextEditingController(), _tfLastNameController = TextEditingController(); - WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; + final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; @override void initState() { @@ -56,16 +56,13 @@ class _AccountRegistrationPageState extends State { @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( leading: IconButton( icon: Icon(Icons.close), onPressed: () => Navigator.pop(context), ), - title: Text( - trans("Register") - ), + title: Text(trans("Register")), centerTitle: true, ), resizeToAvoidBottomInset: false, @@ -129,9 +126,10 @@ class _AccountRegistrationPageState extends State { style: TextStyle(fontWeight: FontWeight.bold)), ], style: TextStyle( - color: (Theme.of(context).brightness == Brightness.light) - ? Colors.black45 - : Colors.white70), + color: + (Theme.of(context).brightness == Brightness.light) + ? Colors.black45 + : Colors.white70), ), textAlign: TextAlign.center, ), @@ -177,7 +175,7 @@ class _AccountRegistrationPageState extends State { }); String username = - (email.replaceAll(new RegExp(r'([@.])'), "")) + _randomStr(4); + (email.replaceAll(RegExp(r'([@.])'), "")) + _randomStr(4); WPUserRegisterResponse wpUserRegisterResponse; try { @@ -196,7 +194,8 @@ class _AccountRegistrationPageState extends State { } on InvalidNonceException catch (_) { showToastNotification(context, title: trans("Invalid details"), - description: trans("Something went wrong, please contact our store"), + description: + trans("Something went wrong, please contact our store"), style: ToastNotificationStyleType.DANGER); } on ExistingUserLoginException catch (_) { showToastNotification(context, @@ -257,11 +256,9 @@ class _AccountRegistrationPageState extends State { subtitle: trans("View Terms and Conditions or Privacy policy"), actions: [ dialogAction(context, - title: trans("Terms and Conditions"), - action: _viewTermsConditions), + title: trans("Terms and Conditions"), action: _viewTermsConditions), dialogAction(context, - title: trans("Privacy Policy"), - action: _viewPrivacyPolicy), + title: trans("Privacy Policy"), action: _viewPrivacyPolicy), ], ); } diff --git a/LabelStoreMax/lib/resources/pages/account_shipping_details.dart b/LabelStoreMax/lib/resources/pages/account_shipping_details.dart index 8b09eef..7fc54df 100644 --- a/LabelStoreMax/lib/resources/pages/account_shipping_details.dart +++ b/LabelStoreMax/lib/resources/pages/account_shipping_details.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -33,7 +33,7 @@ class _AccountShippingDetailsPageState _AccountShippingDetailsPageState(); // BILLING TEXT CONTROLLERS - TextEditingController _txtShippingFirstName = TextEditingController(), + final TextEditingController _txtShippingFirstName = TextEditingController(), _txtShippingLastName = TextEditingController(), _txtShippingAddressLine = TextEditingController(), _txtShippingCity = TextEditingController(), @@ -87,19 +87,16 @@ class _AccountShippingDetailsPageState @override Widget build(BuildContext context) { - return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - title: Text( - trans("Shipping Details") - ), + title: Text(trans("Shipping Details")), centerTitle: true, ), body: SafeAreaWidget( child: GestureDetector( onTap: () { - FocusScope.of(context).requestFocus(new FocusNode()); + FocusScope.of(context).requestFocus(FocusNode()); }, child: _isLoading ? AppLoaderWidget() @@ -177,8 +174,10 @@ class _AccountShippingDetailsPageState decoration: BoxDecoration( color: ThemeColor.get(context).surfaceBackground, borderRadius: BorderRadius.circular(10), - boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + boxShadow: (Theme.of(context).brightness == + Brightness.light) + ? wsBoxShadow() + : null, ), padding: EdgeInsets.all(8), ), diff --git a/LabelStoreMax/lib/resources/pages/browse_category.dart b/LabelStoreMax/lib/resources/pages/browse_category.dart index 9afb936..833db4f 100644 --- a/LabelStoreMax/lib/resources/pages/browse_category.dart +++ b/LabelStoreMax/lib/resources/pages/browse_category.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -9,6 +9,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:flutter_app/app/controllers/product_category_search_loader_controller.dart'; import 'package:flutter_app/app/controllers/browse_category_controller.dart'; import 'package:flutter_app/bootstrap/enums/sort_enums.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; @@ -21,7 +22,7 @@ import 'package:nylo_support/widgets/ny_state.dart'; import 'package:nylo_support/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; +import 'package:woosignal/models/response/products.dart' as ws_product; class BrowseCategoryPage extends NyStatefulWidget { final BrowseCategoryController controller = BrowseCategoryController(); @@ -35,51 +36,20 @@ class _BrowseCategoryPageState extends NyState { ProductCategory productCategory; _BrowseCategoryPageState(); - List _products = []; - RefreshController _refreshController = + final RefreshController _refreshController = RefreshController(initialRefresh: false); + final ProductCategorySearchLoaderController + _productCategorySearchLoaderController = + ProductCategorySearchLoaderController(); - int _page = 1; - bool _shouldStopRequests = false, - waitForNextRequest = false, - _isLoading = true; + bool _shouldStopRequests = false; + bool _isLoading = true; @override widgetDidLoad() async { super.widgetDidLoad(); - this.productCategory = widget.controller.data(); - await _fetchMoreProducts(); - } - - _fetchMoreProducts() async { - if (waitForNextRequest || _shouldStopRequests) { - return; - } - waitForNextRequest = true; - List products = await appWooSignal( - (api) => api.getProducts( - perPage: 50, - category: productCategory.id.toString(), - page: _page, - status: "publish", - stockStatus: "instock"), - ); - - if (products.length == 0) { - _shouldStopRequests = true; - _isLoading = false; - setState(() {}); - return; - } else { - _products.addAll(products); - } - - waitForNextRequest = false; - _page = _page + 1; - - setState(() { - _isLoading = false; - }); + productCategory = widget.controller.data(); + await fetchProducts(); } @override @@ -95,8 +65,7 @@ class _BrowseCategoryPageState extends NyState { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(trans("Browse"), - style: Theme.of(context).textTheme.subtitle1), + Text(trans("Browse"), style: Theme.of(context).textTheme.subtitle1), Text(parseHtmlString(productCategory.name)) ], ), @@ -117,23 +86,22 @@ class _BrowseCategoryPageState extends NyState { refreshController: _refreshController, onRefresh: _onRefresh, onLoading: _onLoading, - products: _products, + products: _productCategorySearchLoaderController.getResults(), onTap: _showProduct), ), ); } void _onRefresh() async { - _products = []; - _page = 1; + _productCategorySearchLoaderController.clear(); _shouldStopRequests = false; - waitForNextRequest = false; - await _fetchMoreProducts(); + + await fetchProducts(); _refreshController.refreshCompleted(); } void _onLoading() async { - await _fetchMoreProducts(); + await fetchProducts(); if (mounted) { setState(() {}); @@ -146,26 +114,28 @@ class _BrowseCategoryPageState extends NyState { } _sortProducts({@required SortByType by}) { + List products = + _productCategorySearchLoaderController.getResults(); switch (by) { - case SortByType.LowToHigh: - _products.sort( + case SortByType.lowToHigh: + products.sort( (product1, product2) => (parseWcPrice(product1.price)) .compareTo((parseWcPrice(product2.price))), ); break; - case SortByType.HighToLow: - _products.sort( + case SortByType.highToLow: + products.sort( (product1, product2) => (parseWcPrice(product2.price)) .compareTo((parseWcPrice(product1.price))), ); break; - case SortByType.NameAZ: - _products.sort( + case SortByType.nameAZ: + products.sort( (product1, product2) => product1.name.compareTo(product2.name), ); break; - case SortByType.NameZA: - _products.sort( + case SortByType.nameZA: + products.sort( (product1, product2) => product2.name.compareTo(product1.name), ); break; @@ -183,28 +153,28 @@ class _BrowseCategoryPageState extends NyState { children: [ LinkButton( title: trans("Sort: Low to high"), - action: () => _sortProducts(by: SortByType.LowToHigh), + action: () => _sortProducts(by: SortByType.lowToHigh), ), Divider( height: 0, ), LinkButton( title: trans("Sort: High to low"), - action: () => _sortProducts(by: SortByType.HighToLow), + action: () => _sortProducts(by: SortByType.highToLow), ), Divider( height: 0, ), LinkButton( title: trans("Sort: Name A-Z"), - action: () => _sortProducts(by: SortByType.NameAZ), + action: () => _sortProducts(by: SortByType.nameAZ), ), Divider( height: 0, ), LinkButton( title: trans("Sort: Name Z-A"), - action: () => _sortProducts(by: SortByType.NameZA), + action: () => _sortProducts(by: SortByType.nameZA), ), Divider( height: 0, @@ -215,11 +185,28 @@ class _BrowseCategoryPageState extends NyState { ); } - _dismissModal() { - Navigator.pop(context); + Future fetchProducts() async { + await _productCategorySearchLoaderController.loadProducts( + hasResults: (result) { + if (result == false) { + setState(() { + _isLoading = false; + _shouldStopRequests = true; + }); + return false; + } + return true; + }, + didFinish: () => setState(() { + _isLoading = false; + }), + productCategory: productCategory, + ); } - _showProduct(WS.Product product) { + _dismissModal() => Navigator.pop(context); + + _showProduct(ws_product.Product product) { Navigator.pushNamed(context, "/product-detail", arguments: product); } } diff --git a/LabelStoreMax/lib/resources/pages/browse_search.dart b/LabelStoreMax/lib/resources/pages/browse_search.dart index e77fcc4..7acc171 100644 --- a/LabelStoreMax/lib/resources/pages/browse_search.dart +++ b/LabelStoreMax/lib/resources/pages/browse_search.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/app/controllers/browse_search_controller.dart'; +import 'package:flutter_app/app/controllers/product_search_loader_controller.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; import 'package:flutter_app/resources/widgets/safearea_widget.dart'; @@ -17,7 +18,7 @@ import 'package:nylo_support/helpers/helper.dart'; import 'package:nylo_support/widgets/ny_state.dart'; import 'package:nylo_support/widgets/ny_stateful_widget.dart'; import 'package: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_product; class BrowseSearchPage extends NyStatefulWidget { final BrowseSearchController controller = BrowseSearchController(); @@ -28,54 +29,19 @@ class BrowseSearchPage extends NyStatefulWidget { } class _BrowseSearchState extends NyState { - RefreshController _refreshController = + final RefreshController _refreshController = RefreshController(initialRefresh: false); + final ProductSearchLoaderController _productSearchLoaderController = + ProductSearchLoaderController(); - List _products = []; String _search; - int _page = 1; - bool _shouldStopRequests = false, - waitForNextRequest = false, - _isLoading = true; + bool _shouldStopRequests = false, _isLoading = true; @override widgetDidLoad() async { super.widgetDidLoad(); _search = widget.controller.data(); - await _fetchProductsForSearch(); - } - - _fetchProductsForSearch() async { - if (waitForNextRequest || _shouldStopRequests) { - return; - } - waitForNextRequest = true; - - List products = await appWooSignal( - (api) => api.getProducts( - perPage: 100, - search: _search, - page: _page, - status: "publish", - stockStatus: "instock", - ), - ); - - if (products.length == 0) { - _shouldStopRequests = true; - setState(() { - _isLoading = false; - }); - return; - } else { - _products.addAll(products); - } - waitForNextRequest = false; - _page = _page + 1; - - setState(() { - _isLoading = false; - }); + await fetchProducts(); } @override @@ -103,27 +69,28 @@ class _BrowseSearchState extends NyState { ? Center( child: AppLoaderWidget(), ) - : refreshableScroll(context, + : refreshableScroll( + context, refreshController: _refreshController, onRefresh: _onRefresh, onLoading: _onLoading, - products: _products, - onTap: _showProduct), + products: _productSearchLoaderController.getResults(), + onTap: _showProduct, + ), ), ); } void _onRefresh() async { - _products = []; - _page = 1; + _productSearchLoaderController.clear(); _shouldStopRequests = false; - waitForNextRequest = false; - await _fetchProductsForSearch(); + + await fetchProducts(); _refreshController.refreshCompleted(); } void _onLoading() async { - await _fetchProductsForSearch(); + await fetchProducts(); if (mounted) { setState(() {}); @@ -135,7 +102,26 @@ class _BrowseSearchState extends NyState { } } - _showProduct(WS.Product product) { + Future fetchProducts() async { + await _productSearchLoaderController.loadProducts( + hasResults: (result) { + if (result == false) { + setState(() { + _isLoading = false; + _shouldStopRequests = true; + }); + return false; + } + return true; + }, + didFinish: () => setState(() { + _isLoading = false; + }), + search: _search, + ); + } + + _showProduct(ws_product.Product product) { Navigator.pushNamed(context, "/product-detail", arguments: product); } } diff --git a/LabelStoreMax/lib/resources/pages/cart.dart b/LabelStoreMax/lib/resources/pages/cart.dart index e2edd07..aed5b81 100644 --- a/LabelStoreMax/lib/resources/pages/cart.dart +++ b/LabelStoreMax/lib/resources/pages/cart.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -40,11 +40,12 @@ class _CartPageState extends State { void initState() { super.initState(); _cartCheck(); + CheckoutSession.getInstance.coupon = null; } _cartCheck() async { List cart = await Cart.getInstance.getCart(); - if (cart.length == 0) { + if (cart.isEmpty) { setState(() { _isLoading = false; _isCartEmpty = true; @@ -56,7 +57,7 @@ class _CartPageState extends State { List cartRes = await appWooSignal((api) => api.cartCheck(cartJSON)); - if (cartRes.length == 0) { + if (cartRes.isEmpty) { Cart.getInstance.saveCartToPref(cartLineItems: []); setState(() { _isCartEmpty = true; @@ -65,7 +66,7 @@ class _CartPageState extends State { return; } _cartLines = cartRes.map((json) => CartLineItem.fromJson(json)).toList(); - if (_cartLines.length > 0) { + if (_cartLines.isNotEmpty) { Cart.getInstance.saveCartToPref(cartLineItems: _cartLines); } setState(() { @@ -80,7 +81,7 @@ class _CartPageState extends State { return; } - if (cartLineItems.length == 0) { + if (cartLineItems.isEmpty) { showToastNotification( context, title: trans("Cart"), @@ -162,7 +163,7 @@ class _CartPageState extends State { style: ToastNotificationStyleType.WARNING, icon: Icons.remove_shopping_cart, ); - if (_cartLines.length == 0) { + if (_cartLines.isEmpty) { _isCartEmpty = true; } setState(() {}); @@ -272,16 +273,17 @@ class _CartPageState extends State { case ConnectionState.waiting: return Text(""); default: - if (snapshot.hasError) + if (snapshot.hasError) { return Text(""); - else - return new Padding( + } else { + return Padding( child: TextRowWidget( title: trans("Total"), text: (_isLoading ? "" : snapshot.data), ), padding: EdgeInsets.only(bottom: 15, top: 15), ); + } } }, ), diff --git a/LabelStoreMax/lib/resources/pages/checkout_confirmation.dart b/LabelStoreMax/lib/resources/pages/checkout_confirmation.dart index fbaaf11..c35d046 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_confirmation.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_confirmation.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -11,12 +11,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/app/models/cart.dart'; import 'package:flutter_app/app/models/checkout_session.dart'; -import 'package:flutter_app/app/models/customer_address.dart'; import 'package:flutter_app/app/models/customer_country.dart'; +import 'package:flutter_app/app/models/payment_type.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/buttons.dart'; +import 'package:flutter_app/resources/widgets/checkout_coupon_amount_widget.dart'; +import 'package:flutter_app/resources/widgets/checkout_payment_type_widget.dart'; +import 'package:flutter_app/resources/widgets/checkout_select_coupon_widget.dart'; +import 'package:flutter_app/resources/widgets/checkout_shipping_type_widget.dart'; +import 'package:flutter_app/resources/widgets/checkout_store_heading_widget.dart'; +import 'package:flutter_app/resources/widgets/checkout_user_details_widget.dart'; import 'package:flutter_app/resources/widgets/safearea_widget.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; @@ -36,17 +42,18 @@ class CheckoutConfirmationPageState extends State { bool _showFullLoader = true, _isProcessingPayment = false; - List _taxRates = []; + final List _taxRates = []; TaxRate _taxRate; final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; @override void initState() { super.initState(); - + CheckoutSession.getInstance.coupon = null; + List paymentTypes = getPaymentTypes(); if (CheckoutSession.getInstance.paymentType == null && - getPaymentTypes().length > 0) { - CheckoutSession.getInstance.paymentType = getPaymentTypes().first; + paymentTypes.isNotEmpty) { + CheckoutSession.getInstance.paymentType = paymentTypes.first; } _getTaxes(); } @@ -64,7 +71,7 @@ class CheckoutConfirmationPageState extends State { List tmpTaxRates = await appWooSignal( (api) => api.getTaxRates(page: pageIndex, perPage: 100)); - if (tmpTaxRates != null && tmpTaxRates.length > 0) { + if (tmpTaxRates != null && tmpTaxRates.isNotEmpty) { _taxRates.addAll(tmpTaxRates); } if (tmpTaxRates.length >= 100) { @@ -74,7 +81,7 @@ class CheckoutConfirmationPageState extends State { } } - if (_taxRates == null || _taxRates.length == 0) { + if (_taxRates == null || _taxRates.isEmpty) { setState(() { _showFullLoader = false; }); @@ -131,12 +138,10 @@ class CheckoutConfirmationPageState extends State { orElse: () => null, ); - if (taxRate == null) { - taxRate = _taxRates.firstWhere( - (t) => t.country == shippingCountry.countryCode, - orElse: () => null, - ); - } + taxRate ??= _taxRates.firstWhere( + (t) => t.country == shippingCountry.countryCode, + orElse: () => null, + ); } if (taxRate != null) { @@ -147,225 +152,154 @@ class CheckoutConfirmationPageState extends State { }); } - _actionCheckoutDetails() { - Navigator.pushNamed(context, "/checkout-details").then((e) { - setState(() { - _showFullLoader = true; - }); - _getTaxes(); - }); - } - - _actionPayWith() { - Navigator.pushNamed(context, "/checkout-payment-type") - .then((value) => setState(() {})); - } - - _actionSelectShipping() { - CustomerAddress shippingAddress = - CheckoutSession.getInstance.billingDetails.shippingAddress; - if (shippingAddress == null || shippingAddress.customerCountry == null) { - showToastNotification(context, - title: trans("Oops"), - description: trans("Add your shipping details first"), - icon: Icons.local_shipping); - return; - } - Navigator.pushNamed(context, "/checkout-shipping-type").then((value) { - setState(() {}); - }); - } - @override Widget build(BuildContext context) { + CheckoutSession checkoutSession = CheckoutSession.getInstance; + + if (_showFullLoader == true) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + AppLoaderWidget(), + Padding( + padding: const EdgeInsets.only(top: 15), + child: Text( + "${trans("One moment")}...", + style: Theme.of(context).textTheme.subtitle1, + ), + ) + ], + ), + ); + } + return Scaffold( appBar: AppBar( - title: Text( - trans("Checkout") - ), + title: Text(trans("Checkout")), centerTitle: true, + leading: Container( + child: IconButton( + icon: Icon(Icons.arrow_back_ios), + onPressed: () { + CheckoutSession.getInstance.coupon = null; + Navigator.pop(context); + }, + ), + margin: EdgeInsets.only(left: 0), + ), ), resizeToAvoidBottomInset: false, body: SafeAreaWidget( - child: !_showFullLoader - ? Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Container( - padding: EdgeInsets.only(left: 10, right: 10), - decoration: BoxDecoration( - color: ThemeColor.get(context).backgroundContainer, - borderRadius: BorderRadius.circular(10), - boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, - ), - margin: EdgeInsets.only(top: 5, bottom: 5), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Container( - decoration: BoxDecoration( - boxShadow: (Theme.of(context).brightness == Brightness.light) - ? wsBoxShadow(blurRadius: 10) - : null, - color: Colors.transparent, - ), - padding: EdgeInsets.all(2), - margin: EdgeInsets.only(top: 16), - child: ClipRRect( - child: StoreLogo(height: 65), - borderRadius: BorderRadius.circular(8), - )), - ((CheckoutSession.getInstance.billingDetails != null && - CheckoutSession.getInstance.billingDetails - .billingAddress != - null) - ? wsCheckoutRow(context, - heading: trans("Billing/shipping details"), - leadImage: Icon(Icons.home), - leadTitle: - (CheckoutSession.getInstance.billingDetails == null || - CheckoutSession.getInstance - .billingDetails.billingAddress - .hasMissingFields() - ? trans("Billing address is incomplete") - : CheckoutSession.getInstance - .billingDetails.billingAddress - .addressFull()), - action: _actionCheckoutDetails, - showBorderBottom: true) - : wsCheckoutRow(context, - heading: - trans("Billing/shipping details"), - leadImage: Icon(Icons.home), - leadTitle: trans("Add billing & shipping details"), - action: _actionCheckoutDetails, - showBorderBottom: true)), - (CheckoutSession.getInstance.paymentType != null - ? wsCheckoutRow(context, - heading: trans("Payment method"), - leadImage: Container( - color: Colors.white, - child: Image.asset( - getImageAsset(CheckoutSession - .getInstance.paymentType.assetImage), - width: 70, - ), - ), - leadTitle: CheckoutSession - .getInstance.paymentType.desc, - action: _actionPayWith, - showBorderBottom: true) - : wsCheckoutRow(context, - heading: trans("Pay with"), - leadImage: Icon(Icons.payment), - leadTitle: trans("Select a payment method"), - action: _actionPayWith, - showBorderBottom: true)), - _wooSignalApp.disableShipping == 1 - ? null - : (CheckoutSession.getInstance.shippingType != - null - ? wsCheckoutRow(context, - heading: - trans("Shipping selected"), - leadImage: Icon(Icons.local_shipping), - leadTitle: CheckoutSession - .getInstance.shippingType - .getTitle(), - action: _actionSelectShipping) - : wsCheckoutRow( - context, - heading: - trans("Select shipping"), - leadImage: Icon(Icons.local_shipping), - leadTitle: trans("Select a shipping option"), - action: _actionSelectShipping, - )), - ].where((e) => e != null).toList()), - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Divider( - color: Colors.black12, - thickness: 1, - ), - wsCheckoutSubtotalWidgetFB( - title: trans("Subtotal"), - ), - _wooSignalApp.disableShipping == 1 - ? null - : widgetCheckoutMeta(context, - title: trans("Shipping fee"), - amount: - CheckoutSession.getInstance.shippingType == - null - ? trans("Select shipping") - : CheckoutSession.getInstance.shippingType - .getTotal(withFormatting: true)), - (_taxRate != null - ? wsCheckoutTaxAmountWidgetFB(taxRate: _taxRate) - : null), - wsCheckoutTotalWidgetFB( - title: trans("Total"), taxRate: _taxRate), - Divider( - color: Colors.black12, - thickness: 1, - ), - ].where((e) => e != null).toList(), - ), - PrimaryButton( - title: _isProcessingPayment - ? "${trans("PROCESSING")}..." - : trans("CHECKOUT"), - action: _isProcessingPayment ? null : _handleCheckout, - ), - ], - ) - : Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AppLoaderWidget(), - Padding( - padding: const EdgeInsets.only(top: 15), - child: Text( - "${trans("One moment")}...", - style: Theme.of(context).textTheme.subtitle1, - ), - ) - ], + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10, right: 10), + decoration: BoxDecoration( + color: ThemeColor.get(context).backgroundContainer, + borderRadius: BorderRadius.circular(10), + boxShadow: (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, ), + margin: EdgeInsets.only(top: 5, bottom: 5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + CheckoutStoreHeadingWidget(), + CheckoutUserDetailsWidget( + context: context, + checkoutSession: checkoutSession, + resetState: () { + setState(() { + _showFullLoader = true; + }); + _getTaxes(); + }, + ), + CheckoutPaymentTypeWidget( + context: context, + checkoutSession: checkoutSession, + resetState: () => setState(() {}), + ), + CheckoutShippingTypeWidget( + context: context, + checkoutSession: checkoutSession, + resetState: () => setState(() {}), + wooSignalApp: _wooSignalApp, + ), + ].where((e) => e != null).toList()), ), + ), + if (_wooSignalApp.couponEnabled == true) + CheckoutSelectCouponWidget( + context: context, + checkoutSession: checkoutSession, + resetState: () => setState(() {}), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Divider( + color: Colors.black12, + thickness: 1, + ), + CheckoutSubtotal( + title: trans("Subtotal"), + ), + CheckoutCouponAmountWidget(checkoutSession: checkoutSession), + _wooSignalApp.disableShipping == 1 + ? null + : CheckoutMetaLine( + title: trans("Shipping fee"), + amount: CheckoutSession.getInstance.shippingType == null + ? trans("Select shipping") + : CheckoutSession.getInstance.shippingType + .getTotal(withFormatting: true)), + (_taxRate != null ? CheckoutTaxTotal(taxRate: _taxRate) : null), + CheckoutTotal(title: trans("Total"), taxRate: _taxRate), + Divider( + color: Colors.black12, + thickness: 1, + ), + ].where((e) => e != null).toList(), + ), + PrimaryButton( + title: _isProcessingPayment + ? "${trans("PROCESSING")}..." + : trans("CHECKOUT"), + action: _isProcessingPayment ? null : _handleCheckout, + ), + ], + ), ), ); } _handleCheckout() async { - if (CheckoutSession.getInstance.billingDetails.billingAddress == null) { + CheckoutSession checkoutSession = CheckoutSession.getInstance; + if (checkoutSession.billingDetails.billingAddress == null) { showToastNotification( context, title: trans("Oops"), - description: trans("Please select add your billing/shipping address to proceed"), + description: + trans("Please select add your billing/shipping address to proceed"), style: ToastNotificationStyleType.WARNING, icon: Icons.local_shipping, ); return; } - if (CheckoutSession.getInstance.billingDetails.billingAddress - .hasMissingFields()) { + if (checkoutSession.billingDetails.billingAddress.hasMissingFields()) { showToastNotification( context, title: trans("Oops"), - description: - trans("Your billing/shipping details are incomplete"), + description: trans("Your billing/shipping details are incomplete"), style: ToastNotificationStyleType.WARNING, icon: Icons.local_shipping, ); @@ -373,24 +307,22 @@ class CheckoutConfirmationPageState extends State { } if (_wooSignalApp.disableShipping == 0 && - CheckoutSession.getInstance.shippingType == null) { + checkoutSession.shippingType == null) { showToastNotification( context, title: trans("Oops"), - description: - trans("Please select a shipping method to proceed"), + description: trans("Please select a shipping method to proceed"), style: ToastNotificationStyleType.WARNING, icon: Icons.local_shipping, ); return; } - if (CheckoutSession.getInstance.paymentType == null) { + if (checkoutSession.paymentType == null) { showToastNotification( context, title: trans("Oops"), - description: - trans("Please select a payment method to proceed"), + description: trans("Please select a payment method to proceed"), style: ToastNotificationStyleType.WARNING, icon: Icons.payment, ); @@ -398,20 +330,20 @@ class CheckoutConfirmationPageState extends State { } if (_wooSignalApp.disableShipping == 0 && - CheckoutSession.getInstance.shippingType?.minimumValue != null) { + checkoutSession.shippingType?.minimumValue != null) { String total = await Cart.getInstance.getTotal(); if (total == null) { return; } double doubleTotal = double.parse(total); double doubleMinimumValue = - double.parse(CheckoutSession.getInstance.shippingType?.minimumValue); + double.parse(checkoutSession.shippingType?.minimumValue); if (doubleTotal < doubleMinimumValue) { showToastNotification(context, title: trans("Sorry"), description: - "${trans("Spend a minimum of")} ${formatDoubleCurrency(total: doubleMinimumValue)} ${trans("for")} ${CheckoutSession.getInstance.shippingType.getTitle()}", + "${trans("Spend a minimum of")} ${formatDoubleCurrency(total: doubleMinimumValue)} ${trans("for")} ${checkoutSession.shippingType.getTitle()}", style: ToastNotificationStyleType.INFO, duration: Duration(seconds: 3)); return; @@ -423,7 +355,7 @@ class CheckoutConfirmationPageState extends State { if (!appStatus) { showToastNotification(context, title: trans("Sorry"), - description: "${trans("Retry later")}", + description: trans("Retry later"), style: ToastNotificationStyleType.INFO, duration: Duration(seconds: 3)); return; @@ -437,13 +369,11 @@ class CheckoutConfirmationPageState extends State { _isProcessingPayment = true; }); - await CheckoutSession.getInstance.paymentType + await checkoutSession.paymentType .pay(context, state: this, taxRate: _taxRate); - Future.delayed(Duration(milliseconds: 5000), () { - setState(() { - _isProcessingPayment = false; - }); + setState(() { + _isProcessingPayment = false; }); } } diff --git a/LabelStoreMax/lib/resources/pages/checkout_details.dart b/LabelStoreMax/lib/resources/pages/checkout_details.dart index 7524053..576f98f 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_details.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_details.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_app/app/models/billing_details.dart'; import 'package:flutter_app/app/models/checkout_session.dart'; @@ -37,7 +36,7 @@ class _CheckoutDetailsPageState extends State { int activeTabIndex = 0; // TEXT CONTROLLERS - TextEditingController + final TextEditingController // billing _txtBillingFirstName = TextEditingController(), _txtBillingLastName = TextEditingController(), @@ -168,7 +167,7 @@ class _CheckoutDetailsPageState extends State { ), body: SafeAreaWidget( child: GestureDetector( - onTap: () => FocusScope.of(context).requestFocus(new FocusNode()), + onTap: () => FocusScope.of(context).requestFocus(FocusNode()), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -194,8 +193,7 @@ class _CheckoutDetailsPageState extends State { MainAxisAlignment.spaceAround, children: [ SwitchAddressTab( - title: - trans("Billing Details"), + title: trans("Billing Details"), currentTabIndex: activeTabIndex, type: "billing", onTapAction: () => setState(() { @@ -227,7 +225,9 @@ class _CheckoutDetailsPageState extends State { color: ThemeColor.get(context).backgroundContainer, borderRadius: BorderRadius.circular(10), boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, ), padding: EdgeInsets.only(left: 8, right: 8, top: 8), child: (activeTab ?? tabBillingDetails()), @@ -315,7 +315,8 @@ class _CheckoutDetailsPageState extends State { showToastNotification( context, title: trans("Oops"), - description: trans("Invalid shipping address, please check your shipping details"), + description: trans( + "Invalid shipping address, please check your shipping details"), style: ToastNotificationStyleType.WARNING, ); return; @@ -324,7 +325,7 @@ class _CheckoutDetailsPageState extends State { // Email validation String billingEmail = _txtBillingEmailAddress.text; String shippingEmail = _txtShippingEmailAddress.text; - if (billingEmail.length > 0 && !validate.isEmail(billingEmail)) { + if (billingEmail.isNotEmpty && !validate.isEmail(billingEmail)) { showToastNotification( context, title: trans("Oops"), @@ -334,7 +335,7 @@ class _CheckoutDetailsPageState extends State { return; } - if (shippingEmail.length > 0 && !validate.isEmail(shippingEmail)) { + if (shippingEmail.isNotEmpty && !validate.isEmail(shippingEmail)) { showToastNotification( context, title: trans("Oops"), @@ -380,7 +381,7 @@ class _CheckoutDetailsPageState extends State { city: "", postalCode: "", emailAddress: "", - customerCountry: new CustomerCountry()); + customerCountry: CustomerCountry()); } setState(() {}); } @@ -393,7 +394,7 @@ class _CheckoutDetailsPageState extends State { @required String postalCode, @required String emailAddress, @required CustomerCountry customerCountry}) { - CustomerAddress customerShippingAddress = new CustomerAddress(); + CustomerAddress customerShippingAddress = CustomerAddress(); customerShippingAddress.firstName = firstName; customerShippingAddress.lastName = lastName; customerShippingAddress.addressLine = addressLine; diff --git a/LabelStoreMax/lib/resources/pages/checkout_payment_type.dart b/LabelStoreMax/lib/resources/pages/checkout_payment_type.dart index 646a5f4..38689c2 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_payment_type.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_payment_type.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_app/app/models/checkout_session.dart'; import 'package:flutter_app/app/models/payment_type.dart'; @@ -35,7 +34,7 @@ class _CheckoutPaymentTypePageState extends State { super.initState(); if (CheckoutSession.getInstance.paymentType == null) { - if (getPaymentTypes() != null && getPaymentTypes().length > 0) { + if (getPaymentTypes() != null && getPaymentTypes().isNotEmpty) { CheckoutSession.getInstance.paymentType = getPaymentTypes().first; } } @@ -44,21 +43,21 @@ class _CheckoutPaymentTypePageState extends State { @override Widget build(BuildContext context) { List paymentTypes = getPaymentTypes(); - if (paymentTypes.length == 0 && getEnv('APP_DEBUG', defaultValue: false) == true) { - NyLogger.info('You have no payment methods set. Visit the WooSignal dashboard (https://woosignal.com/dashboard) to set a payment method.'); + if (paymentTypes.isEmpty && + getEnv('APP_DEBUG', defaultValue: false) == true) { + NyLogger.info( + 'You have no payment methods set. Visit the WooSignal dashboard (https://woosignal.com/dashboard) to set a payment method.'); } return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - title: Text( - trans("Payment Method") - ), + title: Text(trans("Payment Method")), automaticallyImplyLeading: false, centerTitle: true, ), body: SafeAreaWidget( child: GestureDetector( - onTap: () => FocusScope.of(context).requestFocus(new FocusNode()), + onTap: () => FocusScope.of(context).requestFocus(FocusNode()), child: LayoutBuilder( builder: (context, constraints) => Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -78,53 +77,60 @@ class _CheckoutPaymentTypePageState extends State { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Expanded( - child: paymentTypes.length == 0 ? Container( - padding: EdgeInsets.only(top: 20), - child: Text(trans("No payment methods are available"), style: Theme.of(context).textTheme.bodyText1,), - ) : ListView.separated( - itemCount: paymentTypes.length, - itemBuilder: (BuildContext context, int index) { - PaymentType paymentType = - paymentTypes[index]; - return ListTile( - contentPadding: EdgeInsets.only( - top: 10, - bottom: 10, - left: 8, - right: 8, - ), - leading: Container( - decoration: BoxDecoration( - color: Colors.white - ), - padding: EdgeInsets.all(4), - child: Image.asset( - getImageAsset(paymentType.assetImage), - width: 60, - fit: BoxFit.contain, - alignment: Alignment.center, - ), - ), - title: Text(paymentType.desc, + child: paymentTypes.isEmpty + ? Container( + padding: EdgeInsets.only(top: 20), + child: Text( + trans("No payment methods are available"), style: - Theme.of(context).textTheme.subtitle1), - selected: true, - trailing: - (CheckoutSession.getInstance.paymentType == - paymentType - ? Icon(Icons.check) - : null), - onTap: () { - CheckoutSession.getInstance.paymentType = - paymentType; - Navigator.pop(context); - }, - ); - }, - separatorBuilder: (cxt, i) => Divider( - color: Colors.black12, - ), - ), + Theme.of(context).textTheme.bodyText1, + ), + ) + : ListView.separated( + itemCount: paymentTypes.length, + itemBuilder: + (BuildContext context, int index) { + PaymentType paymentType = + paymentTypes[index]; + return ListTile( + contentPadding: EdgeInsets.only( + top: 10, + bottom: 10, + left: 8, + right: 8, + ), + leading: Container( + decoration: + BoxDecoration(color: Colors.white), + padding: EdgeInsets.all(4), + child: Image.asset( + getImageAsset(paymentType.assetImage), + width: 60, + fit: BoxFit.contain, + alignment: Alignment.center, + ), + ), + title: Text(paymentType.desc, + style: Theme.of(context) + .textTheme + .subtitle1), + selected: true, + trailing: (CheckoutSession + .getInstance.paymentType == + paymentType + ? Icon(Icons.check) + : null), + onTap: () { + CheckoutSession.getInstance + .paymentType = paymentType; + Navigator.pop(context); + }, + ); + }, + separatorBuilder: (cxt, i) => Divider( + color: Colors.black12, + ), + ), ), LinkButton( title: trans("CANCEL"), @@ -136,7 +142,9 @@ class _CheckoutPaymentTypePageState extends State { color: ThemeColor.get(context).backgroundContainer, borderRadius: BorderRadius.circular(10), boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, ), padding: EdgeInsets.all(8), ), diff --git a/LabelStoreMax/lib/resources/pages/checkout_shipping_type.dart b/LabelStoreMax/lib/resources/pages/checkout_shipping_type.dart index a126f05..ec148b5 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_shipping_type.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_shipping_type.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_app/app/models/cart.dart'; import 'package:flutter_app/app/models/cart_line_item.dart'; @@ -36,7 +35,7 @@ class _CheckoutShippingTypePageState extends State { _CheckoutShippingTypePageState(); bool _isShippingSupported = true, _isLoading = true; - List> _wsShippingOptions = []; + final List> _wsShippingOptions = []; WSShipping _shipping; @override @@ -105,7 +104,7 @@ class _CheckoutShippingTypePageState extends State { .firstWhere((element) => element.parentId == 0, orElse: () => null); await _handleShippingZones(noZones); } - if (_wsShippingOptions.length == 0) { + if (_wsShippingOptions.isEmpty) { _isShippingSupported = false; } @@ -237,15 +236,13 @@ class _CheckoutShippingTypePageState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - title: Text( - trans("Shipping Methods") - ), + title: Text(trans("Shipping Methods")), automaticallyImplyLeading: false, centerTitle: true, ), body: SafeAreaWidget( child: GestureDetector( - onTap: () => FocusScope.of(context).requestFocus(new FocusNode()), + onTap: () => FocusScope.of(context).requestFocus(FocusNode()), child: LayoutBuilder( builder: (context, constraints) => Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -253,9 +250,12 @@ class _CheckoutShippingTypePageState extends State { children: [ Padding( child: Center( - child: Image.asset(getImageAsset('shipping_icon.png'), + child: Image.asset( + getImageAsset('shipping_icon.png'), height: 100, - color: (Theme.of(context).brightness == Brightness.light) ? null : Colors.white, + color: (Theme.of(context).brightness == Brightness.light) + ? null + : Colors.white, fit: BoxFit.fitHeight, ), ), @@ -325,8 +325,8 @@ class _CheckoutShippingTypePageState extends State { "object"] is FreeShipping ? TextSpan( - text: - trans("Free postage"), + text: trans( + "Free postage"), ) : TextSpan( text: @@ -376,7 +376,8 @@ class _CheckoutShippingTypePageState extends State { ), ) : Text( - trans("Shipping is not supported for your country, sorry"), + trans( + "Shipping is not supported for your country, sorry"), style: Theme.of(context).textTheme.headline6, textAlign: TextAlign.center, @@ -391,7 +392,9 @@ class _CheckoutShippingTypePageState extends State { color: ThemeColor.get(context).backgroundContainer, borderRadius: BorderRadius.circular(10), boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, ), padding: EdgeInsets.all(8), ), diff --git a/LabelStoreMax/lib/resources/pages/checkout_status.dart b/LabelStoreMax/lib/resources/pages/checkout_status.dart index 8ee30d1..fdd51bd 100644 --- a/LabelStoreMax/lib/resources/pages/checkout_status.dart +++ b/LabelStoreMax/lib/resources/pages/checkout_status.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_app/app/controllers/checkout_status_controller.dart'; import 'package:flutter_app/app/models/cart.dart'; @@ -17,7 +16,7 @@ import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/resources/widgets/buttons.dart'; import 'package:nylo_support/widgets/ny_state.dart'; import 'package:nylo_support/widgets/ny_stateful_widget.dart'; -import 'package:woosignal/models/response/order.dart' as WS; +import 'package:woosignal/models/response/order.dart' as ws_order; import 'package:nylo_support/helpers/helper.dart'; import '../widgets/woosignal_ui.dart'; @@ -31,7 +30,7 @@ class CheckoutStatusPage extends NyStatefulWidget { } class _CheckoutStatusState extends NyState { - WS.Order _order; + ws_order.Order _order; @override widgetDidLoad() async { @@ -43,7 +42,6 @@ class _CheckoutStatusState extends NyState { @override Widget build(BuildContext context) { - return Scaffold( appBar: AppBar( elevation: 0.0, @@ -94,7 +92,10 @@ class _CheckoutStatusState extends NyState { border: Border( bottom: BorderSide(color: Colors.black12, width: 1.0), ), - color: (Theme.of(context).brightness == Brightness.light) ? Colors.white : null), + color: + (Theme.of(context).brightness == Brightness.light) + ? Colors.white + : null), padding: EdgeInsets.only(bottom: 20), ), Container( @@ -121,11 +122,11 @@ class _CheckoutStatusState extends NyState { alignment: Alignment.center, ), Expanded( - child: new ListView.builder( + child: ListView.builder( itemCount: _order.lineItems == null ? 0 : _order.lineItems.length, itemBuilder: (BuildContext context, int index) { - WS.LineItems lineItem = _order.lineItems[index]; + ws_order.LineItems lineItem = _order.lineItems[index]; return Container( child: Row( crossAxisAlignment: CrossAxisAlignment.center, @@ -164,13 +165,16 @@ class _CheckoutStatusState extends NyState { padding: EdgeInsets.all(16), margin: EdgeInsets.all(8), color: - (Theme.of(context).brightness == Brightness.light) ? Colors.white : null); + (Theme.of(context).brightness == Brightness.light) + ? Colors.white + : null); }), ), Align( child: LinkButton( title: trans("Back to Home"), - action: () => Navigator.pushNamed(context, "/home"), + action: () => + Navigator.pushReplacementNamed(context, "/home"), ), alignment: Alignment.bottomCenter, ), diff --git a/LabelStoreMax/lib/resources/pages/coupon_page.dart b/LabelStoreMax/lib/resources/pages/coupon_page.dart new file mode 100644 index 0000000..561a4f8 --- /dev/null +++ b/LabelStoreMax/lib/resources/pages/coupon_page.dart @@ -0,0 +1,223 @@ +import 'package:flutter/material.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'; +import 'package:flutter_app/bootstrap/helpers.dart'; +import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; +import 'package:flutter_app/resources/widgets/buttons.dart'; +import 'package:flutter_app/resources/widgets/safearea_widget.dart'; +import 'package:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/models/response/coupon.dart'; + +class CouponPage extends StatefulWidget { + @override + _CouponPageState createState() => _CouponPageState(); +} + +class _CouponPageState extends State { + List _coupons = []; + bool _isLoading = false; + + final couponController = TextEditingController(); + + _showAlert({String message, ToastNotificationStyleType style}) { + showToastNotification( + context, + title: trans('Coupon'), + description: message, + style: style ?? ToastNotificationStyleType.SUCCESS, + icon: Icons.call_to_action, + ); + } + + _successAddCoupon(Coupon coupon) { + _showAlert(message: trans("Added to checkout")); + CheckoutSession.getInstance.coupon = coupon; + + Navigator.of(context).pop(); + } + + Future findCoupon(String couponCode) async { + setState(() { + _isLoading = true; + }); + + _coupons = await appWooSignal( + (api) => api.getCoupons(code: couponCode, perPage: 100), + ); + + setState(() { + _isLoading = false; + }); + } + + final _formKey = GlobalKey(); + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + CheckoutSession checkoutSession = CheckoutSession.getInstance; + return Scaffold( + body: SafeAreaWidget( + child: Column( + children: [ + SizedBox( + height: 30, + ), + Icon(Icons.local_offer_outlined, size: 30), + Text( + trans('Redeem Coupon'), + style: Theme.of(context).textTheme.headline4, + ), + SizedBox( + height: 30, + ), + Form( + key: _formKey, + child: TextFormField( + autofocus: true, + controller: couponController, + validator: (value) { + if (value.isEmpty) { + return trans('Please enter coupon to redeem'); + } + return null; + }, + decoration: InputDecoration( + focusedBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 0.0), + ), + enabledBorder: const OutlineInputBorder( + borderSide: BorderSide(color: Colors.black, width: 0.0), + ), + border: OutlineInputBorder( + borderRadius: const BorderRadius.all( + Radius.circular(8.0), + ), + borderSide: BorderSide( + color: ThemeColor.get(context).primaryAccent)), + filled: true, + hintStyle: TextStyle(color: Colors.grey[800]), + hintText: trans('Add coupon code'), + fillColor: Colors.grey[200], + ), + ), + ), + SizedBox( + height: 25, + ), + (_isLoading == true) + ? AppLoaderWidget() + : PrimaryButton( + action: () => _applyCoupon(checkoutSession), + title: trans('Apply'), + ), + LinkButton( + title: trans("Cancel"), action: () => Navigator.pop(context)), + ], + ), + ), + ); + } + + _applyCoupon(CheckoutSession checkoutSession) async { + await findCoupon(couponController.text); + + if (_formKey.currentState.validate()) { + // No coupons found + if (_coupons.isEmpty) { + _showAlert( + message: "${trans('Coupon not found')}.", + style: ToastNotificationStyleType.WARNING); + return; + } + + Coupon coupon = _coupons.first; + + DateTime dateNow = DateTime.now(); + List cart = await Cart.getInstance.getCart(); + List productIds = cart.map((e) => e.productId).toList(); + + // Check excludedProductIds + for (var productId in productIds) { + if (coupon.excludedProductIds.contains(productId)) { + _showAlert( + message: + "${trans('Sorry, this coupon can not be used with your cart')}.", + style: ToastNotificationStyleType.INFO); + return; + } + } + + // Check email restrictions + String emailAddress = + checkoutSession.billingDetails.billingAddress.emailAddress; + if (coupon.emailRestrictions.contains(emailAddress)) { + _showAlert( + message: trans('You cannot redeem this coupon'), + style: ToastNotificationStyleType.DANGER); + return; + } + + // Check for minimum amount + double minimumAmount = double.parse(coupon.minimumAmount); + String strSubtotal = await Cart.getInstance.getSubtotal(); + double doubleSubtotal = double.parse(strSubtotal); + if (minimumAmount != 0 && doubleSubtotal < minimumAmount) { + _showAlert( + message: trans("Spend a minimum of minimumAmount to redeem", + arguments: {"minimumAmount": minimumAmount.toString()}), + style: ToastNotificationStyleType.DANGER); + return; + } + + // Check maximum amount + double maximumAmount = double.parse(coupon.maximumAmount); + if (maximumAmount != 0 && doubleSubtotal > maximumAmount) { + _showAlert( + message: trans("Spend less than maximumAmount to redeem", + arguments: {"maximumAmount": maximumAmount.toString()}), + style: ToastNotificationStyleType.DANGER); + return; + } + + // Check if coupon has expired + if (coupon.dateExpires != null && + dateNow.isAfter( + DateTime.parse(coupon.dateExpires), + )) { + _showAlert( + message: trans("This coupon has expired"), + style: ToastNotificationStyleType.WARNING); + return; + } + + // Check usage limit + if (coupon.usageLimit != null && coupon.usageCount >= coupon.usageLimit) { + _showAlert( + message: trans("Usage limit has been reached"), + style: ToastNotificationStyleType.WARNING); + return; + } + + // Check usage limit per user + int limitPerUser = coupon.usageLimitPerUser; + if (limitPerUser != null && + coupon.usedBy + .map((e) => e.toLowerCase()) + .where((usedBy) => usedBy == emailAddress.toLowerCase()) + .length >= + limitPerUser) { + _showAlert( + message: "${trans('You cannot redeem this coupon')}.", + style: ToastNotificationStyleType.WARNING); + return; + } + + _successAddCoupon(coupon); + } + } +} diff --git a/LabelStoreMax/lib/resources/pages/customer_countries.dart b/LabelStoreMax/lib/resources/pages/customer_countries.dart index 713db89..09cabe1 100644 --- a/LabelStoreMax/lib/resources/pages/customer_countries.dart +++ b/LabelStoreMax/lib/resources/pages/customer_countries.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -26,7 +26,7 @@ class _CustomerCountriesPageState extends State { _CustomerCountriesPageState(); List _defaultShipping = [], _activeShippingResults = []; - TextEditingController _tfSearchCountry = TextEditingController(); + final TextEditingController _tfSearchCountry = TextEditingController(); @override void initState() { @@ -45,9 +45,7 @@ class _CustomerCountriesPageState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar( - title: Text( - trans("Select a country") - ), + title: Text(trans("Select a country")), centerTitle: true, ), body: SafeAreaWidget( @@ -57,17 +55,16 @@ class _CustomerCountriesPageState extends State { padding: EdgeInsets.symmetric(vertical: 4, horizontal: 16), margin: EdgeInsets.only(bottom: 10, top: 10), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(18), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.1), - spreadRadius: 2, - blurRadius: 3, - offset: Offset(0, 2), - ), - ], - color: ThemeColor.get(context).background - ), + borderRadius: BorderRadius.circular(18), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.1), + spreadRadius: 2, + blurRadius: 3, + offset: Offset(0, 2), + ), + ], + color: ThemeColor.get(context).background), height: 60, child: Row( children: [ diff --git a/LabelStoreMax/lib/resources/pages/home.dart b/LabelStoreMax/lib/resources/pages/home.dart index 1a36895..65ce8f2 100644 --- a/LabelStoreMax/lib/resources/pages/home.dart +++ b/LabelStoreMax/lib/resources/pages/home.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/bootstrap/app_helper.dart'; +import 'package:flutter_app/resources/widgets/compo_theme_widget.dart'; 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'; @@ -34,6 +35,9 @@ class _HomePageState extends State { if (AppHelper.instance.appConfig.theme == "notic") { theme = NoticThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp); } + if (AppHelper.instance.appConfig.theme == "compo") { + theme = CompoThemeWidget(globalKey: _key, wooSignalApp: _wooSignalApp); + } return theme; } } diff --git a/LabelStoreMax/lib/resources/pages/home_search.dart b/LabelStoreMax/lib/resources/pages/home_search.dart index fc99a9e..1b88d57 100644 --- a/LabelStoreMax/lib/resources/pages/home_search.dart +++ b/LabelStoreMax/lib/resources/pages/home_search.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -26,7 +26,7 @@ class HomeSearchPage extends StatefulWidget { class _HomeSearchPageState extends State { _HomeSearchPageState(); - TextEditingController _txtSearchController = TextEditingController(); + final TextEditingController _txtSearchController = TextEditingController(); @override void initState() { @@ -37,7 +37,8 @@ class _HomeSearchPageState extends State { Navigator.pushNamed(context, "/product-search", arguments: _txtSearchController.text) .then((search) { - if (AppHelper.instance.appConfig.theme != "notic") { + if (["notic", "compo"].contains(AppHelper.instance.appConfig.theme) == + false) { Navigator.pop(context); } }); diff --git a/LabelStoreMax/lib/resources/pages/no_connection_page.dart b/LabelStoreMax/lib/resources/pages/no_connection_page.dart index f6b1dc2..544073f 100644 --- a/LabelStoreMax/lib/resources/pages/no_connection_page.dart +++ b/LabelStoreMax/lib/resources/pages/no_connection_page.dart @@ -1,7 +1,7 @@ // StoreMob // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -29,7 +29,9 @@ class _NoConnectionPageState extends State { @override void initState() { super.initState(); - print('WooCommerce site is not connected'); + if (getEnv('APP_DEBUG') == true) { + NyLogger.error('WooCommerce site is not connected'); + } } @override @@ -67,8 +69,7 @@ class _NoConnectionPageState extends State { if (wooSignalApp == null) { showToastNotification(context, - title: trans("Oops"), - description: trans("Retry later")); + title: trans("Oops"), description: trans("Retry later")); return; } diff --git a/LabelStoreMax/lib/resources/pages/product_detail.dart b/LabelStoreMax/lib/resources/pages/product_detail.dart index fca05da..4ba00b7 100644 --- a/LabelStoreMax/lib/resources/pages/product_detail.dart +++ b/LabelStoreMax/lib/resources/pages/product_detail.dart @@ -1,18 +1,18 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_app/app/controllers/product_detail_controller.dart'; import 'package:flutter_app/app/models/cart.dart'; import 'package:flutter_app/app/models/cart_line_item.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/buttons.dart'; @@ -20,11 +20,14 @@ import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; import 'package:flutter_app/resources/widgets/cart_icon_widget.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:nylo_framework/nylo_framework.dart'; -import 'package:woosignal/models/response/product_variation.dart' as WS; -import 'package:woosignal/models/response/products.dart' as WSProduct; +import 'package:woosignal/models/response/product_variation.dart' + as ws_product_variation; +import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:flutter_swiper/flutter_swiper.dart'; +import 'package:woosignal/models/response/woosignal_app.dart'; class ProductDetailPage extends NyStatefulWidget { + @override final ProductDetailController controller = ProductDetailController(); ProductDetailPage({Key key}) : super(key: key); @@ -34,10 +37,12 @@ class ProductDetailPage extends NyStatefulWidget { class _ProductDetailState extends NyState { bool _isLoading = false; - WSProduct.Product _product; + ws_product.Product _product; + bool isInFavourites = false; int _quantityIndicator = 1; - List _productVariations = []; - Map _tmpAttributeObj = {}; + List _productVariations = []; + final Map _tmpAttributeObj = {}; + final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; @override widgetDidLoad() async { @@ -50,16 +55,16 @@ class _ProductDetailState extends NyState { } _fetchProductVariations() async { - List tmpVariations = []; + List tmpVariations = []; int currentPage = 1; bool isFetching = true; while (isFetching) { - List tmp = await appWooSignal( + List tmp = await appWooSignal( (api) => api.getProductVariations(_product.id, perPage: 100, page: currentPage), ); - if (tmp != null && tmp.length > 0) { + if (tmp != null && tmp.isNotEmpty) { tmpVariations.addAll(tmp); } @@ -75,25 +80,25 @@ class _ProductDetailState extends NyState { }); } - WS.ProductVariation findProductVariation() { - WS.ProductVariation tmpProductVariation; + ws_product_variation.ProductVariation findProductVariation() { + ws_product_variation.ProductVariation tmpProductVariation; Map tmpSelectedObj = {}; - (_tmpAttributeObj.values).forEach((attributeObj) { + for (var attributeObj in _tmpAttributeObj.values) { tmpSelectedObj[attributeObj["name"]] = attributeObj["value"]; - }); + } - _productVariations.forEach((productVariation) { + for (var productVariation in _productVariations) { Map tmpVariations = {}; - productVariation.attributes.forEach((attr) { + for (var attr in productVariation.attributes) { tmpVariations[attr.name] = attr.option; - }); + } if (tmpVariations.toString() == tmpSelectedObj.toString()) { tmpProductVariation = productVariation; } - }); + } return tmpProductVariation; } @@ -101,8 +106,7 @@ class _ProductDetailState extends NyState { _modalBottomSheetOptionsForAttribute(int attributeIndex) { wsModalBottom( context, - title: - "${trans("Select a")} ${_product.attributes[attributeIndex].name}", + title: "${trans("Select a")} ${_product.attributes[attributeIndex].name}", bodyWidget: ListView.separated( itemCount: _product.attributes[attributeIndex].options.length, separatorBuilder: (BuildContext context, int index) => Divider(), @@ -144,7 +148,8 @@ class _ProductDetailState extends NyState { } _modalBottomSheetAttributes() { - WS.ProductVariation productVariation = findProductVariation(); + ws_product_variation.ProductVariation productVariation = + findProductVariation(); wsModalBottom( context, title: trans("Options"), @@ -203,8 +208,7 @@ class _ProductDetailState extends NyState { _tmpAttributeObj.values.length) { showToastNotification(context, title: trans("Oops"), - description: - trans("Please select valid options first"), + description: trans("Please select valid options first"), style: ToastNotificationStyleType.WARNING); return; } @@ -212,8 +216,7 @@ class _ProductDetailState extends NyState { if (productVariation == null) { showToastNotification(context, title: trans("Oops"), - description: - trans("Product variation does not exist"), + description: trans("Product variation does not exist"), style: ToastNotificationStyleType.WARNING); return; } @@ -221,8 +224,7 @@ class _ProductDetailState extends NyState { if (productVariation.stockStatus != "instock") { showToastNotification(context, title: trans("Sorry"), - description: - trans("This item is not in stock"), + description: trans("This item is not in stock"), style: ToastNotificationStyleType.WARNING); return; } @@ -232,27 +234,11 @@ class _ProductDetailState extends NyState { options.add("${v["name"]}: ${v["value"]}"); }); - CartLineItem cartLineItem = CartLineItem( - name: _product.name, - productId: _product.id, - variationId: productVariation.id, - quantity: _quantityIndicator, - taxStatus: productVariation.taxStatus, - shippingClassId: - productVariation.shippingClassId.toString(), - subtotal: productVariation.price, - stockQuantity: productVariation.stockQuantity, - isManagedStock: productVariation.manageStock, - taxClass: productVariation.taxClass, - imageSrc: (productVariation.image != null - ? productVariation.image.src - : _product.images.length == 0 - ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") - : _product.images.first.src), - shippingIsTaxable: _product.shippingTaxable, - variationOptions: options.join(", "), - total: productVariation.price, - ); + CartLineItem cartLineItem = CartLineItem.fromProductVariation( + quantityAmount: _quantityIndicator, + options: options, + product: _product, + productVariation: productVariation); _itemAddToCart(cartLineItem: cartLineItem); Navigator.of(context).pop(); @@ -281,9 +267,18 @@ class _ProductDetailState extends NyState { return Scaffold( appBar: AppBar( actions: [ + if (_wooSignalApp.wishlistEnabled) + IconButton( + onPressed: _toggleWishList, + icon: isInFavourites + ? Icon(Icons.favorite, color: Colors.red) + : Icon(Icons.favorite_border, color: Colors.black54), + ), CartIconWidget(), ], - title: StoreLogo(height: 55, showBgWhite: (Theme.of(context).brightness == Brightness.dark)), + title: StoreLogo( + height: 55, + showBgWhite: (Theme.of(context).brightness == Brightness.dark)), centerTitle: true, ), body: SafeArea( @@ -302,9 +297,11 @@ class _ProductDetailState extends NyState { child: Swiper( itemBuilder: (BuildContext context, int index) => CachedImageWidget( - image: _product.images.length != 0 ? _product.images[index].src : getEnv("PRODUCT_PLACEHOLDER_IMAGE"), + image: _product.images.isNotEmpty + ? _product.images[index].src + : getEnv("PRODUCT_PLACEHOLDER_IMAGE"), ), - itemCount: _product.images.length == 0 + itemCount: _product.images.isEmpty ? 1 : _product.images.length, viewportFraction: 0.85, @@ -375,7 +372,6 @@ class _ProductDetailState extends NyState { Container( decoration: BoxDecoration( color: ThemeColor.get(context).background, - // boxShadow: wsBoxShadow(), borderRadius: BorderRadius.circular(4), ), padding: @@ -548,22 +544,8 @@ class _ProductDetailState extends NyState { return; } _itemAddToCart( - cartLineItem: CartLineItem( - name: _product.name, - productId: _product.id, - quantity: _quantityIndicator, - taxStatus: _product.taxStatus, - shippingClassId: _product.shippingClassId.toString(), - subtotal: _product.price, - taxClass: _product.taxClass, - isManagedStock: _product.manageStock, - stockQuantity: _product.stockQuantity, - shippingIsTaxable: _product.shippingTaxable, - imageSrc: _product.images.length == 0 - ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") - : _product.images.first.src, - total: _product.price, - )); + cartLineItem: CartLineItem.fromProduct( + quantityAmount: _quantityIndicator, product: _product)); } _addQuantityTapped() { @@ -591,4 +573,23 @@ class _ProductDetailState extends NyState { }); } } + + _toggleWishList() async { + String subtitleMsg; + if (isInFavourites) { + await removeWishlistProduct(product: _product); + subtitleMsg = trans("This product has been removed from your wishlist"); + } else { + await saveWishlistProduct(product: _product); + subtitleMsg = trans("This product has been added to your wishlist"); + } + showStatusAlert(context, + title: trans("Success"), + subtitle: subtitleMsg, + icon: Icons.favorite, + duration: 1); + + isInFavourites = !isInFavourites; + setState(() {}); + } } diff --git a/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart b/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart index 18f32cd..58cb049 100644 --- a/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart +++ b/LabelStoreMax/lib/resources/pages/product_image_viewer_page.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -33,8 +33,8 @@ class _ProductImageViewerPageState extends NyState { @override void initState() { Map imageData = widget.controller.data(); - this._initialIndex = imageData['index']; - this._arrImageSrc = imageData['images']; + _initialIndex = imageData['index']; + _arrImageSrc = imageData['images']; super.initState(); } @@ -49,11 +49,11 @@ class _ProductImageViewerPageState extends NyState { index: _initialIndex, itemBuilder: (BuildContext context, int index) => CachedImageWidget( - image: (_arrImageSrc.length == 0 + image: (_arrImageSrc.isEmpty ? getEnv("PRODUCT_PLACEHOLDER_IMAGE") : _arrImageSrc[index]), ), - itemCount: _arrImageSrc.length == 0 ? 1 : _arrImageSrc.length, + itemCount: _arrImageSrc.isEmpty ? 1 : _arrImageSrc.length, viewportFraction: 0.9, scale: 0.95, ), diff --git a/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart b/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart new file mode 100644 index 0000000..1d59b1e --- /dev/null +++ b/LabelStoreMax/lib/resources/pages/wishlist_page_widget.dart @@ -0,0 +1,150 @@ +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:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/models/response/products.dart'; + +class WishListPageWidget extends StatefulWidget { + @override + _WishListPageWidgetState createState() => _WishListPageWidgetState(); +} + +class _WishListPageWidgetState extends State { + List _products = []; + bool isLoading; + + @override + void initState() { + super.initState(); + isLoading = true; + loadProducts(); + } + + loadProducts() async { + List favouriteProducts = await getWishlistProducts(); + List productIds = + favouriteProducts.map((e) => e['id']).cast().toList(); + if (productIds.isEmpty) { + setState(() { + isLoading = false; + }); + return; + } + _products = await appWooSignal((api) => api.getProducts( + include: productIds, + perPage: 100, + status: "publish", + stockStatus: "instock", + )); + setState(() { + isLoading = false; + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text(trans("Wishlist")), + ), + body: SafeArea( + child: isLoading + ? AppLoaderWidget() + : _products.isEmpty && isLoading == false + ? Center( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.favorite, + size: 40, + ), + Padding( + padding: EdgeInsets.symmetric(vertical: 12), + ), + Text(trans("No items found"), + style: Theme.of(context) + .textTheme + .headline6 + .setColor( + context, (color) => color.primaryContent)) + ], + ), + ) + : ListView.separated( + padding: EdgeInsets.only(top: 10), + itemBuilder: (BuildContext context, int index) { + Product product = _products[index]; + return InkWell( + onTap: () => Navigator.pushNamed( + context, "/product-detail", + arguments: product), + child: Container( + child: Row( + children: [ + Container( + child: CachedImageWidget( + image: (product.images.isNotEmpty + ? product.images.first.src + : getEnv("PRODUCT_PLACEHOLDER_IMAGE")), + fit: BoxFit.contain, + width: double.infinity, + ), + width: MediaQuery.of(context).size.width / 4, + ), + Expanded( + child: Container( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + Text(product.name), + Text( + formatStringCurrency( + total: product.price), + ), + ], + ), + ), + ), + Container( + width: 100, + alignment: Alignment.center, + child: IconButton( + icon: Icon( + Icons.favorite, + color: Colors.red, + ), + onPressed: () => + _removeFromWishlist(product), + ), + ) + ], + ), + ), + ); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider(); + }, + itemCount: _products.length)), + ); + } + + _removeFromWishlist(Product product) async { + await removeWishlistProduct(product: product); + showToastNotification( + context, + title: trans('Success'), + icon: Icons.shopping_cart, + description: trans('Item removed'), + ); + _products.remove(product); + setState(() {}); + } +} diff --git a/LabelStoreMax/lib/resources/themes/dark_theme.dart b/LabelStoreMax/lib/resources/themes/dark_theme.dart index ff69480..5cb2530 100644 --- a/LabelStoreMax/lib/resources/themes/dark_theme.dart +++ b/LabelStoreMax/lib/resources/themes/dark_theme.dart @@ -17,20 +17,22 @@ import 'package:nylo_framework/nylo_framework.dart'; ThemeData darkTheme(BaseColorStyles darkColors) { try { - appFont = GoogleFonts.getFont(AppHelper.instance.appConfig.themeFont ?? "Poppins"); - } on Exception catch(e) { + appFont = GoogleFonts.getFont( + AppHelper.instance.appConfig.themeFont ?? "Poppins"); + } on Exception catch (e) { if (getEnv('APP_DEBUG') == true) { NyLogger.error(e.toString()); } } - TextTheme darkTheme = - getAppTextTheme(appFont, defaultTextTheme.merge(_darkTextTheme(darkColors))); + TextTheme darkTheme = getAppTextTheme( + appFont, defaultTextTheme.merge(_darkTextTheme(darkColors))); return ThemeData( primaryColor: darkColors.primaryContent, backgroundColor: darkColors.background, colorScheme: ColorScheme.dark(), primaryColorDark: darkColors.primaryContent, + brightness: Brightness.dark, focusColor: darkColors.primaryContent, scaffoldBackgroundColor: darkColors.background, appBarTheme: AppBarTheme( @@ -55,13 +57,13 @@ ThemeData darkTheme(BaseColorStyles darkColors) { bottomNavigationBarTheme: BottomNavigationBarThemeData( backgroundColor: darkColors.bottomTabBarBackground, unselectedIconTheme: - IconThemeData(color: darkColors.bottomTabBarIconUnselected), + IconThemeData(color: darkColors.bottomTabBarIconUnselected), selectedIconTheme: - IconThemeData(color: darkColors.bottomTabBarIconSelected), + IconThemeData(color: darkColors.bottomTabBarIconSelected), unselectedLabelStyle: - TextStyle(color: darkColors.bottomTabBarLabelUnselected), + TextStyle(color: darkColors.bottomTabBarLabelUnselected), selectedLabelStyle: - TextStyle(color: darkColors.bottomTabBarLabelSelected), + TextStyle(color: darkColors.bottomTabBarLabelSelected), selectedItemColor: darkColors.bottomTabBarLabelSelected, ), textTheme: darkTheme, diff --git a/LabelStoreMax/lib/resources/themes/light_theme.dart b/LabelStoreMax/lib/resources/themes/light_theme.dart index 7dff123..ddede42 100644 --- a/LabelStoreMax/lib/resources/themes/light_theme.dart +++ b/LabelStoreMax/lib/resources/themes/light_theme.dart @@ -17,15 +17,16 @@ import 'package:nylo_framework/nylo_framework.dart'; ThemeData lightTheme(BaseColorStyles lightColors) { try { - appFont = GoogleFonts.getFont(AppHelper.instance.appConfig.themeFont ?? "Poppins"); - } on Exception catch(e) { + appFont = GoogleFonts.getFont( + AppHelper.instance.appConfig.themeFont ?? "Poppins"); + } on Exception catch (e) { if (getEnv('APP_DEBUG') == true) { NyLogger.error(e.toString()); } } - TextTheme lightTheme = - getAppTextTheme(appFont, defaultTextTheme.merge(_lightTextTheme(lightColors))); + TextTheme lightTheme = getAppTextTheme( + appFont, defaultTextTheme.merge(_lightTextTheme(lightColors))); return ThemeData( primaryColor: lightColors.primaryContent, @@ -58,13 +59,13 @@ ThemeData lightTheme(BaseColorStyles lightColors) { bottomNavigationBarTheme: BottomNavigationBarThemeData( backgroundColor: lightColors.bottomTabBarBackground, unselectedIconTheme: - IconThemeData(color: lightColors.bottomTabBarIconUnselected), + IconThemeData(color: lightColors.bottomTabBarIconUnselected), selectedIconTheme: - IconThemeData(color: lightColors.bottomTabBarIconSelected), + IconThemeData(color: lightColors.bottomTabBarIconSelected), unselectedLabelStyle: - TextStyle(color: lightColors.bottomTabBarLabelUnselected), + TextStyle(color: lightColors.bottomTabBarLabelUnselected), selectedLabelStyle: - TextStyle(color: lightColors.bottomTabBarLabelSelected), + TextStyle(color: lightColors.bottomTabBarLabelSelected), selectedItemColor: lightColors.bottomTabBarLabelSelected, ), textTheme: lightTheme, diff --git a/LabelStoreMax/lib/resources/themes/styles/base_styles.dart b/LabelStoreMax/lib/resources/themes/styles/base_styles.dart index 3d91476..dc19230 100644 --- a/LabelStoreMax/lib/resources/themes/styles/base_styles.dart +++ b/LabelStoreMax/lib/resources/themes/styles/base_styles.dart @@ -33,4 +33,4 @@ abstract class BaseColorStyles { Color get bottomTabBarLabelSelected; Color get inputPrimaryContent; -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/resources/themes/styles/dark_theme_colors.dart b/LabelStoreMax/lib/resources/themes/styles/dark_theme_colors.dart index b1e6473..8533121 100644 --- a/LabelStoreMax/lib/resources/themes/styles/dark_theme_colors.dart +++ b/LabelStoreMax/lib/resources/themes/styles/dark_theme_colors.dart @@ -10,33 +10,55 @@ import 'package:flutter_app/resources/themes/styles/base_styles.dart'; class DarkThemeColors implements BaseColorStyles { // general - Color get background => Color(int.parse(AppHelper.instance.appConfig.themeColors['dark']['background'])); + @override + Color get background => Color(int.parse( + AppHelper.instance.appConfig.themeColors['dark']['background'])); + @override Color get backgroundContainer => const Color(0xFF4a4a4a); - Color get primaryContent => Color(int.parse(AppHelper.instance.appConfig.themeColors['dark']['primary_text'])); + @override + Color get primaryContent => Color(int.parse( + AppHelper.instance.appConfig.themeColors['dark']['primary_text'])); + @override Color get primaryAccent => const Color(0xFF818181); + @override Color get surfaceBackground => Color(0xFF818181); + @override Color get surfaceContent => Colors.black; // app bar - Color get appBarBackground => Color(int.parse(AppHelper.instance.appConfig.themeColors['dark']['app_bar_background'])); - Color get appBarPrimaryContent => Color(int.parse(AppHelper.instance.appConfig.themeColors['dark']['app_bar_text'])); + @override + Color get appBarBackground => Color(int.parse( + AppHelper.instance.appConfig.themeColors['dark']['app_bar_background'])); + @override + Color get appBarPrimaryContent => Color(int.parse( + AppHelper.instance.appConfig.themeColors['dark']['app_bar_text'])); + @override Color get inputPrimaryContent => Colors.white; // buttons - Color get buttonBackground => Color(int.parse(AppHelper.instance.appConfig.themeColors['dark']['button_background'])); - Color get buttonPrimaryContent => Color(int.parse(AppHelper.instance.appConfig.themeColors['dark']['button_text'])); + @override + Color get buttonBackground => Color(int.parse( + AppHelper.instance.appConfig.themeColors['dark']['button_background'])); + @override + Color get buttonPrimaryContent => Color(int.parse( + AppHelper.instance.appConfig.themeColors['dark']['button_text'])); // bottom tab bar + @override Color get bottomTabBarBackground => const Color(0xFF232c33); // bottom tab bar - icons + @override Color get bottomTabBarIconSelected => Colors.white70; + @override Color get bottomTabBarIconUnselected => Colors.white60; // bottom tab bar - label + @override Color get bottomTabBarLabelUnselected => Colors.white54; + @override Color get bottomTabBarLabelSelected => Colors.white; -} \ No newline at end of file +} diff --git a/LabelStoreMax/lib/resources/themes/styles/light_theme_colors.dart b/LabelStoreMax/lib/resources/themes/styles/light_theme_colors.dart index f3bc31f..af85d53 100644 --- a/LabelStoreMax/lib/resources/themes/styles/light_theme_colors.dart +++ b/LabelStoreMax/lib/resources/themes/styles/light_theme_colors.dart @@ -11,32 +11,54 @@ import 'package:flutter_app/resources/themes/styles/base_styles.dart'; class LightThemeColors implements BaseColorStyles { // general - Color get background => Color(int.parse(AppHelper.instance.appConfig.themeColors['light']['background'])); + @override + Color get background => Color(int.parse( + AppHelper.instance.appConfig.themeColors['light']['background'])); + @override Color get backgroundContainer => Colors.white; - Color get primaryContent => Color(int.parse(AppHelper.instance.appConfig.themeColors['light']['primary_text'])); + @override + Color get primaryContent => Color(int.parse( + AppHelper.instance.appConfig.themeColors['light']['primary_text'])); + @override Color get primaryAccent => const Color(0xFF87c694); + @override Color get surfaceBackground => Colors.white; + @override Color get surfaceContent => Colors.black; // app bar - Color get appBarBackground => Color(int.parse(AppHelper.instance.appConfig.themeColors['light']['app_bar_background'])); - Color get appBarPrimaryContent => Color(int.parse(AppHelper.instance.appConfig.themeColors['light']['app_bar_text'])); + @override + Color get appBarBackground => Color(int.parse( + AppHelper.instance.appConfig.themeColors['light']['app_bar_background'])); + @override + Color get appBarPrimaryContent => Color(int.parse( + AppHelper.instance.appConfig.themeColors['light']['app_bar_text'])); + @override Color get inputPrimaryContent => Colors.black; // buttons - Color get buttonBackground => Color(int.parse(AppHelper.instance.appConfig.themeColors['light']['button_background'])); - Color get buttonPrimaryContent => Color(int.parse(AppHelper.instance.appConfig.themeColors['light']['button_text'])); + @override + Color get buttonBackground => Color(int.parse( + AppHelper.instance.appConfig.themeColors['light']['button_background'])); + @override + Color get buttonPrimaryContent => Color(int.parse( + AppHelper.instance.appConfig.themeColors['light']['button_text'])); // bottom tab bar + @override Color get bottomTabBarBackground => Colors.white; // bottom tab bar - icons + @override Color get bottomTabBarIconSelected => Colors.blue; + @override Color get bottomTabBarIconUnselected => Colors.black54; // bottom tab bar - label + @override Color get bottomTabBarLabelUnselected => Colors.black45; + @override Color get bottomTabBarLabelSelected => Colors.black; } diff --git a/LabelStoreMax/lib/resources/widgets/app_loader_widget.dart b/LabelStoreMax/lib/resources/widgets/app_loader_widget.dart index cbad679..51dcae6 100644 --- a/LabelStoreMax/lib/resources/widgets/app_loader_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/app_loader_widget.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_spinkit/flutter_spinkit.dart'; import 'package:hexcolor/hexcolor.dart'; @@ -20,7 +19,6 @@ class AppLoaderWidget extends StatelessWidget { Widget build(BuildContext context) { bool isDark = (Theme.of(context).brightness == Brightness.dark); return SpinKitDoubleBounce( - color: HexColor(!isDark ? "#424242" : "#c7c7c7") - ); + color: HexColor(!isDark ? "#424242" : "#c7c7c7")); } } diff --git a/LabelStoreMax/lib/resources/widgets/app_version_widget.dart b/LabelStoreMax/lib/resources/widgets/app_version_widget.dart index c2252ae..912e1cc 100644 --- a/LabelStoreMax/lib/resources/widgets/app_version_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/app_version_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -29,8 +29,7 @@ class AppVersionWidget extends StatelessWidget { case ConnectionState.done: if (snapshot.hasError) return Text(""); return Padding( - child: Text( - "${trans("Version")}: ${snapshot.data.version}", + child: Text("${trans("Version")}: ${snapshot.data.version}", style: Theme.of(context) .textTheme .bodyText2 diff --git a/LabelStoreMax/lib/resources/widgets/buttons.dart b/LabelStoreMax/lib/resources/widgets/buttons.dart index bde64db..724be8b 100644 --- a/LabelStoreMax/lib/resources/widgets/buttons.dart +++ b/LabelStoreMax/lib/resources/widgets/buttons.dart @@ -1,13 +1,14 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:hexcolor/hexcolor.dart'; @@ -27,11 +28,11 @@ class PrimaryButton extends StatelessWidget { key: key, title: title, action: action, - textStyle: Theme.of(context) - .textTheme - .button - .copyWith(fontSize: 16, fontWeight: FontWeight.bold, color: ThemeColor.get(context).buttonPrimaryContent), - bgColor: ThemeColor.get(context).buttonBackground, + textStyle: Theme.of(context).textTheme.button.copyWith( + fontSize: 16, + fontWeight: FontWeight.bold, + color: ThemeColor.get(context).buttonPrimaryContent), + bgColor: ThemeColor.get(context).buttonBackground, ); } @@ -109,14 +110,14 @@ class WooSignalButton extends StatelessWidget { elevation: 0, primary: bgColor, shadowColor: Colors.transparent), - child: Text( + child: AutoSizeText( title, style: textStyle, maxLines: (screenWidth >= 385 ? 2 : 1), textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, ), - onPressed: action ?? null, + onPressed: action, ), ); } diff --git a/LabelStoreMax/lib/resources/widgets/cached_image_widget.dart b/LabelStoreMax/lib/resources/widgets/cached_image_widget.dart index a2a2955..721a2bc 100644 --- a/LabelStoreMax/lib/resources/widgets/cached_image_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/cached_image_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -19,10 +19,9 @@ class CachedImageWidget extends StatelessWidget { this.width = 70, this.placeholder = const Center( child: CircularProgressIndicator( - strokeWidth: 2, - backgroundColor: Colors.black12, - color: Colors.black54 - ), + strokeWidth: 2, + backgroundColor: Colors.black12, + color: Colors.black54), ), this.fit = BoxFit.contain, }) : super(key: key); @@ -37,7 +36,7 @@ class CachedImageWidget extends StatelessWidget { Widget build(BuildContext context) => CachedNetworkImage( imageUrl: image, placeholder: (context, url) => placeholder, - errorWidget: (context, url, error) => new Icon(Icons.error), + errorWidget: (context, url, error) => Icon(Icons.error), height: height, width: width, alignment: Alignment.center, diff --git a/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart b/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart index 0fedc06..39d7f1b 100644 --- a/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/cart_icon_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -48,7 +48,7 @@ class _CartIconWidgetState extends State { List cartItems = snapshot.data.map((e) => e.quantity).toList(); String cartValue = "0"; - if (cartItems.length > 0) { + if (cartItems.isNotEmpty) { cartValue = cartItems .reduce((value, element) => value + element) .toString(); diff --git a/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart b/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart new file mode 100644 index 0000000..4ea73c1 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/category_subcategory_scroll_widget.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class CategorySubcategoryScrollWidget extends StatefulWidget { + @override + _CategorySubcategoryScrollWidgetState createState() => + _CategorySubcategoryScrollWidgetState(); +} + +class _CategorySubcategoryScrollWidgetState + extends State { + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/checkout_coupon_amount_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_coupon_amount_widget.dart new file mode 100644 index 0000000..8e9a195 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/checkout_coupon_amount_widget.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/app/models/cart.dart'; +import 'package:flutter_app/app/models/checkout_session.dart'; +import 'package:flutter_app/bootstrap/helpers.dart'; +import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; +import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class CheckoutCouponAmountWidget extends StatelessWidget { + const CheckoutCouponAmountWidget({Key key, @required this.checkoutSession}) + : super(key: key); + + final CheckoutSession checkoutSession; + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: Cart.getInstance.couponDiscountAmount(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return AppLoaderWidget(); + default: + if (snapshot.hasError) { + return Text(""); + } else { + if (checkoutSession.coupon == null) { + return Container(); + } + return Padding( + child: CheckoutMetaLine( + title: "${trans('Coupon')}: ${checkoutSession.coupon.code}", + amount: "-" + formatStringCurrency(total: snapshot.data), + ), + padding: EdgeInsets.only(bottom: 0, top: 0), + ); + } + } + }, + ); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart new file mode 100644 index 0000000..ce1f6d4 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/checkout_payment_type_widget.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/app/models/checkout_session.dart'; +import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class CheckoutPaymentTypeWidget extends StatelessWidget { + const CheckoutPaymentTypeWidget( + {Key key, + @required this.context, + @required this.checkoutSession, + this.resetState}) + : super(key: key); + final CheckoutSession checkoutSession; + final BuildContext context; + final Function resetState; + + @override + Widget build(BuildContext context) { + bool hasPaymentType = checkoutSession.paymentType != null; + return CheckoutRowLine( + heading: trans(hasPaymentType ? "Payment method" : "Pay with"), + leadImage: hasPaymentType + ? Container( + color: Colors.white, + child: Image.asset( + getImageAsset(checkoutSession.paymentType.assetImage), + width: 70, + ), + ) + : Icon(Icons.payment), + leadTitle: hasPaymentType + ? checkoutSession.paymentType.desc + : trans("Select a payment method"), + action: _actionPayWith, + showBorderBottom: true, + ); + } + + _actionPayWith() { + Navigator.pushNamed(context, "/checkout-payment-type") + .then((value) => resetState()); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/checkout_paypal.dart b/LabelStoreMax/lib/resources/widgets/checkout_paypal.dart index 7fb6978..f87e4cf 100644 --- a/LabelStoreMax/lib/resources/widgets/checkout_paypal.dart +++ b/LabelStoreMax/lib/resources/widgets/checkout_paypal.dart @@ -24,50 +24,51 @@ class PayPalCheckout extends StatefulWidget { class WebViewState extends NyState { final Completer _controller = - Completer(); + Completer(); String payerId = ''; int intCount = 0; StreamSubscription _onUrlChanged; - WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; + final WooSignalApp _wooSignalApp = AppHelper.instance.appConfig; String formCheckoutShippingAddress; setCheckoutShippingAddress(CustomerAddress customerAddress) { String tmp = ""; if (customerAddress.firstName != null) { tmp += - '\n'; + '\n'; } if (customerAddress.lastName != null) { tmp += - '\n'; + '\n'; } if (customerAddress.addressLine != null) { tmp += - '\n'; + '\n'; } if (customerAddress.city != null) { tmp += - '\n'; + '\n'; } if (customerAddress.customerCountry.hasState() && customerAddress.customerCountry.state.name != null) { tmp += - '\n'; + '\n'; } if (customerAddress.postalCode != null) { tmp += - '\n'; + '\n'; } if (customerAddress.customerCountry.countryCode != null) { tmp += - '\n'; + '\n'; } formCheckoutShippingAddress = tmp; } String getPayPalItemName() { - return truncateString(widget.description.replaceAll(new RegExp(r'[^\w\s]+'),''), 124); + return truncateString( + widget.description.replaceAll(RegExp(r'[^\w\s]+'), ''), 124); } String getPayPalPaymentType() { @@ -75,7 +76,8 @@ class WebViewState extends NyState { } String getPayPalUrl() { - bool liveMode = envVal('PAYPAL_LIVE_MODE', defaultValue: _wooSignalApp.paypalLiveMode); + bool liveMode = + envVal('PAYPAL_LIVE_MODE', defaultValue: _wooSignalApp.paypalLiveMode); return liveMode == true ? "https://www.paypal.com/cgi-bin/webscr" : "https://www.sandbox.paypal.com/cgi-bin/webscr"; @@ -100,8 +102,10 @@ class WebViewState extends NyState { String _loadHTML() { final String strProcessingPayment = trans("Processing Payment"); - final String strPleaseWait = trans("Please wait, your order is being processed and you will be redirected to the PayPal website."); - final String strRedirectMessage = trans("If you are not automatically redirected to PayPal within 5 seconds"); + final String strPleaseWait = trans( + "Please wait, your order is being processed and you will be redirected to the PayPal website."); + final String strRedirectMessage = trans( + "If you are not automatically redirected to PayPal within 5 seconds"); return ''' $strProcessingPayment... @@ -125,7 +129,8 @@ $formCheckoutShippingAddress


$strRedirectMessage...

-'''.toString(); +''' + .toString(); } @override @@ -134,18 +139,17 @@ $formCheckoutShippingAddress resizeToAvoidBottomInset: false, body: SafeArea( child: WebView( - initialUrl: Uri.dataFromString(_loadHTML(), mimeType: 'text/html').toString(), + initialUrl: + Uri.dataFromString(_loadHTML(), mimeType: 'text/html').toString(), javascriptMode: JavascriptMode.unrestricted, onWebViewCreated: (WebViewController webViewController) { _controller.complete(webViewController); }, - onProgress: (int progress) { - }, + onProgress: (int progress) {}, navigationDelegate: (NavigationRequest request) { return NavigationDecision.navigate; }, - onPageStarted: (String url) { - }, + onPageStarted: (String url) {}, onPageFinished: (String url) { if (intCount > 0) { url = url.replaceAll("~", "_"); @@ -157,7 +161,10 @@ $formCheckoutShippingAddress setState(() { payerId = uri.queryParameters['PayerID']; }); - Navigator.pop(context, {"status": payerId == null ? "cancelled" : "success", "payerId": payerId}); + Navigator.pop(context, { + "status": payerId == null ? "cancelled" : "success", + "payerId": payerId + }); } else if (url.contains("payment_failure")) { Navigator.pop(context, {"status": "cancelled"}); } diff --git a/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart new file mode 100644 index 0000000..ba65b21 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/checkout_select_coupon_widget.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/app/models/checkout_session.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class CheckoutSelectCouponWidget extends StatelessWidget { + const CheckoutSelectCouponWidget( + {Key key, + @required this.context, + @required this.checkoutSession, + @required this.resetState}) + : super(key: key); + + final CheckoutSession checkoutSession; + final BuildContext context; + final Function resetState; + + @override + Widget build(BuildContext context) { + bool hasCoupon = checkoutSession.coupon != null; + return InkWell( + onTap: _actionCoupon, + child: Container( + padding: EdgeInsets.symmetric(vertical: 5), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + hasCoupon == true + ? IconButton( + padding: EdgeInsets.symmetric(vertical: 3), + onPressed: _clearCoupon, + icon: Icon( + Icons.close, + size: 19, + )) + : null, + Text( + hasCoupon + ? "Coupon Applied: " + checkoutSession.coupon.code + : trans('Apply Coupon'), + style: Theme.of(context).textTheme.subtitle2, + ), + ].where((element) => element != null).toList(), + ), + ), + ); + } + + _clearCoupon() { + CheckoutSession.getInstance.coupon = null; + resetState(); + } + + _actionCoupon() { + if (checkoutSession.billingDetails.billingAddress == null) { + showToastNotification( + context, + title: trans("Oops"), + description: + trans("Please select add your billing/shipping address to proceed"), + style: ToastNotificationStyleType.WARNING, + icon: Icons.local_shipping, + ); + + return; + } + if (checkoutSession.billingDetails.billingAddress.hasMissingFields()) { + showToastNotification( + context, + title: trans("Oops"), + description: trans("Your billing/shipping details are incomplete"), + style: ToastNotificationStyleType.WARNING, + icon: Icons.local_shipping, + ); + return; + } + Navigator.pushNamed(context, "/checkout-coupons") + .then((value) => resetState()); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart new file mode 100644 index 0000000..bfb267a --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/checkout_shipping_type_widget.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/app/models/checkout_session.dart'; +import 'package:flutter_app/app/models/customer_address.dart'; +import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; +import 'package:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/models/response/woosignal_app.dart'; + +class CheckoutShippingTypeWidget extends StatelessWidget { + const CheckoutShippingTypeWidget( + {Key key, + @required this.context, + @required this.wooSignalApp, + @required this.checkoutSession, + this.resetState}) + : super(key: key); + + final CheckoutSession checkoutSession; + final BuildContext context; + final Function resetState; + final WooSignalApp wooSignalApp; + + @override + Widget build(BuildContext context) { + bool hasDisableShipping = wooSignalApp.disableShipping == 1; + if (hasDisableShipping == true) { + return null; + } + bool hasSelectedShippingType = checkoutSession.shippingType != null; + return CheckoutRowLine( + heading: trans( + hasSelectedShippingType ? "Shipping selected" : "Select shipping"), + leadImage: Icon(Icons.local_shipping), + leadTitle: hasSelectedShippingType + ? checkoutSession.shippingType.getTitle() + : trans("Select a shipping option"), + action: _actionSelectShipping, + showBorderBottom: false, + ); + } + + _actionSelectShipping() { + CustomerAddress shippingAddress = + checkoutSession.billingDetails.shippingAddress; + if (shippingAddress == null || shippingAddress.customerCountry == null) { + showToastNotification(context, + title: trans("Oops"), + description: trans("Add your shipping details first"), + icon: Icons.local_shipping); + return; + } + Navigator.pushNamed(context, "/checkout-shipping-type") + .then((value) => resetState()); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart new file mode 100644 index 0000000..36b6be3 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/checkout_store_heading_widget.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; + +class CheckoutStoreHeadingWidget extends StatelessWidget { + const CheckoutStoreHeadingWidget({Key key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + boxShadow: (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow(blurRadius: 10) + : null, + color: Colors.transparent, + ), + padding: EdgeInsets.all(2), + margin: EdgeInsets.only(top: 16), + child: ClipRRect( + child: StoreLogo(height: 65), + borderRadius: BorderRadius.circular(8), + )); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart b/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart new file mode 100644 index 0000000..7118874 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/checkout_user_details_widget.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/app/models/checkout_session.dart'; +import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; +import 'package:nylo_framework/nylo_framework.dart'; + +class CheckoutUserDetailsWidget extends StatelessWidget { + const CheckoutUserDetailsWidget( + {Key key, + @required this.context, + @required this.checkoutSession, + this.resetState}) + : super(key: key); + final CheckoutSession checkoutSession; + final BuildContext context; + final Function resetState; + + @override + Widget build(BuildContext context) { + bool hasUserCheckoutInfo = (checkoutSession.billingDetails != null && + checkoutSession.billingDetails.billingAddress != null); + return CheckoutRowLine( + heading: trans("Billing/shipping details"), + leadImage: Icon(Icons.home), + leadTitle: hasUserCheckoutInfo + ? (checkoutSession.billingDetails == null || + checkoutSession.billingDetails.billingAddress + .hasMissingFields() + ? trans("Billing address is incomplete") + : checkoutSession.billingDetails.billingAddress.addressFull()) + : trans("Add billing & shipping details"), + action: _actionCheckoutDetails, + showBorderBottom: true, + ); + } + + _actionCheckoutDetails() { + Navigator.pushNamed(context, "/checkout-details").then((e) { + resetState(); + // setState(() { + // _showFullLoader = true; + // }); + // _getTaxes(); + }); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart b/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart new file mode 100644 index 0000000..a6d59e1 --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/compo_home_widget.dart @@ -0,0 +1,186 @@ +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/buttons.dart'; +import 'package:flutter_app/resources/widgets/cached_image_widget.dart'; +import 'package:flutter_app/resources/widgets/home_drawer_widget.dart'; +import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; +import 'package:flutter_swiper/flutter_swiper.dart'; +import 'package:nylo_framework/nylo_framework.dart'; +import 'package:woosignal/models/response/product_category.dart'; +import 'package:woosignal/models/response/woosignal_app.dart'; +import 'package:woosignal/models/response/products.dart'; + +class CompoHomeWidget extends StatefulWidget { + CompoHomeWidget({Key key, @required this.wooSignalApp}) : super(key: key); + + final WooSignalApp wooSignalApp; + + @override + _CompoHomeWidgetState createState() => _CompoHomeWidgetState(); +} + +class _CompoHomeWidgetState extends State { + @override + void initState() { + super.initState(); + _loadHome(); + } + + _loadHome() async { + categories = await appWooSignal((api) => + api.getProductCategories(parent: 0, perPage: 20, hideEmpty: true)); + categories.sort((category1, category2) => + category1.menuOrder.compareTo(category2.menuOrder)); + + for (var category in categories) { + List products = await appWooSignal((api) => api.getProducts( + perPage: 10, + category: category.id.toString(), + status: "publish", + stockStatus: "instock")); + if (products.isNotEmpty) { + categoryAndProducts.addAll({category: products}); + setState(() {}); + } + } + } + + List categories = []; + Map> categoryAndProducts = {}; + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + Size size = MediaQuery.of(context).size; + List bannerImages = widget.wooSignalApp.bannerImages; + return Scaffold( + drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp), + appBar: AppBar( + centerTitle: true, + title: StoreLogo(), + elevation: 0, + ), + body: SafeArea( + child: categoryAndProducts.isEmpty + ? AppLoaderWidget() + : ListView( + shrinkWrap: true, + children: [ + if (bannerImages.isNotEmpty) + Container( + child: Swiper( + itemBuilder: (BuildContext context, int index) { + return CachedImageWidget( + image: bannerImages[index], + fit: BoxFit.cover, + ); + }, + itemCount: bannerImages.length, + viewportFraction: 0.8, + scale: 0.9, + ), + height: size.height / 2.5, + ), + ...categoryAndProducts.entries.map((catProds) { + double containerHeight = size.height / 1.1; + bool hasImage = catProds.key.image != null; + if (hasImage == false) { + containerHeight = (containerHeight / 2); + } + return Container( + height: containerHeight, + width: size.width, + margin: EdgeInsets.only(top: 10), + child: Column( + children: [ + hasImage + ? InkWell( + child: CachedImageWidget( + image: catProds.key.image.src, + height: containerHeight / 2, + width: MediaQuery.of(context).size.width, + fit: BoxFit.cover, + ), + onTap: () => _showCategory(catProds.key)) + : null, + ConstrainedBox( + constraints: BoxConstraints( + minHeight: 50, + minWidth: double.infinity, + maxHeight: 80.0, + maxWidth: double.infinity, + ), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + catProds.key.name, + style: Theme.of(context) + .textTheme + .subtitle1 + .copyWith( + fontWeight: FontWeight.bold, + fontSize: 22), + ), + ), + Flexible( + child: Container( + width: size.width / 4, + child: LinkButton( + title: trans("View All"), + action: () => + _showCategory(catProds.key), + ), + ), + ), + ], + ), + ), + ), + Container( + height: hasImage + ? (containerHeight / 2) / 1.2 + : containerHeight / 1.2, + padding: EdgeInsets.symmetric(horizontal: 8), + child: ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: false, + itemBuilder: (cxt, i) { + Product product = catProds.value[i]; + return Container( + height: MediaQuery.of(cxt).size.height, + width: size.width / 2.5, + child: ProductItemContainer( + product: product, onTap: _showProduct), + ); + }, + itemCount: catProds.value.length, + ), + ) + ].where((e) => e != null).toList(), + ), + ); + }), + ], + ), + ), + ); + } + + _showCategory(ProductCategory productCategory) => + Navigator.pushNamed(context, "/browse-category", + arguments: productCategory); + + _showProduct(Product product) => + Navigator.pushNamed(context, "/product-detail", arguments: product); +} diff --git a/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart b/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart new file mode 100644 index 0000000..68be90b --- /dev/null +++ b/LabelStoreMax/lib/resources/widgets/compo_theme_widget.dart @@ -0,0 +1,143 @@ +// +// LabelCore +// Label StoreMax +// +// Created by Anthony Gordon. +// 2022, 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_app/app/models/bottom_nav_item.dart'; +import 'package:flutter_app/bootstrap/app_helper.dart'; +import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart'; +import 'package:flutter_app/resources/pages/account_detail.dart'; +import 'package:flutter_app/resources/pages/account_landing.dart'; +import 'package:flutter_app/resources/pages/cart.dart'; +import 'package:flutter_app/resources/pages/wishlist_page_widget.dart'; +import 'package:flutter_app/resources/pages/home_search.dart'; +import 'package:flutter_app/resources/widgets/app_loader_widget.dart'; +import 'package:flutter_app/resources/widgets/compo_home_widget.dart'; +import 'package:woosignal/models/response/woosignal_app.dart'; + +class CompoThemeWidget extends StatefulWidget { + CompoThemeWidget( + {Key key, @required this.globalKey, @required this.wooSignalApp}) + : super(key: key); + final WooSignalApp wooSignalApp; + final GlobalKey globalKey; + + @override + CcompoThemeWidgetState createState() => CcompoThemeWidgetState(); +} + +class CcompoThemeWidgetState extends State { + Widget activeWidget; + + int _currentIndex = 0; + List allNavWidgets; + + @override + void initState() { + super.initState(); + + activeWidget = CompoHomeWidget(wooSignalApp: widget.wooSignalApp); + _loadTabs(); + } + + _loadTabs() async { + allNavWidgets = await bottomNavWidgets(); + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: activeWidget, + bottomNavigationBar: allNavWidgets == null + ? AppLoaderWidget() + : BottomNavigationBar( + onTap: (currentIndex) => + _changeMainWidget(currentIndex, allNavWidgets), + currentIndex: _currentIndex, + unselectedItemColor: Colors.black54, + type: BottomNavigationBarType.fixed, + fixedColor: Colors.black87, + selectedLabelStyle: TextStyle(color: Colors.black), + unselectedLabelStyle: TextStyle( + color: Colors.black87, + ), + showSelectedLabels: false, + showUnselectedLabels: false, + items: + allNavWidgets.map((e) => e.bottomNavigationBarItem).toList(), + ), + ); + } + + Future> bottomNavWidgets() async { + List items = []; + items.add( + BottomNavItem( + id: 1, + bottomNavigationBarItem: BottomNavigationBarItem( + icon: Icon(Icons.home), + label: 'Home', + ), + tabWidget: CompoHomeWidget(wooSignalApp: widget.wooSignalApp)), + ); + + items.add( + BottomNavItem( + id: 2, + bottomNavigationBarItem: BottomNavigationBarItem( + icon: Icon(Icons.search), + label: 'Search', + ), + tabWidget: HomeSearchPage()), + ); + + if (AppHelper.instance.appConfig.wishlistEnabled == true) { + items.add(BottomNavItem( + id: 3, + bottomNavigationBarItem: BottomNavigationBarItem( + icon: Icon(Icons.favorite_border), + label: 'Wishlist', + ), + tabWidget: WishListPageWidget(), + )); + } + + items.add(BottomNavItem( + id: 4, + bottomNavigationBarItem: BottomNavigationBarItem( + icon: Icon(Icons.shopping_cart), label: 'Cart'), + tabWidget: CartPage(), + )); + + if (AppHelper.instance.appConfig.wpLoginEnabled == 1) { + items.add(BottomNavItem( + id: 5, + bottomNavigationBarItem: + BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Account'), + tabWidget: (await authCheck()) + ? AccountDetailPage(showLeadingBackButton: false) + : AccountLandingPage( + showBackButton: false, + ), + )); + } + return items; + } + + _changeMainWidget( + int currentIndex, List bottomNavWidgets) async { + _currentIndex = currentIndex; + activeWidget = bottomNavWidgets[_currentIndex].tabWidget; + setState(() {}); + } +} diff --git a/LabelStoreMax/lib/resources/widgets/customer_address_input.dart b/LabelStoreMax/lib/resources/widgets/customer_address_input.dart index edbc674..b5c9bf5 100644 --- a/LabelStoreMax/lib/resources/widgets/customer_address_input.dart +++ b/LabelStoreMax/lib/resources/widgets/customer_address_input.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart b/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart index 4583adf..9c16ae1 100644 --- a/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/home_drawer_widget.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/helpers.dart'; @@ -31,18 +30,19 @@ class HomeDrawerWidget extends StatefulWidget { } class _HomeDrawerWidgetState extends State { - Map _socialLinks = {}; - + String _themeType; @override void initState() { super.initState(); _socialLinks = AppHelper.instance.appConfig.socialLinks ?? {}; + _themeType = AppHelper.instance.appConfig.theme; } @override Widget build(BuildContext context) { + print(widget.wooSignalApp.wishlistEnabled); bool isDark = (Theme.of(context).brightness == Brightness.dark); return Drawer( child: Container( @@ -56,29 +56,55 @@ class _HomeDrawerWidgetState extends State { color: ThemeColor.get(context).background, ), ), - Padding( - child: Text( - trans("Menu"), - style: Theme.of(context).textTheme.subtitle2, + if (["compo"].contains(_themeType) == false) + Column( + children: [ + Padding( + child: Text( + trans("Menu"), + style: Theme.of(context).textTheme.subtitle2, + ), + padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), + ), + if (widget.wooSignalApp.wpLoginEnabled == 1) + ListTile( + title: Text( + trans("Profile"), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16), + ), + leading: Icon(Icons.account_circle), + onTap: _actionProfile, + ), + if (widget.wooSignalApp.wishlistEnabled == true) + ListTile( + title: Text( + trans("Wishlist"), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16), + ), + leading: Icon(Icons.favorite_border), + onTap: _actionWishlist, + ), + ListTile( + title: Text( + trans("Cart"), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16), + ), + leading: Icon(Icons.shopping_cart), + onTap: _actionCart, + ), + ], ), - padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), - ), - if (widget.wooSignalApp.wpLoginEnabled == 1) - ListTile( - title: Text(trans("Profile"), style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 16 - ),), - leading: Icon(Icons.account_circle), - onTap: _actionProfile, - ), - ListTile( - title: Text(trans("Cart"), style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 16 - ),), - leading: Icon(Icons.shopping_cart), - onTap: _actionCart, - ), - if (widget.wooSignalApp.appTermsLink != null && widget.wooSignalApp.appPrivacyLink != null) + if (widget.wooSignalApp.appTermsLink != null && + widget.wooSignalApp.appPrivacyLink != null) Padding( child: Text( trans("About Us"), @@ -89,10 +115,13 @@ class _HomeDrawerWidgetState extends State { if (widget.wooSignalApp.appTermsLink != null && widget.wooSignalApp.appTermsLink.isNotEmpty) ListTile( - title: Text(trans("Terms and conditions"), - style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 16 - ),), + title: Text( + trans("Terms and conditions"), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16), + ), leading: Icon(Icons.menu_book_rounded), trailing: Icon(Icons.keyboard_arrow_right_rounded), onTap: _actionTerms, @@ -100,47 +129,58 @@ class _HomeDrawerWidgetState extends State { if (widget.wooSignalApp.appPrivacyLink != null && widget.wooSignalApp.appPrivacyLink.isNotEmpty) ListTile( - title: Text(trans("Privacy policy"), style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 16 - ),), + title: Text( + trans("Privacy policy"), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16), + ), trailing: Icon(Icons.keyboard_arrow_right_rounded), leading: Icon(Icons.account_balance), onTap: _actionPrivacy, ), ListTile( - title: Text( - trans((isDark ? "Light Mode" : "Dark Mode")), - style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 16 - ) - ), + title: Text(trans((isDark ? "Light Mode" : "Dark Mode")), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16)), leading: Icon(Icons.brightness_4_rounded), onTap: () { setState(() { - NyTheme.set(context, id: isDark ? "default_light_theme" : "default_dark_theme"); + NyTheme.set(context, + id: isDark + ? "default_light_theme" + : "default_dark_theme"); }); }, ), if (_socialLinks.isNotEmpty) - Padding( - child: Text( - trans("Social"), - style: Theme.of(context).textTheme.subtitle2, + Padding( + child: Text( + trans("Social"), + style: Theme.of(context).textTheme.subtitle2, + ), + padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), ), - padding: EdgeInsets.only(left: 16, top: 8, bottom: 8), - ), - ..._socialLinks.entries.where((element) => element != null && element.value != "").map((socialLink) => ListTile( - title: Text( - capitalize(socialLink.key), - style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 16 - ) - ), - leading: Image.asset(getImageAsset(socialLink.key) + '.png', height: 25, width: 25), - onTap: () async { - await launch(socialLink.value); - }, - )).toList(), + ..._socialLinks.entries + .where((element) => element != null && element.value != "") + .map((socialLink) => ListTile( + title: Text(capitalize(socialLink.key), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16)), + leading: Image.asset( + getImageAsset(socialLink.key) + '.png', + height: 25, + width: 25), + onTap: () async { + await launch(socialLink.value); + }, + )) + .toList(), ListTile( title: AppVersionWidget(), ), @@ -164,6 +204,11 @@ class _HomeDrawerWidgetState extends State { Navigator.pushNamed(context, "/account-detail"); } + _actionWishlist() async { + Navigator.pop(context); + Navigator.pushNamed(context, "/wishlist"); + } + _actionCart() { Navigator.pop(context); Navigator.pushNamed(context, "/cart"); diff --git a/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart b/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart index 158c5b5..8246163 100644 --- a/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/mello_theme_widget.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_app/app/controllers/product_loader_controller.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'; @@ -8,8 +9,8 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:nylo_support/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; +import 'package:woosignal/models/response/product_category.dart' as ws_category; +import 'package:woosignal/models/response/products.dart' as ws_product; class MelloThemeWidget extends StatefulWidget { MelloThemeWidget( @@ -23,16 +24,14 @@ class MelloThemeWidget extends StatefulWidget { } class _MelloThemeWidgetState extends State { - RefreshController _refreshController = + final RefreshController _refreshController = RefreshController(initialRefresh: false); + final ProductLoaderController _productLoaderController = + ProductLoaderController(); - List _products = []; - List _categories = []; + List _categories = []; - int _page = 1; - bool _shouldStopRequests = false, - waitForNextRequest = false, - _isLoading = true; + bool _shouldStopRequests = false, _isLoading = true; @override void initState() { @@ -41,7 +40,7 @@ class _MelloThemeWidgetState extends State { } _home() async { - await _fetchMoreProducts(); + await fetchProducts(); await _fetchCategories(); setState(() { _isLoading = false; @@ -53,31 +52,6 @@ class _MelloThemeWidgetState extends State { await appWooSignal((api) => api.getProductCategories(perPage: 100)); } - _fetchMoreProducts() async { - if (waitForNextRequest || _shouldStopRequests) { - return; - } - waitForNextRequest = true; - - List products = await appWooSignal((api) => - api.getProducts( - perPage: 50, - page: _page, - status: "publish", - stockStatus: "instock"), - ); - if (products.length == 0) { - _shouldStopRequests = true; - setState(() {}); - return; - } - _page = _page + 1; - waitForNextRequest = false; - setState(() { - _products.addAll(products); - }); - } - _modalBottomSheetMenu() { widget.globalKey.currentState.setState(() {}); wsModalBottom( @@ -126,16 +100,18 @@ class _MelloThemeWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( - child: _isLoading ? AppLoaderWidget() : RefreshableScrollContainer( - controller: _refreshController, - onRefresh: _onRefresh, - onLoading: _onLoading, - products: _products, - onTap: _showProduct, - bannerHeight: MediaQuery.of(context).size.height / 3.5, - bannerImages: bannerImages, - modalBottomSheetMenu: _modalBottomSheetMenu, - ), + child: _isLoading + ? AppLoaderWidget() + : RefreshableScrollContainer( + controller: _refreshController, + onRefresh: _onRefresh, + onLoading: _onLoading, + products: _productLoaderController.getResults(), + onTap: _showProduct, + bannerHeight: MediaQuery.of(context).size.height / 3.5, + bannerImages: bannerImages, + modalBottomSheetMenu: _modalBottomSheetMenu, + ), flex: 1, ), ], @@ -145,16 +121,15 @@ class _MelloThemeWidgetState extends State { } _onRefresh() async { - _products = []; - _page = 1; + _productLoaderController.clear(); _shouldStopRequests = false; - waitForNextRequest = false; - await _fetchMoreProducts(); + + await fetchProducts(); _refreshController.refreshCompleted(); } _onLoading() async { - await _fetchMoreProducts(); + await fetchProducts(); if (mounted) { setState(() {}); @@ -166,7 +141,21 @@ class _MelloThemeWidgetState extends State { } } - _showProduct(WSProduct.Product product) => + Future fetchProducts() async { + await _productLoaderController.loadProducts( + hasResults: (result) { + if (result == false) { + setState(() { + _shouldStopRequests = true; + }); + return false; + } + return true; + }, + didFinish: () => setState(() {})); + } + + _showProduct(ws_product.Product product) => Navigator.pushNamed(context, "/product-detail", arguments: product) .then((value) => widget.globalKey.currentState.setState(() {})); } diff --git a/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart b/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart index b67d394..055842b 100644 --- a/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/no_results_for_products_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart b/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart index 7f6e2de..54f3d3b 100644 --- a/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/notic_home_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app/app/controllers/product_loader_controller.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'; @@ -12,8 +13,8 @@ import 'package:flutter_swiper/flutter_swiper.dart'; import 'package:nylo_support/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; +import 'package:woosignal/models/response/product_category.dart' as ws_category; +import 'package:woosignal/models/response/products.dart' as ws_product; class NoticHomeWidget extends StatefulWidget { NoticHomeWidget({Key key, @required this.wooSignalApp}) : super(key: key); @@ -26,16 +27,14 @@ class NoticHomeWidget extends StatefulWidget { class _NoticHomeWidgetState extends State { Widget activeWidget; - RefreshController _refreshController = + final RefreshController _refreshController = RefreshController(initialRefresh: false); - List _products = []; - List _categories = []; + final ProductLoaderController _productLoaderController = + ProductLoaderController(); + List _categories = []; - int _page = 1; - bool _shouldStopRequests = false, - waitForNextRequest = false, - _isLoading = true; + bool _shouldStopRequests = false, _isLoading = true; @override void initState() { @@ -44,7 +43,7 @@ class _NoticHomeWidgetState extends State { } _home() async { - await _fetchMoreProducts(); + await fetchProducts(); await _fetchCategories(); setState(() { _isLoading = false; @@ -56,32 +55,6 @@ class _NoticHomeWidgetState extends State { await appWooSignal((api) => api.getProductCategories(perPage: 100)); } - _fetchMoreProducts() async { - if (waitForNextRequest || _shouldStopRequests) { - return; - } - waitForNextRequest = true; - - List products = await appWooSignal((api) => - api.getProducts( - perPage: 50, - page: _page, - status: "publish", - stockStatus: "instock"), - ); - - if (products.length == 0) { - _shouldStopRequests = true; - setState(() {}); - return; - } else { - _products.addAll(products); - } - _page = _page + 1; - waitForNextRequest = false; - setState(() {}); - } - _modalBottomSheetMenu() { wsModalBottom( context, @@ -104,6 +77,7 @@ class _NoticHomeWidgetState extends State { @override Widget build(BuildContext context) { + List products = _productLoaderController.getResults(); return Scaffold( drawer: HomeDrawerWidget(wooSignalApp: widget.wooSignalApp), appBar: AppBar( @@ -162,7 +136,8 @@ class _NoticHomeWidgetState extends State { child: Text( trans("Our selection of new items"), style: Theme.of(context).textTheme.headline4, - maxLines: 2, overflow: TextOverflow.ellipsis, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), ) ], @@ -181,13 +156,12 @@ class _NoticHomeWidgetState extends State { } else if (mode == LoadStatus.loading) { body = CupertinoActivityIndicator(); } else if (mode == LoadStatus.failed) { - body = Text(trans("Load Failed! Click retry!")); - } else if (mode == LoadStatus.canLoading) { - body = Text( - trans("release to load more")); - } else { body = - Text(trans("No more products")); + Text(trans("Load Failed! Click retry!")); + } else if (mode == LoadStatus.canLoading) { + body = Text(trans("release to load more")); + } else { + body = Text(trans("No more products")); } return Container( height: 55.0, @@ -198,30 +172,29 @@ class _NoticHomeWidgetState extends State { 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()), + child: + (products.length != null && products.isNotEmpty + ? StaggeredGridView.countBuilder( + crossAxisCount: 2, + scrollDirection: Axis.horizontal, + itemCount: products.length, + itemBuilder: + (BuildContext context, int index) { + return Container( + height: 250, + child: ProductItemContainer( + product: products[index], + onTap: _showProduct, + ), + ); + }, + staggeredTileBuilder: (int index) { + return StaggeredTile.fit(2); + }, + mainAxisSpacing: 4.0, + crossAxisSpacing: 4.0, + ) + : NoResultsForProductsWidget()), ), ) ], @@ -235,16 +208,15 @@ class _NoticHomeWidgetState extends State { } _onRefresh() async { - _products = []; - _page = 1; + _productLoaderController.clear(); _shouldStopRequests = false; - waitForNextRequest = false; - await _fetchMoreProducts(); + + await fetchProducts(); _refreshController.refreshCompleted(); } _onLoading() async { - await _fetchMoreProducts(); + await fetchProducts(); if (mounted) { setState(() {}); @@ -256,6 +228,20 @@ class _NoticHomeWidgetState extends State { } } - _showProduct(WSProduct.Product product) => + Future fetchProducts() async { + await _productLoaderController.loadProducts( + hasResults: (result) { + if (result == false) { + setState(() { + _shouldStopRequests = true; + }); + return false; + } + return true; + }, + didFinish: () => setState(() {})); + } + + _showProduct(ws_product.Product product) => Navigator.pushNamed(context, "/product-detail", arguments: product); } diff --git a/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart b/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart index 2dbf97b..a04798b 100644 --- a/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/notic_theme_widget.dart @@ -3,7 +3,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -17,6 +17,7 @@ import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart'; import 'package:flutter_app/resources/pages/account_detail.dart'; import 'package:flutter_app/resources/pages/account_landing.dart'; import 'package:flutter_app/resources/pages/cart.dart'; +import 'package:flutter_app/resources/pages/wishlist_page_widget.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'; @@ -68,7 +69,13 @@ class _NoticThemeWidgetState extends State { label: 'Search', ), BottomNavigationBarItem( - icon: Icon(Icons.shopping_cart), label: 'Cart'), + icon: Icon(Icons.favorite_border), + label: 'Favourites', + ), + BottomNavigationBarItem( + icon: Icon(Icons.shopping_cart), + label: 'Cart', + ), if (AppHelper.instance.appConfig.wpLoginEnabled == 1) BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Account') ], @@ -78,11 +85,15 @@ class _NoticThemeWidgetState extends State { _onTabTapped(int i) async { _currentIndex = i; - await _changeMainWidget(); + await _changeMainWidget(); setState(() {}); } _changeMainWidget() async { + if (_currentIndex == 2) { + activeWidget = WishListPageWidget(); + return; + } switch (_currentIndex) { case 0: { @@ -101,7 +112,11 @@ class _NoticThemeWidgetState extends State { } case 3: { - activeWidget = (await authCheck()) ? AccountDetailPage(showLeadingBackButton: false) : AccountLandingPage(showBackButton: false,); + activeWidget = (await authCheck()) + ? AccountDetailPage(showLeadingBackButton: false) + : AccountLandingPage( + showBackButton: false, + ); break; } } diff --git a/LabelStoreMax/lib/resources/widgets/safearea_widget.dart b/LabelStoreMax/lib/resources/widgets/safearea_widget.dart index 8c6801f..d85d549 100644 --- a/LabelStoreMax/lib/resources/widgets/safearea_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/safearea_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/resources/widgets/switch_address_tab.dart b/LabelStoreMax/lib/resources/widgets/switch_address_tab.dart index ba714df..585d859 100644 --- a/LabelStoreMax/lib/resources/widgets/switch_address_tab.dart +++ b/LabelStoreMax/lib/resources/widgets/switch_address_tab.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -40,7 +40,7 @@ class SwitchAddressTab extends StatelessWidget { child: Container( width: double.infinity, child: Text( - this.title, + title, style: Theme.of(context).textTheme.subtitle1.copyWith( color: isActive ? Colors.white : Colors.black, ), diff --git a/LabelStoreMax/lib/resources/widgets/text_row_widget.dart b/LabelStoreMax/lib/resources/widgets/text_row_widget.dart index ba8c047..82595f8 100644 --- a/LabelStoreMax/lib/resources/widgets/text_row_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/text_row_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -14,8 +14,7 @@ class TextRowWidget extends StatelessWidget { const TextRowWidget({Key key, @required this.title, @required this.text}) : super(key: key); - final String title; - final String text; + final String title, text; @override Widget build(BuildContext context) { diff --git a/LabelStoreMax/lib/resources/widgets/top_nav_widget.dart b/LabelStoreMax/lib/resources/widgets/top_nav_widget.dart index 66e499e..4fe7f0a 100644 --- a/LabelStoreMax/lib/resources/widgets/top_nav_widget.dart +++ b/LabelStoreMax/lib/resources/widgets/top_nav_widget.dart @@ -1,7 +1,7 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, WooSignal Ltd. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -14,7 +14,6 @@ import 'package:nylo_support/helpers/helper.dart'; class TopNavWidget extends StatelessWidget { const TopNavWidget({Key key, this.onPressBrowseCategories}) : super(key: key); - final Function() onPressBrowseCategories; @override diff --git a/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart b/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart index c61e2a8..0ac09c0 100644 --- a/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart +++ b/LabelStoreMax/lib/resources/widgets/woosignal_ui.dart @@ -1,14 +1,13 @@ // Label StoreMax // // Created by Anthony Gordon. -// 2021, WooSignal Ltd. All rights reserved. +// 2022, 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:auto_size_text/auto_size_text.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -20,7 +19,6 @@ 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/no_results_for_products_widget.dart'; -import 'package:flutter_app/resources/widgets/text_row_widget.dart'; import 'package:flutter_app/resources/widgets/top_nav_widget.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_swiper/flutter_swiper.dart'; @@ -79,13 +77,13 @@ class RefreshableScrollContainer extends StatelessWidget { controller: controller, onRefresh: onRefresh, onLoading: onLoading, - child: (products.length != null && products.length > 0 + child: (products.length != null && products.isNotEmpty ? StaggeredGridView.countBuilder( crossAxisCount: 2, itemCount: - (products.length + (bannerImages.length > 0 ? 2 : 0)), + ((products.length + 1) + (bannerImages.isNotEmpty ? 1 : 0)), itemBuilder: (BuildContext context, int index) { - if (bannerImages.length > 0 && index == 0) { + if (bannerImages.isNotEmpty && index == 0) { return Container( child: Swiper( itemBuilder: (BuildContext context, int index) { @@ -101,35 +99,39 @@ class RefreshableScrollContainer extends StatelessWidget { height: bannerHeight, ); } - if (bannerImages.length > 0 && index == 1 || - bannerImages.length == 0 && index == 0) { + if (bannerImages.isNotEmpty && index == 1 || + bannerImages.isEmpty && index == 0) { return TopNavWidget( onPressBrowseCategories: modalBottomSheetMenu, ); } int productIndex = - (index - (bannerImages.length > 0 ? 2 : 0)); + ((index - 1) - (bannerImages.isNotEmpty ? 1 : 0)); return Container( height: 200, child: ProductItemContainer( - index: productIndex, + // index: productIndex, product: products[productIndex], onTap: onTap, ), ); }, staggeredTileBuilder: (int index) { - if (index == 0) { - return new StaggeredTile.fit(2); + // When there's banners and we need to display the [TopNavWidget] widget + if (bannerImages.isNotEmpty && index == 1) { + return StaggeredTile.fit(2); } - if (bannerImages.length == 0) { - return new StaggeredTile.fit(1); + // When there's banners and we need to display the banner + if (bannerImages.isNotEmpty && index == 0) { + return StaggeredTile.fit(2); } - if (bannerImages.length > 0 && index == 0 || index == 1) { - return new StaggeredTile.fit(2); + // When there's no banners but we need to display the [TopNavWidget] widget + if (bannerImages.isEmpty && index == 0) { + return StaggeredTile.fit(2); } - return new StaggeredTile.fit(1); + // display products + return StaggeredTile.fit(1); }, mainAxisSpacing: 4.0, crossAxisSpacing: 4.0, @@ -138,76 +140,87 @@ class RefreshableScrollContainer extends StatelessWidget { ); } -Widget wsCheckoutRow(BuildContext context, - {heading: String, - Widget leadImage, - String leadTitle, - void Function() action, - bool showBorderBottom}) { - return Flexible( - child: InkWell( - child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - child: Text( - heading, - style: Theme.of(context) - .textTheme - .bodyText2 - .copyWith(fontSize: 16, fontWeight: FontWeight.bold), - ), - padding: EdgeInsets.only(bottom: 8), - ), - Flexible( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - leadImage, - Expanded( - child: Container( - child: Text( - leadTitle, - style: Theme.of(context).textTheme.subtitle1, - maxLines: 2, - overflow: TextOverflow.ellipsis, - softWrap: false, - ), - padding: EdgeInsets.only(left: 15), - margin: EdgeInsets.only(right: 10), - ), - ), - ], - ), +class CheckoutRowLine extends StatelessWidget { + const CheckoutRowLine( + {Key key, + @required this.heading, + @required this.leadImage, + @required this.leadTitle, + @required this.action, + this.showBorderBottom = true}) + : super(key: key); + + final String heading; + final String leadTitle; + final Widget leadImage; + final Function() action; + final bool showBorderBottom; + + @override + Widget build(BuildContext context) => Flexible( + child: InkWell( + child: Container( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + child: Text( + heading, + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 16, fontWeight: FontWeight.bold), ), - Icon(Icons.arrow_forward_ios), - ], - ), - ) - ], - ), - padding: EdgeInsets.all(8), - decoration: showBorderBottom == true - ? BoxDecoration( - border: Border( - bottom: BorderSide(color: Colors.black12, width: 1), + padding: EdgeInsets.only(bottom: 8), ), - ) - : BoxDecoration(), - ), - onTap: action, - borderRadius: BorderRadius.circular(8), - ), - flex: 3, - ); + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + leadImage, + Expanded( + child: Container( + child: Text( + leadTitle, + style: Theme.of(context).textTheme.subtitle1, + maxLines: 2, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + padding: EdgeInsets.only(left: 15), + margin: EdgeInsets.only(right: 10), + ), + ), + ], + ), + ), + Icon(Icons.arrow_forward_ios), + ], + ), + ) + ], + ), + padding: EdgeInsets.all(8), + decoration: showBorderBottom == true + ? BoxDecoration( + border: Border( + bottom: BorderSide(color: Colors.black12, width: 1), + ), + ) + : BoxDecoration(), + ), + onTap: action, + borderRadius: BorderRadius.circular(8), + ), + flex: 3, + ); } class TextEditingRow extends StatelessWidget { @@ -236,9 +249,10 @@ class TextEditingRow extends StatelessWidget { child: Padding( child: Text( heading, - style: Theme.of(context).textTheme.bodyText1.copyWith( - color: ThemeColor.get(context).primaryContent - ), + style: Theme.of(context) + .textTheme + .bodyText1 + .copyWith(color: ThemeColor.get(context).primaryContent), ), padding: EdgeInsets.only(bottom: 2), ), @@ -261,25 +275,30 @@ class TextEditingRow extends StatelessWidget { ); } -Widget widgetCheckoutMeta(BuildContext context, {String title, String amount}) { - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: Container( - child: Text(title, style: Theme.of(context).textTheme.bodyText2), - ), - flex: 3, - ), - Flexible( - child: Container( - child: Text(amount, style: Theme.of(context).textTheme.bodyText1), - ), - flex: 3, - ) - ], - ); +class CheckoutMetaLine extends StatelessWidget { + const CheckoutMetaLine({Key key, this.title, this.amount}) : super(key: key); + + final String title, amount; + + @override + Widget build(BuildContext context) => Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Container( + child: Text(title, style: Theme.of(context).textTheme.bodyText2), + ), + flex: 3, + ), + Flexible( + child: Container( + child: Text(amount, style: Theme.of(context).textTheme.bodyText1), + ), + flex: 3, + ) + ], + ); } List wsBoxShadow({double blurRadius}) => [ @@ -297,12 +316,10 @@ List wsBoxShadow({double blurRadius}) => [ class ProductItemContainer extends StatelessWidget { const ProductItemContainer({ Key key, - this.index, this.product, this.onTap, }) : super(key: key); - final int index; final Product product; final Function onTap; @@ -327,7 +344,7 @@ class ProductItemContainer extends StatelessWidget { width: double.infinity, ), CachedImageWidget( - image: (product.images.length > 0 + image: (product.images.isNotEmpty ? product.images.first.src : getEnv("PRODUCT_PLACEHOLDER_IMAGE")), fit: BoxFit.contain, @@ -376,9 +393,10 @@ class ProductItemContainer extends StatelessWidget { margin: const EdgeInsets.only(top: 2, bottom: 2), child: Text( product.name, - style: Theme.of(context).textTheme.bodyText2.copyWith( - fontSize: 15 - ), + style: Theme.of(context) + .textTheme + .bodyText2 + .copyWith(fontSize: 15), maxLines: 2, overflow: TextOverflow.ellipsis, ), @@ -441,7 +459,6 @@ class ProductItemContainer extends StatelessWidget { wsModalBottom(BuildContext context, {String title, Widget bodyWidget, Widget extraWidget}) { - showModalBottomSheet( context: context, backgroundColor: Colors.transparent, @@ -451,42 +468,43 @@ wsModalBottom(BuildContext context, height: double.infinity, width: double.infinity, color: Colors.transparent, - child: new Container( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: new BoxDecoration( - color: ThemeColor.get(context).background, - borderRadius: new BorderRadius.only( - topLeft: const Radius.circular(10.0), - topRight: const Radius.circular(10.0), + child: Container( + padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: ThemeColor.get(context).background, + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(10.0), + topRight: const Radius.circular(10.0), + ), + ), + child: Column( + children: [ + Padding( + padding: EdgeInsets.symmetric(vertical: 16), + child: Text( + title, + style: Theme.of(context).textTheme.headline4, + textAlign: TextAlign.left, + ), ), - ), - child: Column( - children: [ - Padding( - padding: EdgeInsets.symmetric(vertical: 16), - child: Text( - title, - style: Theme.of(context).textTheme.headline4, - textAlign: TextAlign.left, + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8), + width: double.infinity, + decoration: BoxDecoration( + boxShadow: + (Theme.of(context).brightness == Brightness.light) + ? wsBoxShadow() + : null, + color: ThemeColor.get(context).background, + borderRadius: BorderRadius.circular(8), ), + child: bodyWidget, ), - Expanded( - child: Container( - padding: - EdgeInsets.symmetric(horizontal: 16, vertical: 8), - width: double.infinity, - decoration: BoxDecoration( - boxShadow: - (Theme.of(context).brightness == Brightness.light) ? wsBoxShadow() : null, - color: ThemeColor.get(context).background, - borderRadius: BorderRadius.circular(8), - ), - child: bodyWidget, - ), - ), - extraWidget ?? null - ].where((t) => t != null).toList(), - ), + ), + extraWidget + ].where((t) => t != null).toList(), + ), ), ), ); @@ -494,128 +512,92 @@ wsModalBottom(BuildContext context, ); } -FutureBuilder getTotalWidget() => FutureBuilder( - future: Cart.getInstance.getTotal(withFormat: true), - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return AppLoaderWidget(); - default: - if (snapshot.hasError) - return Text(""); - else - return new Padding( - child: TextRowWidget( - title: trans("Total"), - text: snapshot.data, - ), - padding: EdgeInsets.only(bottom: 15, top: 15), - ); - } - }, - ); +class CheckoutTotal extends StatelessWidget { + const CheckoutTotal({Key key, this.title, this.taxRate}) : super(key: key); -FutureBuilder wsCheckoutTotalWidgetFB({String title, TaxRate taxRate}) { - return FutureBuilder( - future: - CheckoutSession.getInstance.total(withFormat: true, taxRate: taxRate), - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return AppLoaderWidget(); - default: - if (snapshot.hasError) - return Text(""); - else - return new Padding( - child: widgetCheckoutMeta(context, - title: title, amount: snapshot.data), - padding: EdgeInsets.only(bottom: 0, top: 15), - ); - } - }, - ); + final String title; + final TaxRate taxRate; + + @override + Widget build(BuildContext context) => FutureBuilder( + future: CheckoutSession.getInstance + .total(withFormat: true, taxRate: taxRate), + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return AppLoaderWidget(); + default: + if (snapshot.hasError) { + return Text(""); + } else { + return Padding( + child: CheckoutMetaLine(title: title, amount: snapshot.data), + padding: EdgeInsets.only(bottom: 0, top: 15), + ); + } + } + }, + ); } -FutureBuilder wsCheckoutTaxAmountWidgetFB({TaxRate taxRate}) { - return FutureBuilder( - future: Cart.getInstance.taxAmount(taxRate), - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return AppLoaderWidget(); - default: - if (snapshot.hasError) - return Text(""); - else - return (snapshot.data == "0" - ? Container() - : Padding( - child: widgetCheckoutMeta( - context, - title: trans("Tax"), - amount: formatStringCurrency(total: snapshot.data), - ), - padding: EdgeInsets.only(bottom: 0, top: 0), - )); - } - }, - ); +class CheckoutTaxTotal extends StatelessWidget { + const CheckoutTaxTotal({Key key, this.taxRate}) : super(key: key); + + final TaxRate taxRate; + + @override + Widget build(BuildContext context) => FutureBuilder( + future: Cart.getInstance.taxAmount(taxRate), + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return AppLoaderWidget(); + default: + if (snapshot.hasError) { + return Text(""); + } else { + return (snapshot.data == "0" + ? Container() + : Padding( + child: CheckoutMetaLine( + title: trans("Tax"), + amount: formatStringCurrency(total: snapshot.data), + ), + padding: EdgeInsets.only(bottom: 0, top: 0), + )); + } + } + }, + ); } -FutureBuilder wsCheckoutSubtotalWidgetFB({String title}) { - return FutureBuilder( - future: Cart.getInstance.getSubtotal(withFormat: true), - builder: (BuildContext context, AsyncSnapshot snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return AppLoaderWidget(); - default: - if (snapshot.hasError) - return Text(""); - else - return new Padding( - child: widgetCheckoutMeta( - context, - title: title, - amount: snapshot.data, - ), - padding: EdgeInsets.only(bottom: 0, top: 0), - ); - } - }, - ); -} +class CheckoutSubtotal extends StatelessWidget { + const CheckoutSubtotal({Key key, this.title}) : super(key: key); -FutureBuilder wsWidgetCartItemsFB( - {void Function() actionIncrementQuantity, - void Function() actionDecrementQuantity, - void Function() actionRemoveItem}) { - return FutureBuilder>( - future: Cart.getInstance.getCart(), - builder: - (BuildContext context, AsyncSnapshot> snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return AppLoaderWidget(); - default: - if (snapshot.hasError) - return Text(""); - else - return ListView.builder( - padding: const EdgeInsets.all(8), - itemCount: snapshot.data.length, - itemBuilder: (BuildContext context, int index) { - CartLineItem cartLineItem = snapshot.data[index]; - return CartItemContainer( - cartLineItem: cartLineItem, - actionIncrementQuantity: actionIncrementQuantity, - actionDecrementQuantity: actionDecrementQuantity, - actionRemoveItem: actionRemoveItem); - }); - } - }, - ); + final String title; + + @override + Widget build(BuildContext context) => FutureBuilder( + future: Cart.getInstance.getSubtotal(withFormat: true), + builder: (BuildContext context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return AppLoaderWidget(); + default: + if (snapshot.hasError) { + return Text(""); + } else { + return Padding( + child: CheckoutMetaLine( + title: title, + amount: snapshot.data, + ), + padding: EdgeInsets.only(bottom: 0, top: 0), + ); + } + } + }, + ); } class CartItemContainer extends StatelessWidget { @@ -721,15 +703,15 @@ class CartItemContainer extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( - icon: Icon(Icons.add_circle_outline), - onPressed: actionIncrementQuantity, + icon: Icon(Icons.remove_circle_outline), + onPressed: actionDecrementQuantity, highlightColor: Colors.transparent, ), Text(cartLineItem.quantity.toString(), style: Theme.of(context).textTheme.headline6), IconButton( - icon: Icon(Icons.remove_circle_outline), - onPressed: actionDecrementQuantity, + icon: Icon(Icons.add_circle_outline), + onPressed: actionIncrementQuantity, highlightColor: Colors.transparent, ), ], @@ -768,7 +750,7 @@ class StoreLogo extends StatelessWidget { Widget build(BuildContext context) => Container( decoration: BoxDecoration( color: showBgWhite ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(3)), + borderRadius: BorderRadius.circular(5)), child: CachedImageWidget( image: AppHelper.instance.appConfig.appLogo, height: height, diff --git a/LabelStoreMax/lib/routes/router.dart b/LabelStoreMax/lib/routes/router.dart index bd6f0a5..afb474c 100644 --- a/LabelStoreMax/lib/routes/router.dart +++ b/LabelStoreMax/lib/routes/router.dart @@ -13,12 +13,14 @@ import 'package:flutter_app/resources/pages/checkout_details.dart'; import 'package:flutter_app/resources/pages/checkout_payment_type.dart'; import 'package:flutter_app/resources/pages/checkout_shipping_type.dart'; import 'package:flutter_app/resources/pages/checkout_status.dart'; +import 'package:flutter_app/resources/pages/coupon_page.dart'; import 'package:flutter_app/resources/pages/customer_countries.dart'; import 'package:flutter_app/resources/pages/home.dart'; 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/pages/wishlist_page_widget.dart'; import 'package:flutter_app/resources/widgets/checkout_paypal.dart'; import 'package:nylo_support/router/router.dart'; import 'package:page_transition/page_transition.dart'; @@ -48,6 +50,9 @@ appRouter() => nyRoutes((router) { router.route("/product-images", (context) => ProductImageViewerPage(), transition: PageTransitionType.fade); + router.route("/wishlist", (context) => WishListPageWidget(), + transition: PageTransitionType.rightToLeftWithFade); + router.route( "/account-order-detail", (context) => AccountOrderDetailPage(), transition: PageTransitionType.rightToLeftWithFade); @@ -66,6 +71,9 @@ appRouter() => nyRoutes((router) { "/checkout-shipping-type", (context) => CheckoutShippingTypePage(), transition: PageTransitionType.bottomToTop); + router.route("/checkout-coupons", (context) => CouponPage(), + transition: PageTransitionType.bottomToTop); + router.route("/home-search", (context) => HomeSearchPage(), transition: PageTransitionType.bottomToTop); diff --git a/LabelStoreMax/pubspec.lock b/LabelStoreMax/pubspec.lock index 2f50631..ff9c09c 100644 --- a/LabelStoreMax/pubspec.lock +++ b/LabelStoreMax/pubspec.lock @@ -231,7 +231,7 @@ packages: source: hosted version: "5.0.2" flutter_launcher_icons: - dependency: transitive + dependency: "direct dev" description: name: flutter_launcher_icons url: "https://pub.dartlang.org" @@ -311,7 +311,7 @@ packages: name: flutter_stripe url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" flutter_styled_toast: dependency: "direct main" description: @@ -349,7 +349,7 @@ packages: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.14.3" + version: "1.1.0" glob: dependency: transitive description: @@ -363,7 +363,7 @@ packages: name: google_fonts url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" hexcolor: dependency: "direct main" description: @@ -419,7 +419,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.4.0" + lints: + dependency: "direct dev" + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" logger: dependency: transitive description: @@ -440,7 +447,7 @@ packages: name: math_expressions url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" meta: dependency: transitive description: @@ -461,7 +468,7 @@ packages: name: nylo_framework url: "https://pub.dartlang.org" source: hosted - version: "2.1.3" + version: "2.1.4" nylo_support: dependency: transitive description: @@ -725,21 +732,21 @@ packages: name: stripe_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" stripe_ios: dependency: transitive description: name: stripe_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" stripe_platform_interface: dependency: transitive description: name: stripe_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" synchronized: dependency: transitive description: @@ -907,7 +914,7 @@ packages: name: woosignal url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.3" wp_json_api: dependency: "direct main" description: diff --git a/LabelStoreMax/pubspec.yaml b/LabelStoreMax/pubspec.yaml index 6f6675a..1745117 100644 --- a/LabelStoreMax/pubspec.yaml +++ b/LabelStoreMax/pubspec.yaml @@ -1,7 +1,7 @@ # Official WooSignal App Template for WooCommerce # Label StoreMax -# Version: 5.5.2 +# Version: 5.6.0 # Author: Anthony Gordon # Homepage: https://woosignal.com # Documentation: https://woosignal.com/docs/app/label-storemax @@ -25,13 +25,13 @@ environment: sdk: ">=2.7.0 <3.0.0" dependencies: - google_fonts: ^2.1.0 + google_fonts: ^2.2.0 analyzer: ^1.5.0 intl: ^0.17.0 page_transition: ^2.0.4 - nylo_framework: ^2.1.3 - woosignal: ^3.0.1 - flutter_stripe: ^2.0.2 + nylo_framework: ^2.1.4 + woosignal: ^3.0.3 + flutter_stripe: ^2.1.0 wp_json_api: ^3.1.3 cached_network_image: ^3.2.0 package_info: ^2.0.2 @@ -46,7 +46,7 @@ dependencies: animate_do: ^2.0.0 bubble_tab_indicator: ^0.1.5 status_alert: ^0.1.3 - math_expressions: ^2.2.0 + math_expressions: ^2.3.0 validated: ^2.0.0 hexcolor: ^2.0.5 flutter_spinkit: ^5.1.0 @@ -65,14 +65,17 @@ dependencies: cupertino_icons: ^1.0.4 dev_dependencies: + flutter_launcher_icons: ^0.9.2 + lints: ^1.0.0 flutter_test: sdk: flutter # APP ICON flutter_icons: - android: "launcher_icon" + android: true ios: true image_path: "public/assets/app_icon/appicon.png" + remove_alpha_ios: true dependency_overrides: intl: ^0.17.0 diff --git a/README.md b/README.md index ae1a072..8f503ac 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ # WooCommerce App: Label StoreMax -### Label StoreMax - v5.5.2 +### Label StoreMax - v5.6.0 [Official WooSignal WooCommerce App](https://woosignal.com)