diff --git a/LabelStoreMax/.flutter-plugins-dependencies b/LabelStoreMax/.flutter-plugins-dependencies new file mode 100644 index 0000000..f74011f --- /dev/null +++ b/LabelStoreMax/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"device_info","dependencies":[]},{"name":"flutter_money_formatter","dependencies":[]},{"name":"flutter_web_browser","dependencies":[]},{"name":"fluttertoast","dependencies":[]},{"name":"package_info","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"sqflite","dependencies":[]},{"name":"woosignal_stripe","dependencies":[]}]} \ No newline at end of file diff --git a/LabelStoreMax/android/app/build.gradle b/LabelStoreMax/android/app/build.gradle index afc015b..f559b85 100644 --- a/LabelStoreMax/android/app/build.gradle +++ b/LabelStoreMax/android/app/build.gradle @@ -25,6 +25,12 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + android { compileSdkVersion 28 @@ -37,7 +43,6 @@ android { } defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.woosignal.label_storemax" minSdkVersion 28 targetSdkVersion 28 @@ -47,13 +52,20 @@ android { multiDexEnabled = true } - buildTypes { + signingConfigs { release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] } } + buildTypes { + release { + signingConfig signingConfigs.release + } + } + } flutter { diff --git a/LabelStoreMax/android/key.properties b/LabelStoreMax/android/key.properties new file mode 100644 index 0000000..9dea776 --- /dev/null +++ b/LabelStoreMax/android/key.properties @@ -0,0 +1,4 @@ +storePassword= +keyPassword= +keyAlias=key +storeFile=/key.jks> diff --git a/LabelStoreMax/ios/Flutter/Flutter.podspec b/LabelStoreMax/ios/Flutter/Flutter.podspec new file mode 100644 index 0000000..5ca3041 --- /dev/null +++ b/LabelStoreMax/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# NOTE: This podspec is NOT to be published. It is only used as a local source! +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'High-performance, high-fidelity mobile apps.' + s.description = <<-DESC +Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. + DESC + s.homepage = 'https://flutter.io' + s.license = { :type => 'MIT' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '8.0' + s.vendored_frameworks = 'Flutter.framework' +end diff --git a/LabelStoreMax/ios/Podfile b/LabelStoreMax/ios/Podfile new file mode 100644 index 0000000..b30a428 --- /dev/null +++ b/LabelStoreMax/ios/Podfile @@ -0,0 +1,90 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + generated_key_values = {} + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values +end + +target 'Runner' do + use_frameworks! + use_modular_headers! + + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end +end + +# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. +install! 'cocoapods', :disable_input_output_paths => true + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/LabelStoreMax/ios/Podfile.lock b/LabelStoreMax/ios/Podfile.lock new file mode 100644 index 0000000..6b4b762 --- /dev/null +++ b/LabelStoreMax/ios/Podfile.lock @@ -0,0 +1,95 @@ +PODS: + - device_info (0.0.1): + - Flutter + - Flutter (1.0.0) + - flutter_money_formatter (0.0.1): + - Flutter + - flutter_web_browser (0.11.0): + - Flutter + - fluttertoast (0.0.2): + - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - package_info (0.0.1): + - Flutter + - path_provider (0.0.1): + - Flutter + - shared_preferences (0.0.1): + - Flutter + - shared_preferences_macos (0.0.1): + - Flutter + - shared_preferences_web (0.0.1): + - Flutter + - sqflite (0.0.1): + - Flutter + - FMDB (~> 2.7.2) + - Stripe (19.0.1) + - woosignal_stripe (0.0.4): + - Flutter + - Stripe (= 19.0.1) + +DEPENDENCIES: + - device_info (from `.symlinks/plugins/device_info/ios`) + - Flutter (from `Flutter`) + - flutter_money_formatter (from `.symlinks/plugins/flutter_money_formatter/ios`) + - flutter_web_browser (from `.symlinks/plugins/flutter_web_browser/ios`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - package_info (from `.symlinks/plugins/package_info/ios`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) + - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - woosignal_stripe (from `.symlinks/plugins/woosignal_stripe/ios`) + +SPEC REPOS: + trunk: + - FMDB + - Stripe + +EXTERNAL SOURCES: + device_info: + :path: ".symlinks/plugins/device_info/ios" + Flutter: + :path: Flutter + flutter_money_formatter: + :path: ".symlinks/plugins/flutter_money_formatter/ios" + flutter_web_browser: + :path: ".symlinks/plugins/flutter_web_browser/ios" + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" + package_info: + :path: ".symlinks/plugins/package_info/ios" + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" + shared_preferences_macos: + :path: ".symlinks/plugins/shared_preferences_macos/ios" + shared_preferences_web: + :path: ".symlinks/plugins/shared_preferences_web/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + woosignal_stripe: + :path: ".symlinks/plugins/woosignal_stripe/ios" + +SPEC CHECKSUMS: + device_info: cbf09d2ec12aa7110e0b09fabe54b5bd6c8efe74 + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + flutter_money_formatter: d0d18ddc5be333fad8d09964d741b59fa11a91dc + flutter_web_browser: bdea232160dec44dec86540bee05168cc844ef7c + fluttertoast: b644586ef3b16f67fae9a1f8754cef6b2d6b634b + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + package_info: 48b108e75b8802c2d5e126f208ef540561c98aef + path_provider: f96fff6166a8867510d2c25fdcc346327cc4b259 + shared_preferences: 430726339841afefe5142b9c1f50cb6bd7793e01 + shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 + shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 + sqflite: ff1d9da63c06588cc8d1faf7256d741f16989d5a + Stripe: 03313f9520a0786e2c00d9a7a2672c11e08821af + woosignal_stripe: 55c9a08f483aae42ca1c9769f5c474802b865f17 + +PODFILE CHECKSUM: 1b66dae606f75376c5f2135a8290850eeb09ae83 + +COCOAPODS: 1.9.1 diff --git a/LabelStoreMax/lang/en.json b/LabelStoreMax/lang/en.json index ddb4a1e..d2dc0a2 100644 --- a/LabelStoreMax/lang/en.json +++ b/LabelStoreMax/lang/en.json @@ -90,5 +90,7 @@ "About Us": "About Us", "Something went wrong": "Something went wrong", "Product variation does not exist": "Product variation does not exist", - "This variation is unavailable": "This variation is unavailable" + "This variation is unavailable": "This variation is unavailable", + "Sorry, something went wrong": "Sorry, something went wrong", + "Back": "Back" } \ No newline at end of file diff --git a/LabelStoreMax/lib/app_country_options.dart b/LabelStoreMax/lib/app_country_options.dart index a953468..4d3c54b 100644 --- a/LabelStoreMax/lib/app_country_options.dart +++ b/LabelStoreMax/lib/app_country_options.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/app_payment_methods.dart b/LabelStoreMax/lib/app_payment_methods.dart new file mode 100644 index 0000000..3113994 --- /dev/null +++ b/LabelStoreMax/lib/app_payment_methods.dart @@ -0,0 +1,29 @@ +import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/payment_type.dart'; +import 'package:label_storemax/providers/stripe_pay.dart'; + +// Payment methods available for uses in the app +// To use use a payment method, include the PaymentType "name" in the app_payment_methods variable in #labelconfig.dart + +List arrPaymentMethods = [ + addPayment( + PaymentType( + id: 1, + name: "Stripe", + desc: "Debit or Credit Card", + assetImage: "dark_powered_by_stripe.png", + pay: stripePay,), + ), + + // e.g. add more here + +// addPayment( +// PaymentType( +// id: 2, +// name: "MyNewPaymentMethod", +// desc: "Debit or Credit Card", +// assetImage: "add icon image to assets/images/myimage.png", +// pay: stripePay +// ), +// ), +]; diff --git a/LabelStoreMax/lib/app_tax_states_options.dart b/LabelStoreMax/lib/app_tax_states_options.dart deleted file mode 100644 index 36eb7b0..0000000 --- a/LabelStoreMax/lib/app_tax_states_options.dart +++ /dev/null @@ -1,72 +0,0 @@ -// Label StoreMAX -// -// Created by Anthony Gordon. -// Copyright © 2019 WooSignal. 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. - -var appCountryOptions = [ - {"code": "*", "title": "Match all states"}, - {"code": "AL", "title": "Alabama"}, - {"code": "AK", "title": "Alaska"}, - {"code": "AS", "title": "American Samoa"}, - {"code": "AZ", "title": "Arizona"}, - {"code": "AR", "title": "Arkansas"}, - {"code": "CA", "title": "California"}, - {"code": "CO", "title": "Colorado"}, - {"code": "CT", "title": "Connecticut"}, - {"code": "DE", "title": "Delaware"}, - {"code": "DC", "title": "District Of Columbia"}, - {"code": "FM", "title": "Federated States Of Micronesia"}, - {"code": "FL", "title": "Florida"}, - {"code": "GA", "title": "Georgia"}, - {"code": "GU", "title": "Guam"}, - {"code": "HI", "title": "Hawaii"}, - {"code": "ID", "title": "Idaho"}, - {"code": "IL", "title": "Illinois"}, - {"code": "IN", "title": "Indiana"}, - {"code": "IA", "title": "Iowa"}, - {"code": "KS", "title": "Kansas"}, - {"code": "KY", "title": "Kentucky"}, - {"code": "LA", "title": "Louisiana"}, - {"code": "ME", "title": "Maine"}, - {"code": "MH", "title": "Marshall Islands"}, - {"code": "MD", "title": "Maryland"}, - {"code": "MA", "title": "Massachusetts"}, - {"code": "MI", "title": "Michigan"}, - {"code": "MN", "title": "Minnesota"}, - {"code": "MS", "title": "Mississippi"}, - {"code": "MO", "title": "Missouri"}, - {"code": "MT", "title": "Montana"}, - {"code": "NE", "title": "Nebraska"}, - {"code": "NV", "title": "Nevada"}, - {"code": "NH", "title": "New Hampshire"}, - {"code": "NJ", "title": "New Jersey"}, - {"code": "NM", "title": "New Mexico"}, - {"code": "NY", "title": "New York"}, - {"code": "NC", "title": "North Carolina"}, - {"code": "ND", "title": "North Dakota"}, - {"code": "MP", "title": "Northern Mariana Islands"}, - {"code": "OH", "title": "Ohio"}, - {"code": "OK", "title": "Oklahoma"}, - {"code": "OR", "title": "Oregon"}, - {"code": "PW", "title": "Palau"}, - {"code": "PA", "title": "Pennsylvania"}, - {"code": "PR", "title": "Puerto Rico"}, - {"code": "RI", "title": "Rhode Island"}, - {"code": "SC", "title": "South Carolina"}, - {"code": "SD", "title": "South Dakota"}, - {"code": "TN", "title": "Tennessee"}, - {"code": "TX", "title": "Texas"}, - {"code": "UT", "title": "Utah"}, - {"code": "VT", "title": "Vermont"}, - {"code": "VI", "title": "Virgin Islands"}, - {"code": "VA", "title": "Virginia"}, - {"code": "WA", "title": "Washington"}, - {"code": "WV", "title": "West Virginia"}, - {"code": "WI", "title": "Wisconsin"}, - {"code": "WY", "title": "Wyoming"} -]; diff --git a/LabelStoreMax/lib/helpers/app_localizations.dart b/LabelStoreMax/lib/helpers/app_localizations.dart index c320ca5..44c8ce3 100644 --- a/LabelStoreMax/lib/helpers/app_localizations.dart +++ b/LabelStoreMax/lib/helpers/app_localizations.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -14,6 +14,8 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import '../labelconfig.dart'; + class AppLocalizations { final Locale locale; @@ -48,7 +50,8 @@ class _AppLocalizationsDelegate const _AppLocalizationsDelegate(); @override - bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode); + bool isSupported(Locale locale) => + app_locales_supported.contains(locale.languageCode); @override bool shouldReload(_AppLocalizationsDelegate old) => false; diff --git a/LabelStoreMax/lib/helpers/app_themes.dart b/LabelStoreMax/lib/helpers/app_themes.dart index 5b0e78d..9f251ca 100644 --- a/LabelStoreMax/lib/helpers/app_themes.dart +++ b/LabelStoreMax/lib/helpers/app_themes.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software diff --git a/LabelStoreMax/lib/helpers/data/order_wc.dart b/LabelStoreMax/lib/helpers/data/order_wc.dart new file mode 100644 index 0000000..d8e5c2b --- /dev/null +++ b/LabelStoreMax/lib/helpers/data/order_wc.dart @@ -0,0 +1,100 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:io'; + +import 'package:label_storemax/labelconfig.dart'; +import 'package:label_storemax/models/billing_details.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:woosignal/models/payload/order_wc.dart'; +import 'package:woosignal/models/response/tax_rate.dart'; + +Future buildOrderWC({TaxRate taxRate}) async { + OrderWC orderWC = OrderWC(); + + String paymentMethodName = CheckoutSession.getInstance.paymentType.name ?? ""; + + orderWC.paymentMethod = Platform.isAndroid + ? "$paymentMethodName - Android App" + : "$paymentMethodName - IOS App"; + + orderWC.paymentMethodTitle = paymentMethodName.toLowerCase(); + + orderWC.setPaid = true; + orderWC.status = "pending"; + orderWC.currency = app_currency_iso.toUpperCase(); + + List lineItems = []; + List cartItems = await Cart.getInstance.getCart(); + cartItems.forEach((cartItem) { + LineItems tmpLineItem = LineItems(); + tmpLineItem.quantity = cartItem.quantity; + tmpLineItem.name = cartItem.name; + tmpLineItem.productId = cartItem.productId; + if (cartItem.variationId != null && cartItem.variationId != 0) { + tmpLineItem.variationId = cartItem.variationId; + } + + tmpLineItem.total = cartItem.total; + tmpLineItem.subtotal = cartItem.subtotal; + + lineItems.add(tmpLineItem); + }); + + orderWC.lineItems = lineItems; + + BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails; + + Billing billing = Billing(); + billing.firstName = billingDetails.billingAddress.firstName; + billing.lastName = billingDetails.billingAddress.lastName; + billing.address1 = billingDetails.billingAddress.addressLine; + billing.city = billingDetails.billingAddress.city; + billing.postcode = billingDetails.billingAddress.postalCode; + billing.country = billingDetails.billingAddress.country; + billing.email = billingDetails.billingAddress.emailAddress; + + orderWC.billing = billing; + + Shipping shipping = Shipping(); + shipping.firstName = billingDetails.shippingAddress.firstName; + shipping.lastName = billingDetails.shippingAddress.lastName; + shipping.address1 = billingDetails.shippingAddress.addressLine; + shipping.city = billingDetails.shippingAddress.city; + shipping.postcode = billingDetails.shippingAddress.postalCode; + shipping.country = billingDetails.shippingAddress.country; + + orderWC.shipping = shipping; + + orderWC.shippingLines = []; + Map shippingLineFeeObj = + CheckoutSession.getInstance.shippingType.toShippingLineFee(); + if (shippingLineFeeObj != null) { + ShippingLines shippingLine = ShippingLines(); + shippingLine.methodId = shippingLineFeeObj['method_id']; + shippingLine.methodTitle = shippingLineFeeObj['method_title']; + shippingLine.total = shippingLineFeeObj['total']; + orderWC.shippingLines.add(shippingLine); + } + + if (taxRate != null) { + orderWC.feeLines = []; + FeeLines feeLines = FeeLines(); + feeLines.name = taxRate.name; + feeLines.total = await Cart.getInstance.taxAmount(taxRate); + feeLines.taxClass = ""; + feeLines.taxStatus = "taxable"; + orderWC.feeLines.add(feeLines); + } + + return orderWC; +} diff --git a/LabelStoreMax/lib/helpers/shared_pref.dart b/LabelStoreMax/lib/helpers/shared_pref.dart new file mode 100644 index 0000000..f3a0cb2 --- /dev/null +++ b/LabelStoreMax/lib/helpers/shared_pref.dart @@ -0,0 +1,28 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:shared_preferences/shared_preferences.dart'; + +class SharedPref { + read(String key) async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString(key); + } + + save(String key, value) async { + final prefs = await SharedPreferences.getInstance(); + prefs.setString(key, value); + } + + remove(String key) async { + final prefs = await SharedPreferences.getInstance(); + prefs.remove(key); + } +} diff --git a/LabelStoreMax/lib/helpers/tools.dart b/LabelStoreMax/lib/helpers/tools.dart index 43a1392..4c3d86d 100644 --- a/LabelStoreMax/lib/helpers/tools.dart +++ b/LabelStoreMax/lib/helpers/tools.dart @@ -1,50 +1,42 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. 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:label_storemax/app_payment_methods.dart'; import 'package:label_storemax/helpers/app_localizations.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:label_storemax/labelconfig.dart'; import 'package:edge_alert/edge_alert.dart'; -import 'package:flutter_spinkit/flutter_spinkit.dart'; -import 'package:shared_preferences/shared_preferences.dart'; +import 'package:label_storemax/models/billing_details.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/models/payment_type.dart'; import 'package:html/parser.dart'; import 'package:flutter_web_browser/flutter_web_browser.dart'; -import 'dart:convert'; import 'package:flutter_money_formatter/flutter_money_formatter.dart'; -import 'package:woosignal/models/response/shipping_method.dart'; +import 'package:status_alert/status_alert.dart'; import 'package:woosignal/models/response/tax_rate.dart'; +import 'package:woosignal/woosignal.dart'; -// CONFIG FOR WOOSIGNAL API -var wsConfig = {"appKey": app_key, "debugMode": app_debug}; - -// MARK: PaymentMethodType -class PaymentType { - int id; - String name; - String assetImage; - - PaymentType({this.id, this.name, this.assetImage}); +appWooSignal(Function(WooSignal) api) async { + WooSignal wooSignal = await WooSignal.getInstance( + config: {"appKey": app_key, "debugMode": app_debug}); + return await api(wooSignal); } -List arrPaymentMethods = [ - (paymentMethods.contains("Stripe") - ? (PaymentType( - id: 1, - name: "Debit or Credit Card", - assetImage: "dark_powered_by_stripe.png")) - : null) -]; - List getPaymentTypes() { - return arrPaymentMethods; + return arrPaymentMethods.where((v) => v != null).toList(); +} + +PaymentType addPayment(PaymentType paymentType) { + return app_payment_methods.contains(paymentType.name) ? paymentType : null; } class HexColor extends Color { @@ -65,29 +57,12 @@ String truncateWithEllipsis(int cutoff, String myString) { : '${myString.substring(0, cutoff)}...'; } -class TextFieldMaker extends TextField { - static TextField makeWith(labelTitle) { - return TextField( - decoration: InputDecoration( - labelText: labelTitle, - labelStyle: TextStyle( - fontFamily: 'Overpass', - fontWeight: FontWeight.bold, - color: Colors.grey), - focusedBorder: UnderlineInputBorder( - borderSide: BorderSide(color: Colors.green))), - keyboardAppearance: Brightness.light, - keyboardType: TextInputType.emailAddress, - ); - } -} - void showToastWith({String message, String statusType}) { Fluttertoast.showToast( msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.CENTER, - timeInSecForIos: 3, + timeInSecForIosWeb: 3, backgroundColor: (statusType == "error" ? HexColor("#b5123a") : Colors.grey), textColor: (statusType == "error" ? Colors.white : Colors.black), @@ -98,26 +73,15 @@ void showToastNetworkError() { showToastWith(message: "Oops, something went wrong"); } -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); - 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); -} - -Widget showAppLoader() { - return SpinKitDoubleBounce(color: HexColor("#393318")); -} - -Future delayFunction(void Function() action) { - return Future.delayed(const Duration(milliseconds: 300), action); +showStatusAlert(context, + {@required String title, String subtitle, IconData icon, int duration}) { + StatusAlert.show( + context, + duration: Duration(seconds: duration ?? 2), + title: title, + subtitle: subtitle, + configuration: IconConfiguration(icon: icon ?? Icons.done, size: 50), + ); } class PaymentMethodType { @@ -176,218 +140,19 @@ void showEdgeAlertWith(context, } } -void errorWithNetworkDefault(BuildContext context) { - showEdgeAlertWith(context, - title: trans(context, "Oops"), - desc: trans(context, "Something went wrong"), - style: EdgeAlertStyle.DANGER); -} - String parseHtmlString(String htmlString) { var document = parse(htmlString); String parsedString = parse(document.body.text).documentElement.text; return parsedString; } -class CartLineItem { - String name; - int productId; - int variationId; - int quantity; - bool isManagedStock; - int stockQuantity; - String shippingClassId; - String taxStatus; - String taxClass; - bool shippingIsTaxable; - String subtotal; - String total; - String imageSrc; - String variationOptions; - String stockStatus; - Object metaData = {}; - - CartLineItem( - {this.name, - this.productId, - this.variationId, - this.isManagedStock, - this.stockQuantity, - this.quantity, - this.stockStatus, - this.shippingClassId, - this.taxStatus, - this.taxClass, - this.shippingIsTaxable, - this.variationOptions, - this.imageSrc, - this.subtotal, - this.total, - this.metaData}); - - CartLineItem.fromJson(Map json) - : name = json['name'], - productId = json['product_id'], - variationId = json['variation_id'], - quantity = json['quantity'], - shippingClassId = json['shipping_class_id'].toString(), - taxStatus = json['tax_status'], - stockQuantity = json['stock_quantity'], - isManagedStock = json['is_managed_stock'], - shippingIsTaxable = json['shipping_is_taxable'], - subtotal = json['subtotal'], - total = json['total'], - taxClass = json['tax_class'], - stockStatus = json['stock_status'], - imageSrc = json['image_src'], - variationOptions = json['variation_options'], - metaData = json['metaData']; - - Map toJson() => { - 'name': name, - 'product_id': productId, - 'variation_id': variationId, - 'quantity': quantity, - 'shipping_class_id': shippingClassId, - 'tax_status': taxStatus, - 'tax_class': taxClass, - 'stock_status': stockStatus, - 'is_managed_stock': isManagedStock, - 'stock_quantity': stockQuantity, - 'shipping_is_taxable': shippingIsTaxable, - 'image_src': imageSrc, - 'variation_options': variationOptions, - 'subtotal': subtotal, - 'total': total, - 'meta_data': metaData, - }; -} - -class SharedPref { - read(String key) async { - final prefs = await SharedPreferences.getInstance(); - return prefs.getString(key); - } - - save(String key, value) async { - final prefs = await SharedPreferences.getInstance(); - prefs.setString(key, value); - } - - remove(String key) async { - final prefs = await SharedPreferences.getInstance(); - prefs.remove(key); - } -} - -class CustomerAddress { - String firstName; - String lastName; - String addressLine; - String city; - String postalCode; - String country; - String emailAddress; - - CustomerAddress( - {this.firstName, - this.lastName, - this.addressLine, - this.city, - this.postalCode, - this.country, - this.emailAddress}); - - void initAddress() { - firstName = ""; - lastName = ""; - addressLine = ""; - city = ""; - postalCode = ""; - country = ""; - emailAddress = ""; - } - - bool hasMissingFields() { - return (this.firstName.isEmpty || - this.lastName.isEmpty || - this.addressLine.isEmpty || - this.city.isEmpty || - this.postalCode.isEmpty); - } - - String addressFull() { - List tmpArrAddress = new List(); - if (addressLine != "") { - tmpArrAddress.add(addressLine); - } - if (city != "") { - tmpArrAddress.add(city); - } - if (postalCode != "") { - tmpArrAddress.add(postalCode); - } - if (country != "") { - tmpArrAddress.add(country); - } - return tmpArrAddress.join(", "); - } - - String nameFull() { - List tmpArrName = new List(); - if (firstName != "") { - tmpArrName.add(firstName); - } - if (lastName != "") { - tmpArrName.add(lastName); - } - return tmpArrName.join(", "); - } - - CustomerAddress.fromJson(Map json) { - firstName = json['first_name']; - lastName = json['last_name']; - addressLine = json['address_line']; - city = json['city']; - postalCode = json['postal_code']; - country = json['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['country'] = this.country; - data['email_address'] = this.emailAddress; - return data; - } -} - -class BillingDetails { - CustomerAddress billingAddress; - CustomerAddress shippingAddress; - bool rememberDetails; - - void initSession() { - billingAddress = CustomerAddress(); - shippingAddress = CustomerAddress(); - } -} - -class PaymentDetails { - String method; -} - String formatDoubleCurrency({double total}) { FlutterMoneyFormatter fmf = FlutterMoneyFormatter( - amount: total, - settings: MoneyFormatterSettings( - symbol: app_currency_symbol, - )); + amount: total, + settings: MoneyFormatterSettings( + symbol: app_currency_symbol, + ), + ); return fmf.output.symbolOnLeft; } @@ -399,338 +164,15 @@ String formatStringCurrency({String total}) { tmpVal = double.parse(total); } FlutterMoneyFormatter fmf = FlutterMoneyFormatter( - amount: tmpVal, - settings: MoneyFormatterSettings( - symbol: app_currency_symbol, - )); + amount: tmpVal, + settings: MoneyFormatterSettings( + symbol: app_currency_symbol, + ), + ); return fmf.output.symbolOnLeft; } -class ShippingType { - String methodId; - String cost; - dynamic object; - - ShippingType({this.methodId, this.object, this.cost}); - - Map toJson() => - {'methodId': methodId, 'object': object, 'cost': cost}; - - String getTotal({bool withFormatting}) { - if (this.methodId != null && this.object != null) { - switch (this.methodId) { - case "flat_rate": - FlatRate flatRate = (this.object as FlatRate); - return (withFormatting == true - ? formatStringCurrency(total: cost) - : flatRate.cost); - case "free_shipping": - FreeShipping freeShipping = (this.object as FreeShipping); - return (withFormatting == true - ? formatStringCurrency(total: cost) - : freeShipping.cost); - case "local_pickup": - LocalPickup localPickup = (this.object as LocalPickup); - return (withFormatting == true - ? formatStringCurrency(total: cost) - : localPickup.cost); - default: - return "0"; - break; - } - } - return "0"; - } - - String getTitle() { - if (this.methodId != null && this.object != null) { - switch (this.methodId) { - case "flat_rate": - FlatRate flatRate = (this.object as FlatRate); - return flatRate.title; - case "free_shipping": - FreeShipping freeShipping = (this.object as FreeShipping); - return freeShipping.title; - case "local_pickup": - LocalPickup localPickup = (this.object as LocalPickup); - return localPickup.title; - default: - return ""; - break; - } - } - return ""; - } - - Map toShippingLineFee() { - if (this.methodId != null && this.object != null) { - Map tmpShippingLinesObj = {}; - - switch (this.methodId) { - case "flat_rate": - FlatRate flatRate = (this.object as FlatRate); - tmpShippingLinesObj["method_title"] = flatRate.title; - tmpShippingLinesObj["method_id"] = flatRate.methodId; - tmpShippingLinesObj["total"] = this.cost; - break; - case "free_shipping": - FreeShipping freeShipping = (this.object as FreeShipping); - tmpShippingLinesObj["method_title"] = freeShipping.title; - tmpShippingLinesObj["method_id"] = freeShipping.methodId; - tmpShippingLinesObj["total"] = this.cost; - break; - case "local_pickup": - LocalPickup localPickup = (this.object as LocalPickup); - tmpShippingLinesObj["method_title"] = localPickup.title; - tmpShippingLinesObj["method_id"] = localPickup.methodId; - tmpShippingLinesObj["total"] = this.cost; - break; - default: - return null; - break; - } - return tmpShippingLinesObj; - } - - return null; - } -} - -class CheckoutSession { - String sfKeyCheckout = "CS_BILLING_DETAILS"; - CheckoutSession._privateConstructor(); - static final CheckoutSession getInstance = - CheckoutSession._privateConstructor(); - - BillingDetails billingDetails; - ShippingType shippingType; - PaymentType paymentType; - - void initSession() { - billingDetails = BillingDetails(); - shippingType = null; - } - - void saveBillingAddress() { - SharedPref sharedPref = SharedPref(); - CustomerAddress customerAddress = - CheckoutSession.getInstance.billingDetails.billingAddress; - - String billingAddress = jsonEncode(customerAddress.toJson()); - sharedPref.save(sfKeyCheckout, billingAddress); - } - - Future getBillingAddress() async { - SharedPref sharedPref = SharedPref(); - - String strCheckoutDetails = await sharedPref.read(sfKeyCheckout); - - if (strCheckoutDetails != null && strCheckoutDetails != "") { - return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails)); - } - return null; - } - - void clearBillingAddress() { - SharedPref sharedPref = SharedPref(); - sharedPref.remove(sfKeyCheckout); - } - - Future total({bool withFormat, TaxRate taxRate}) async { - double totalCart = double.parse(await Cart.getInstance.getTotal()); - double totalShipping = 0; - if (shippingType != null && shippingType.object != null) { - switch (shippingType.methodId) { - case "flat_rate": - totalShipping = double.parse(shippingType.cost); - break; - case "free_shipping": - totalShipping = double.parse(shippingType.cost); - break; - case "local_pickup": - totalShipping = double.parse(shippingType.cost); - break; - default: - break; - } - } - - double total = totalCart + totalShipping; - - if (taxRate != null) { - String taxAmount = await Cart.getInstance.taxAmount(taxRate); - total += double.parse(taxAmount); - } - - if (withFormat != null && withFormat == true) { - return formatDoubleCurrency(total: total); - } - return total.toString(); - } -} - -class Cart { - String _keyCart = "CART_SESSION"; - - Cart._privateConstructor(); - static final Cart getInstance = Cart._privateConstructor(); - - Future> getCart() async { - List cartLineItems = []; - SharedPref sharedPref = SharedPref(); - String currentCartArrJSON = (await sharedPref.read(_keyCart) as String); - if (currentCartArrJSON == null) { - cartLineItems = List(); - } else { - cartLineItems = (jsonDecode(currentCartArrJSON) as List) - .map((i) => CartLineItem.fromJson(i)) - .toList(); - } - return cartLineItems; - } - - void addToCart({CartLineItem cartLineItem}) async { - List cartLineItems = await getCart(); - var firstCartItem = cartLineItems.firstWhere( - (i) => - i.productId == cartLineItem.productId || - i.productId == cartLineItem.productId && - i.variationId == cartLineItem.variationId, orElse: () { - return null; - }); - if (firstCartItem != null) { - return; - } - cartLineItems.add(cartLineItem); - - saveCartToPref(cartLineItems: cartLineItems); - } - - Future getTotal({bool withFormat}) async { - List cartLineItems = await getCart(); - double total = 0; - cartLineItems.forEach((cartItem) { - total += (double.parse(cartItem.total) * cartItem.quantity); - }); - - if (withFormat != null && withFormat == true) { - return formatDoubleCurrency(total: total); - } - return total.toString(); - } - - Future getSubtotal({bool withFormat}) async { - List cartLineItems = await getCart(); - double subtotal = 0; - cartLineItems.forEach((cartItem) { - subtotal += (double.parse(cartItem.subtotal) * cartItem.quantity); - }); - if (withFormat != null && withFormat == true) { - return formatDoubleCurrency(total: subtotal); - } - return subtotal.toString(); - } - - void updateQuantity( - {CartLineItem cartLineItem, int incrementQuantity}) async { - List cartLineItems = await getCart(); - List tmpCartItem = new List(); - cartLineItems.forEach((cartItem) { - if (cartItem.variationId == cartLineItem.variationId && - cartItem.productId == cartLineItem.productId) { - if ((cartItem.quantity + incrementQuantity) > 0) { - cartItem.quantity += incrementQuantity; - } - } - tmpCartItem.add(cartItem); - }); - saveCartToPref(cartLineItems: tmpCartItem); - } - - Future cartShortDesc() async { - List cartLineItems = await getCart(); - var tmpShortItemDesc = []; - cartLineItems.forEach((cartItem) { - tmpShortItemDesc - .add(cartItem.quantity.toString() + " x | " + cartItem.name); - }); - return tmpShortItemDesc.join(","); - } - - void removeCartItemForIndex({int index}) async { - List cartLineItems = await getCart(); - cartLineItems.removeAt(index); - saveCartToPref(cartLineItems: cartLineItems); - } - - void clear() { - SharedPref sharedPref = SharedPref(); - List cartLineItems = new List(); - String jsonArrCartItems = - jsonEncode(cartLineItems.map((i) => i.toJson()).toList()); - sharedPref.save(_keyCart, jsonArrCartItems); - } - - void saveCartToPref({List cartLineItems}) { - SharedPref sharedPref = SharedPref(); - String jsonArrCartItems = - jsonEncode(cartLineItems.map((i) => i.toJson()).toList()); - sharedPref.save(_keyCart, jsonArrCartItems); - } - - Future taxAmount(TaxRate taxRate) async { - double subtotal = 0; - double shippingTotal = 0; - - List cartItems = await Cart.getInstance.getCart(); - if (cartItems.every((c) => c.taxStatus == 'none')) { - return "0"; - } - List taxableCartLines = - cartItems.where((c) => c.taxStatus == 'taxable').toList(); - double cartSubtotal = 0; - - if (taxableCartLines.length > 0) { - cartSubtotal = taxableCartLines - .map((m) => double.parse(m.subtotal)) - .reduce((a, b) => a + b); - } - - subtotal = cartSubtotal; - - ShippingType shippingType = CheckoutSession.getInstance.shippingType; - - if (shippingType != null) { - switch (shippingType.methodId) { - case "flat_rate": - FlatRate flatRate = (shippingType.object as FlatRate); - if (flatRate.taxable != null && flatRate.taxable) { - shippingTotal += double.parse(shippingType.cost); - } - break; - case "local_pickup": - LocalPickup localPickup = (shippingType.object as LocalPickup); - if (localPickup.taxable != null && localPickup.taxable) { - shippingTotal += double.parse(localPickup.cost); - } - break; - default: - break; - } - } - - double total = 0; - if (subtotal != 0) { - total += ((double.parse(taxRate.rate) * subtotal) / 100); - } - if (shippingTotal != 0) { - total += ((double.parse(taxRate.rate) * shippingTotal) / 100); - } - return (total).toString(); - } -} - -openBrowserTab({String url}) async { +openBrowserTab({@required String url}) async { await FlutterWebBrowser.openWebPage( url: url, androidToolbarColor: Colors.white70); } @@ -739,26 +181,21 @@ EdgeInsets safeAreaDefault() { return EdgeInsets.only(left: 16, right: 16, bottom: 8); } -class SlideRightRoute extends PageRouteBuilder { - final Widget widget; - SlideRightRoute({this.widget}) - : super(pageBuilder: (BuildContext context, Animation animation, - Animation secondaryAnimation) { - return widget; - }, transitionsBuilder: (BuildContext context, - Animation animation, - Animation secondaryAnimation, - Widget child) { - return new SlideTransition( - position: new Tween( - begin: const Offset(-1.0, 0.0), - end: Offset.zero, - ).animate(animation), - child: child, - ); - }); -} - String trans(BuildContext context, String key) { return AppLocalizations.of(context).trans(key); } + +bool isNumeric(String str) { + if (str == null) { + return false; + } + return double.tryParse(str) != null; +} + +checkout(TaxRate taxRate, Function(String total, BillingDetails billingDetails, Cart cart) completeCheckout) async { + String cartTotal = await CheckoutSession.getInstance + .total(withFormat: false, taxRate: taxRate); + BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails; + Cart cart = Cart.getInstance; + return await completeCheckout(cartTotal, billingDetails, cart); +} diff --git a/LabelStoreMax/lib/labelconfig.dart b/LabelStoreMax/lib/labelconfig.dart index 1792eb4..f70e5f8 100644 --- a/LabelStoreMax/lib/labelconfig.dart +++ b/LabelStoreMax/lib/labelconfig.dart @@ -3,7 +3,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -14,7 +14,7 @@ Developer Notes SUPPORT EMAIL - support@woosignal.com - VERSION - 1.0 + VERSION - 2.0 https://woosignal.com */ @@ -22,7 +22,8 @@ const app_name = "MyApp"; -const app_key = "your app key"; +const app_key = + "app_affb6434339b34443a297c2e40a3edab7102137e6d67de9abfe612b749bd"; const app_logo_url = "https://woosignal.com/images/120x120_woosignal.png"; @@ -31,7 +32,9 @@ const app_privacy_url = "https://yourdomain.com/privacy"; /**/ -const app_stripe_account = "your StripeAccount key"; // Your StripeAccount key from WooSignal +const app_stripe_account = + "acct_1DNNUgADlQ9NE89O"; // Your StripeAccount key from WooSignal + const app_stripe_live_mode = false; // SET true for live payments /**/ @@ -40,7 +43,7 @@ const app_currency_symbol = "\£"; const app_currency_iso = "gbp"; const app_locales_supported = ['en']; -const paymentMethods = ["Stripe"]; +const app_payment_methods = ["Stripe", "RazorPay"]; /**/ diff --git a/LabelStoreMax/lib/main.dart b/LabelStoreMax/lib/main.dart index 974e44c..91bec8a 100644 --- a/LabelStoreMax/lib/main.dart +++ b/LabelStoreMax/lib/main.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,6 +10,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:label_storemax/pages/error_page.dart'; +import 'package:woosignal/models/response/order.dart'; +import 'package:woosignal/models/response/product_category.dart'; +import 'package:woosignal/models/response/products.dart'; import 'labelconfig.dart'; import 'package:label_storemax/pages/checkout_details.dart'; import 'package:label_storemax/pages/home.dart'; @@ -32,7 +36,7 @@ import 'package:label_storemax/helpers/app_localizations.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - + await SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, ]); @@ -46,43 +50,106 @@ void main() async { routes: { '/home': (BuildContext context) => new HomePage(), '/cart': (BuildContext context) => new CartPage(), - '/browse-category': (BuildContext context) => new BrowseCategoryPage(), - '/product-search': (BuildContext context) => new BrowseSearchPage(), - '/product-detail': (BuildContext context) => new ProductDetailPage(), + '/error': (BuildContext context) => new ErrorPage(), '/checkout': (BuildContext context) => new CheckoutConfirmationPage(), - '/checkout-status': (BuildContext context) => new CheckoutStatusPage(), }, onGenerateRoute: (settings) { switch (settings.name) { + case '/browse-category': + if (settings.arguments != null) { + final ProductCategory category = + settings.arguments as ProductCategory; + return PageTransition( + child: BrowseCategoryPage(productCategory: category), + type: PageTransitionType.fade, + ); + } + return PageTransition( + child: ErrorPage(), + type: PageTransitionType.fade, + ); + + case '/product-search': + if (settings.arguments != null) { + final String search = settings.arguments as String; + return PageTransition( + child: BrowseSearchPage(search: search), + type: PageTransitionType.fade, + ); + } + return PageTransition( + child: ErrorPage(), + type: PageTransitionType.fade, + ); + + case '/product-detail': + if (settings.arguments != null) { + final Product product = settings.arguments as Product; + return PageTransition( + child: ProductDetailPage(product: product), + type: PageTransitionType.rightToLeftWithFade, + ); + } + return PageTransition( + child: ErrorPage(), + type: PageTransitionType.fade, + ); + + case '/checkout-status': + if (settings.arguments != null) { + final Order order = settings.arguments as Order; + return PageTransition( + child: CheckoutStatusPage(order: order), + type: PageTransitionType.rightToLeftWithFade, + ); + } + return PageTransition( + child: ErrorPage(), + type: PageTransitionType.fade, + ); + case '/home-menu': return PageTransition( - child: HomeMenuPage(), type: PageTransitionType.leftToRight); + child: HomeMenuPage(), + type: PageTransitionType.leftToRightWithFade, + ); + case '/checkout-details': return PageTransition( - child: CheckoutDetailsPage(), - type: PageTransitionType.downToUp); + child: CheckoutDetailsPage(), + type: PageTransitionType.downToUp, + ); + case '/about': return PageTransition( - child: AboutPage(), type: PageTransitionType.leftToRight); + child: AboutPage(), + type: PageTransitionType.leftToRightWithFade, + ); case '/checkout-payment-type': return PageTransition( - child: CheckoutPaymentTypePage(), - type: PageTransitionType.downToUp); + child: CheckoutPaymentTypePage(), + type: PageTransitionType.downToUp, + ); case '/checkout-shipping-type': return PageTransition( - child: CheckoutShippingTypePage(), - type: PageTransitionType.downToUp); + child: CheckoutShippingTypePage(), + type: PageTransitionType.downToUp, + ); case '/home-search': return PageTransition( - child: HomeSearchPage(), type: PageTransitionType.downToUp); + child: HomeSearchPage(), + type: PageTransitionType.downToUp, + ); default: return null; } }, - supportedLocales: [Locale('en')], + supportedLocales: [ + Locale('en'), + ], localizationsDelegates: [ AppLocalizations.delegate, GlobalWidgetsLocalizations.delegate, @@ -106,14 +173,15 @@ void main() async { ), ), appBarTheme: AppBarTheme( - color: Colors.white, - textTheme: textThemeAppBar(), - elevation: 0.0, - brightness: Brightness.light, - iconTheme: IconThemeData(color: Colors.black), - actionsIconTheme: IconThemeData( - color: Colors.black, - )), + color: Colors.white, + textTheme: textThemeAppBar(), + elevation: 0.0, + brightness: Brightness.light, + iconTheme: IconThemeData(color: Colors.black), + actionsIconTheme: IconThemeData( + color: Colors.black, + ), + ), accentColor: Colors.black, accentTextTheme: textThemeAccent(), textTheme: textThemeMain(), diff --git a/LabelStoreMax/lib/models/billing_details.dart b/LabelStoreMax/lib/models/billing_details.dart new file mode 100644 index 0000000..2640493 --- /dev/null +++ b/LabelStoreMax/lib/models/billing_details.dart @@ -0,0 +1,22 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:label_storemax/models/customer_address.dart'; + +class BillingDetails { + CustomerAddress billingAddress; + CustomerAddress shippingAddress; + bool rememberDetails; + + void initSession() { + billingAddress = CustomerAddress(); + shippingAddress = CustomerAddress(); + } +} diff --git a/LabelStoreMax/lib/models/cart.dart b/LabelStoreMax/lib/models/cart.dart new file mode 100644 index 0000000..f18389a --- /dev/null +++ b/LabelStoreMax/lib/models/cart.dart @@ -0,0 +1,181 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:convert'; + +import 'package:label_storemax/helpers/shared_pref.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/models/shipping_type.dart'; +import 'package:woosignal/models/response/shipping_method.dart'; +import 'package:woosignal/models/response/tax_rate.dart'; + +import '../helpers/tools.dart'; + +class Cart { + String _keyCart = "CART_SESSION"; + + Cart._privateConstructor(); + static final Cart getInstance = Cart._privateConstructor(); + + Future> getCart() async { + List cartLineItems = []; + SharedPref sharedPref = SharedPref(); + String currentCartArrJSON = (await sharedPref.read(_keyCart) as String); + if (currentCartArrJSON == null) { + cartLineItems = List(); + } else { + cartLineItems = (jsonDecode(currentCartArrJSON) as List) + .map((i) => CartLineItem.fromJson(i)) + .toList(); + } + return cartLineItems; + } + + void addToCart({CartLineItem cartLineItem}) async { + List cartLineItems = await getCart(); + var firstCartItem = cartLineItems.firstWhere( + (i) => + i.productId == cartLineItem.productId || + i.productId == cartLineItem.productId && + i.variationId == cartLineItem.variationId, orElse: () { + return null; + }); + if (firstCartItem != null) { + return; + } + cartLineItems.add(cartLineItem); + + saveCartToPref(cartLineItems: cartLineItems); + } + + Future getTotal({bool withFormat}) async { + List cartLineItems = await getCart(); + double total = 0; + cartLineItems.forEach((cartItem) { + total += (double.parse(cartItem.total) * cartItem.quantity); + }); + + if (withFormat != null && withFormat == true) { + return formatDoubleCurrency(total: total); + } + return total.toString(); + } + + Future getSubtotal({bool withFormat}) async { + List cartLineItems = await getCart(); + double subtotal = 0; + cartLineItems.forEach((cartItem) { + subtotal += (double.parse(cartItem.subtotal) * cartItem.quantity); + }); + if (withFormat != null && withFormat == true) { + return formatDoubleCurrency(total: subtotal); + } + return subtotal.toString(); + } + + void updateQuantity( + {CartLineItem cartLineItem, int incrementQuantity}) async { + List cartLineItems = await getCart(); + List tmpCartItem = new List(); + cartLineItems.forEach((cartItem) { + if (cartItem.variationId == cartLineItem.variationId && + cartItem.productId == cartLineItem.productId) { + if ((cartItem.quantity + incrementQuantity) > 0) { + cartItem.quantity += incrementQuantity; + } + } + tmpCartItem.add(cartItem); + }); + saveCartToPref(cartLineItems: tmpCartItem); + } + + Future cartShortDesc() async { + List cartLineItems = await getCart(); + var tmpShortItemDesc = []; + cartLineItems.forEach((cartItem) { + tmpShortItemDesc + .add(cartItem.quantity.toString() + " x | " + cartItem.name); + }); + return tmpShortItemDesc.join(","); + } + + void removeCartItemForIndex({int index}) async { + List cartLineItems = await getCart(); + cartLineItems.removeAt(index); + saveCartToPref(cartLineItems: cartLineItems); + } + + void clear() { + SharedPref sharedPref = SharedPref(); + List cartLineItems = new List(); + String jsonArrCartItems = + jsonEncode(cartLineItems.map((i) => i.toJson()).toList()); + sharedPref.save(_keyCart, jsonArrCartItems); + } + + void saveCartToPref({List cartLineItems}) { + SharedPref sharedPref = SharedPref(); + String jsonArrCartItems = + jsonEncode(cartLineItems.map((i) => i.toJson()).toList()); + sharedPref.save(_keyCart, jsonArrCartItems); + } + + Future taxAmount(TaxRate taxRate) async { + double subtotal = 0; + double shippingTotal = 0; + + List cartItems = await Cart.getInstance.getCart(); + if (cartItems.every((c) => c.taxStatus == 'none')) { + return "0"; + } + List taxableCartLines = + cartItems.where((c) => c.taxStatus == 'taxable').toList(); + double cartSubtotal = 0; + + if (taxableCartLines.length > 0) { + cartSubtotal = taxableCartLines + .map((m) => double.parse(m.subtotal)) + .reduce((a, b) => a + b); + } + + subtotal = cartSubtotal; + + ShippingType shippingType = CheckoutSession.getInstance.shippingType; + + if (shippingType != null) { + switch (shippingType.methodId) { + case "flat_rate": + FlatRate flatRate = (shippingType.object as FlatRate); + if (flatRate.taxable != null && flatRate.taxable) { + shippingTotal += double.parse(shippingType.cost); + } + break; + case "local_pickup": + LocalPickup localPickup = (shippingType.object as LocalPickup); + if (localPickup.taxable != null && localPickup.taxable) { + shippingTotal += double.parse(localPickup.cost); + } + break; + default: + break; + } + } + + double total = 0; + if (subtotal != 0) { + total += ((double.parse(taxRate.rate) * subtotal) / 100); + } + if (shippingTotal != 0) { + total += ((double.parse(taxRate.rate) * shippingTotal) / 100); + } + return (total).toString(); + } +} diff --git a/LabelStoreMax/lib/models/cart_line_item.dart b/LabelStoreMax/lib/models/cart_line_item.dart new file mode 100644 index 0000000..0cf6035 --- /dev/null +++ b/LabelStoreMax/lib/models/cart_line_item.dart @@ -0,0 +1,83 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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. + +class CartLineItem { + String name; + int productId; + int variationId; + int quantity; + bool isManagedStock; + int stockQuantity; + String shippingClassId; + String taxStatus; + String taxClass; + bool shippingIsTaxable; + String subtotal; + String total; + String imageSrc; + String variationOptions; + String stockStatus; + Object metaData = {}; + + CartLineItem( + {this.name, + this.productId, + this.variationId, + this.isManagedStock, + this.stockQuantity, + this.quantity, + this.stockStatus, + this.shippingClassId, + this.taxStatus, + this.taxClass, + this.shippingIsTaxable, + this.variationOptions, + this.imageSrc, + this.subtotal, + this.total, + this.metaData}); + + CartLineItem.fromJson(Map json) + : name = json['name'], + productId = json['product_id'], + variationId = json['variation_id'], + quantity = json['quantity'], + shippingClassId = json['shipping_class_id'].toString(), + taxStatus = json['tax_status'], + stockQuantity = json['stock_quantity'], + isManagedStock = json['is_managed_stock'], + shippingIsTaxable = json['shipping_is_taxable'], + subtotal = json['subtotal'], + total = json['total'], + taxClass = json['tax_class'], + stockStatus = json['stock_status'], + imageSrc = json['image_src'], + variationOptions = json['variation_options'], + metaData = json['metaData']; + + Map toJson() => { + 'name': name, + 'product_id': productId, + 'variation_id': variationId, + 'quantity': quantity, + 'shipping_class_id': shippingClassId, + 'tax_status': taxStatus, + 'tax_class': taxClass, + 'stock_status': stockStatus, + 'is_managed_stock': isManagedStock, + 'stock_quantity': stockQuantity, + 'shipping_is_taxable': shippingIsTaxable, + 'image_src': imageSrc, + 'variation_options': variationOptions, + 'subtotal': subtotal, + 'total': total, + 'meta_data': metaData, + }; +} diff --git a/LabelStoreMax/lib/models/checkout_session.dart b/LabelStoreMax/lib/models/checkout_session.dart new file mode 100644 index 0000000..5b30d10 --- /dev/null +++ b/LabelStoreMax/lib/models/checkout_session.dart @@ -0,0 +1,94 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:convert'; + +import 'package:label_storemax/helpers/shared_pref.dart'; +import 'package:label_storemax/models/billing_details.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/customer_address.dart'; +import 'package:label_storemax/models/payment_type.dart'; +import 'package:label_storemax/models/shipping_type.dart'; +import 'package:woosignal/models/response/tax_rate.dart'; + +import '../helpers/tools.dart'; + +class CheckoutSession { + String sfKeyCheckout = "CS_BILLING_DETAILS"; + CheckoutSession._privateConstructor(); + static final CheckoutSession getInstance = + CheckoutSession._privateConstructor(); + + BillingDetails billingDetails; + ShippingType shippingType; + PaymentType paymentType; + + void initSession() { + billingDetails = BillingDetails(); + shippingType = null; + } + + void saveBillingAddress() { + SharedPref sharedPref = SharedPref(); + CustomerAddress customerAddress = + CheckoutSession.getInstance.billingDetails.billingAddress; + + String billingAddress = jsonEncode(customerAddress.toJson()); + sharedPref.save(sfKeyCheckout, billingAddress); + } + + Future getBillingAddress() async { + SharedPref sharedPref = SharedPref(); + + String strCheckoutDetails = await sharedPref.read(sfKeyCheckout); + + if (strCheckoutDetails != null && strCheckoutDetails != "") { + return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails)); + } + return null; + } + + void clearBillingAddress() { + SharedPref sharedPref = SharedPref(); + sharedPref.remove(sfKeyCheckout); + } + + Future total({bool withFormat, TaxRate taxRate}) async { + double totalCart = double.parse(await Cart.getInstance.getTotal()); + double totalShipping = 0; + if (shippingType != null && shippingType.object != null) { + switch (shippingType.methodId) { + case "flat_rate": + totalShipping = double.parse(shippingType.cost); + break; + case "free_shipping": + totalShipping = double.parse(shippingType.cost); + break; + case "local_pickup": + totalShipping = double.parse(shippingType.cost); + break; + default: + break; + } + } + + double total = totalCart + totalShipping; + + if (taxRate != null) { + String taxAmount = await Cart.getInstance.taxAmount(taxRate); + total += double.parse(taxAmount); + } + + if (withFormat != null && withFormat == true) { + return formatDoubleCurrency(total: total); + } + return total.toString(); + } +} diff --git a/LabelStoreMax/lib/models/customer_address.dart b/LabelStoreMax/lib/models/customer_address.dart new file mode 100644 index 0000000..e7347e7 --- /dev/null +++ b/LabelStoreMax/lib/models/customer_address.dart @@ -0,0 +1,96 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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. + +class CustomerAddress { + String firstName; + String lastName; + String addressLine; + String city; + String postalCode; + String country; + String emailAddress; + + CustomerAddress( + {this.firstName, + this.lastName, + this.addressLine, + this.city, + this.postalCode, + this.country, + this.emailAddress}); + + void initAddress() { + firstName = ""; + lastName = ""; + addressLine = ""; + city = ""; + postalCode = ""; + country = ""; + emailAddress = ""; + } + + bool hasMissingFields() { + return (this.firstName.isEmpty || + this.lastName.isEmpty || + this.addressLine.isEmpty || + this.city.isEmpty || + this.postalCode.isEmpty); + } + + String addressFull() { + List tmpArrAddress = new List(); + if (addressLine != "") { + tmpArrAddress.add(addressLine); + } + if (city != "") { + tmpArrAddress.add(city); + } + if (postalCode != "") { + tmpArrAddress.add(postalCode); + } + if (country != "") { + tmpArrAddress.add(country); + } + return tmpArrAddress.join(", "); + } + + String nameFull() { + List tmpArrName = new List(); + if (firstName != "") { + tmpArrName.add(firstName); + } + if (lastName != "") { + tmpArrName.add(lastName); + } + return tmpArrName.join(", "); + } + + CustomerAddress.fromJson(Map json) { + firstName = json['first_name']; + lastName = json['last_name']; + addressLine = json['address_line']; + city = json['city']; + postalCode = json['postal_code']; + country = json['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['country'] = this.country; + data['email_address'] = this.emailAddress; + return data; + } +} diff --git a/LabelStoreMax/lib/models/payment_type.dart b/LabelStoreMax/lib/models/payment_type.dart new file mode 100644 index 0000000..82b0b85 --- /dev/null +++ b/LabelStoreMax/lib/models/payment_type.dart @@ -0,0 +1,19 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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. + +class PaymentType { + int id; + String name; + String desc; + String assetImage; + Function pay; + + PaymentType({this.id, this.name, this.desc, this.assetImage, this.pay}); +} diff --git a/LabelStoreMax/lib/models/shipping_type.dart b/LabelStoreMax/lib/models/shipping_type.dart new file mode 100644 index 0000000..4c3dad5 --- /dev/null +++ b/LabelStoreMax/lib/models/shipping_type.dart @@ -0,0 +1,103 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:woosignal/models/response/shipping_method.dart'; + +import '../helpers/tools.dart'; + +class ShippingType { + String methodId; + String cost; + dynamic object; + + ShippingType({this.methodId, this.object, this.cost}); + + Map toJson() => + {'methodId': methodId, 'object': object, 'cost': cost}; + + String getTotal({bool withFormatting}) { + if (this.methodId != null && this.object != null) { + switch (this.methodId) { + case "flat_rate": + FlatRate flatRate = (this.object as FlatRate); + return (withFormatting == true + ? formatStringCurrency(total: cost) + : flatRate.cost); + case "free_shipping": + FreeShipping freeShipping = (this.object as FreeShipping); + return (withFormatting == true + ? formatStringCurrency(total: cost) + : freeShipping.cost); + case "local_pickup": + LocalPickup localPickup = (this.object as LocalPickup); + return (withFormatting == true + ? formatStringCurrency(total: cost) + : localPickup.cost); + default: + return "0"; + break; + } + } + return "0"; + } + + String getTitle() { + if (this.methodId != null && this.object != null) { + switch (this.methodId) { + case "flat_rate": + FlatRate flatRate = (this.object as FlatRate); + return flatRate.title; + case "free_shipping": + FreeShipping freeShipping = (this.object as FreeShipping); + return freeShipping.title; + case "local_pickup": + LocalPickup localPickup = (this.object as LocalPickup); + return localPickup.title; + default: + return ""; + break; + } + } + return ""; + } + + Map toShippingLineFee() { + if (this.methodId != null && this.object != null) { + Map tmpShippingLinesObj = {}; + + switch (this.methodId) { + case "flat_rate": + FlatRate flatRate = (this.object as FlatRate); + tmpShippingLinesObj["method_title"] = flatRate.title; + tmpShippingLinesObj["method_id"] = flatRate.methodId; + tmpShippingLinesObj["total"] = this.cost; + break; + case "free_shipping": + FreeShipping freeShipping = (this.object as FreeShipping); + tmpShippingLinesObj["method_title"] = freeShipping.title; + tmpShippingLinesObj["method_id"] = freeShipping.methodId; + tmpShippingLinesObj["total"] = this.cost; + break; + case "local_pickup": + LocalPickup localPickup = (this.object as LocalPickup); + tmpShippingLinesObj["method_title"] = localPickup.title; + tmpShippingLinesObj["method_id"] = localPickup.methodId; + tmpShippingLinesObj["total"] = this.cost; + break; + default: + return null; + break; + } + return tmpShippingLinesObj; + } + + return null; + } +} diff --git a/LabelStoreMax/lib/pages/about.dart b/LabelStoreMax/lib/pages/about.dart index 92aee13..b184119 100644 --- a/LabelStoreMax/lib/pages/about.dart +++ b/LabelStoreMax/lib/pages/about.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -11,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/labelconfig.dart'; +import 'package:label_storemax/widgets/menu_item.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:package_info/package_info.dart'; diff --git a/LabelStoreMax/lib/pages/browse_category.dart b/LabelStoreMax/lib/pages/browse_category.dart index 887ef22..b7f09c5 100644 --- a/LabelStoreMax/lib/pages/browse_category.dart +++ b/LabelStoreMax/lib/pages/browse_category.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,20 +10,23 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/products.dart' as WS; -import 'package:woosignal/woosignal.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; class BrowseCategoryPage extends StatefulWidget { - BrowseCategoryPage(); + final ProductCategory productCategory; + const BrowseCategoryPage({Key key, @required this.productCategory}) + : super(key: key); @override - _BrowseCategoryPageState createState() => _BrowseCategoryPageState(); + _BrowseCategoryPageState createState() => + _BrowseCategoryPageState(productCategory); } class _BrowseCategoryPageState extends State { - _BrowseCategoryPageState(); + _BrowseCategoryPageState(this._selectedCategory); List _products = []; var _productsController = ScrollController(); @@ -44,6 +47,11 @@ class _BrowseCategoryPageState extends State { _shouldStopRequests = false; waitForNextRequest = false; + _fetchProductsForCategory(); + _addScrollListener(); + } + + _addScrollListener() async { _productsController.addListener(() { double maxScroll = _productsController.position.maxScrollExtent; double currentScroll = _productsController.position.pixels; @@ -55,44 +63,35 @@ class _BrowseCategoryPageState extends State { if (waitForNextRequest) { return; } - WooSignal.getInstance(config: wsConfig).then((wcStore) { - waitForNextRequest = true; - _page = _page + 1; - wcStore - .getProducts(perPage: 50, page: _page, status: "publish") - .then((products) { - waitForNextRequest = false; - if (products.length == 0) { - _shouldStopRequests = true; - } - _products.addAll(products.toList()); - setState(() {}); - }); - }); + + _fetchMoreProducts(); } }); } - _fetchProductsForCategory() { - WooSignal.getInstance(config: wsConfig).then((wcStore) { - wcStore - .getProducts(category: _selectedCategory.id.toString(), perPage: 50) - .then((products) { - _products = products; - setState(() { - _isLoading = false; - }); - }); + _fetchMoreProducts() async { + waitForNextRequest = true; + List products = await appWooSignal((api) { + return api.getProducts(perPage: 50, page: _page, status: "publish"); }); + _products.addAll(products); + waitForNextRequest = false; + _page = _page + 1; + + waitForNextRequest = false; + if (products.length == 0) { + _shouldStopRequests = true; + } } - @override - void didChangeDependencies() { - super.didChangeDependencies(); - if (_isLoading) { - _selectedCategory = ModalRoute.of(context).settings.arguments; - _fetchProductsForCategory(); - } + _fetchProductsForCategory() async { + _products = await appWooSignal((api) { + return api.getProducts( + category: _selectedCategory.id.toString(), perPage: 50); + }); + setState(() { + _isLoading = false; + }); } @override diff --git a/LabelStoreMax/lib/pages/browse_search.dart b/LabelStoreMax/lib/pages/browse_search.dart index 5803524..d870ee1 100644 --- a/LabelStoreMax/lib/pages/browse_search.dart +++ b/LabelStoreMax/lib/pages/browse_search.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,19 +10,20 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; import 'package:woosignal/models/response/products.dart' as WS; -import 'package:woosignal/woosignal.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; class BrowseSearchPage extends StatefulWidget { - BrowseSearchPage(); + final String search; + BrowseSearchPage({Key key, @required this.search}) : super(key: key); @override - _BrowseSearchState createState() => _BrowseSearchState(); + _BrowseSearchState createState() => _BrowseSearchState(search); } class _BrowseSearchState extends State { - _BrowseSearchState(); + _BrowseSearchState(this._search); var _productsController = ScrollController(); List _products = []; @@ -41,6 +42,11 @@ class _BrowseSearchState extends State { _shouldStopRequests = false; waitForNextRequest = false; + _fetchProductsForSearch(_page); + _addScrollListener(); + } + + _addScrollListener() async { _productsController.addListener(() { double maxScroll = _productsController.position.maxScrollExtent; double currentScroll = _productsController.position.pixels; @@ -57,33 +63,20 @@ class _BrowseSearchState extends State { }); } - _fetchProductsForSearch(int page) { - WooSignal.getInstance(config: wsConfig).then((wcStore) { - waitForNextRequest = true; + _fetchProductsForSearch(int page) async { + waitForNextRequest = true; + List products = await appWooSignal((api) { _page = _page + 1; - wcStore - .getProducts( - search: _search, perPage: 100, page: page, status: "publish") - .then((products) { - waitForNextRequest = false; - if (products.length == 0) { - _shouldStopRequests = true; - } - _products.addAll(products.toList()); - setState(() { - _isLoading = false; - }); - }); + return api.getProducts( + search: _search, perPage: 100, page: page, status: "publish"); }); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - if (_isLoading) { - _search = ModalRoute.of(context).settings.arguments; - _fetchProductsForSearch(_page); + if (products.length == 0) { + _shouldStopRequests = true; } + setState(() { + _products.addAll(products.toList()); + _isLoading = false; + }); } @override @@ -122,10 +115,14 @@ class _BrowseSearchState extends State { ? GridView.count( crossAxisCount: 2, controller: _productsController, - children: List.generate(_products.length, (index) { - return wsCardProductItem(context, - index: index, product: _products[index]); - })) + children: List.generate( + _products.length, + (index) { + return wsCardProductItem(context, + index: index, product: _products[index]); + }, + ), + ) : wsNoResults(context)), flex: 1, ), diff --git a/LabelStoreMax/lib/pages/cart.dart b/LabelStoreMax/lib/pages/cart.dart index e8eb8ec..32971e3 100644 --- a/LabelStoreMax/lib/pages/cart.dart +++ b/LabelStoreMax/lib/pages/cart.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -11,8 +11,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/models/customer_address.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:label_storemax/widgets/buttons.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; -import 'package:woosignal/woosignal.dart'; class CartPage extends StatefulWidget { CartPage(); @@ -45,10 +50,12 @@ class _CartPageState extends State { }); return []; } - WooSignal wooSignal = await WooSignal.getInstance(config: wsConfig); + List> cartJSON = cart.map((c) => c.toJson()).toList(); - List cartRes = await wooSignal.cartCheck(cartJSON); + List cartRes = await appWooSignal((api) { + return api.cartCheck(cartJSON); + }); _cartLines = cartRes.map((json) => CartLineItem.fromJson(json)).toList(); if (_cartLines.length > 0) { Cart.getInstance.saveCartToPref(cartLineItems: _cartLines); diff --git a/LabelStoreMax/lib/pages/checkout_confirmation.dart b/LabelStoreMax/lib/pages/checkout_confirmation.dart index 9a2b20b..fc9a369 100644 --- a/LabelStoreMax/lib/pages/checkout_confirmation.dart +++ b/LabelStoreMax/lib/pages/checkout_confirmation.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -9,27 +9,28 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:label_storemax/app_payment_methods.dart'; import 'package:label_storemax/helpers/tools.dart'; -import 'package:label_storemax/labelconfig.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/models/customer_address.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:label_storemax/widgets/buttons.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:woosignal/models/response/tax_rate.dart'; -import 'package:woosignal_stripe/woosignal_stripe.dart'; -import 'package:woosignal/models/payload/order_wc.dart'; -import 'package:woosignal/models/response/order.dart' as WS; -import 'package:woosignal/woosignal.dart'; -import 'dart:io'; import 'package:label_storemax/app_country_options.dart'; class CheckoutConfirmationPage extends StatefulWidget { - CheckoutConfirmationPage(); + CheckoutConfirmationPage({Key key}) : super(key: key); @override - _CheckoutConfirmationPageState createState() => - _CheckoutConfirmationPageState(); + CheckoutConfirmationPageState createState() => + CheckoutConfirmationPageState(); } -class _CheckoutConfirmationPageState extends State { - _CheckoutConfirmationPageState(); +class CheckoutConfirmationPageState extends State { + CheckoutConfirmationPageState(); + + GlobalKey _key = GlobalKey(); bool _showFullLoader; @@ -48,9 +49,17 @@ class _CheckoutConfirmationPageState extends State { _getTaxes(); } + void reloadState({bool showLoader}) { + setState(() { + _showFullLoader = showLoader ?? false; + }); + } + _getTaxes() async { - WooSignal wooSignal = await WooSignal.getInstance(config: wsConfig); - _taxRates = await wooSignal.getTaxRates(page: 1, perPage: 100); + _taxRates = await appWooSignal((api) { + return api.getTaxRates(page: 1, perPage: 100); + }); + if (CheckoutSession.getInstance.billingDetails.shippingAddress == null) { setState(() { _showFullLoader = false; @@ -150,7 +159,8 @@ class _CheckoutConfirmationPageState extends State { 30, CheckoutSession.getInstance .billingDetails.billingAddress - .addressFull())), + .addressFull(), + )), action: _actionCheckoutDetails, showBorderBottom: true) : wsCheckoutRow(context, @@ -170,7 +180,7 @@ class _CheckoutConfirmationPageState extends State { .paymentType.assetImage), width: 70), leadTitle: CheckoutSession - .getInstance.paymentType.name, + .getInstance.paymentType.desc, action: _actionPayWith, showBorderBottom: true) : wsCheckoutRow(context, @@ -236,8 +246,13 @@ class _CheckoutConfirmationPageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ showAppLoader(), - Text(trans(context, "One moment") + "...", - style: Theme.of(context).primaryTextTheme.subhead) + Padding( + padding: const EdgeInsets.only(top: 15), + child: Text( + trans(context, "One moment") + "...", + style: Theme.of(context).primaryTextTheme.subhead, + ), + ) ], ), ), @@ -284,168 +299,7 @@ class _CheckoutConfirmationPageState extends State { return; } - _pay(); - } - - Future _buildOrderWC() async { - OrderWC orderWC = OrderWC(); - if (Platform.isAndroid) { - orderWC.paymentMethod = "Stripe - Android App"; - orderWC.paymentMethodTitle = "stripe"; - } else if (Platform.isIOS) { - orderWC.paymentMethod = "Stripe - IOS App"; - orderWC.paymentMethodTitle = "stripe"; - } - - orderWC.setPaid = true; - orderWC.status = "pending"; - orderWC.currency = app_currency_iso.toUpperCase(); - - List lineItems = []; - List cartItems = await Cart.getInstance.getCart(); - cartItems.forEach((cartItem) { - LineItems tmpLineItem = LineItems(); - tmpLineItem.quantity = cartItem.quantity; - tmpLineItem.name = cartItem.name; - tmpLineItem.productId = cartItem.productId; - if (cartItem.variationId != null && cartItem.variationId != 0) { - tmpLineItem.variationId = cartItem.variationId; - } - - tmpLineItem.total = cartItem.total; - tmpLineItem.subtotal = cartItem.subtotal; - - lineItems.add(tmpLineItem); - }); - - orderWC.lineItems = lineItems; - - BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails; - - Billing billing = Billing(); - billing.firstName = billingDetails.billingAddress.firstName; - billing.lastName = billingDetails.billingAddress.lastName; - billing.address1 = billingDetails.billingAddress.addressLine; - billing.city = billingDetails.billingAddress.city; - billing.postcode = billingDetails.billingAddress.postalCode; - billing.country = billingDetails.billingAddress.country; - billing.email = billingDetails.billingAddress.emailAddress; - - orderWC.billing = billing; - - Shipping shipping = Shipping(); - shipping.firstName = billingDetails.shippingAddress.firstName; - shipping.lastName = billingDetails.shippingAddress.lastName; - shipping.address1 = billingDetails.shippingAddress.addressLine; - shipping.city = billingDetails.shippingAddress.city; - shipping.postcode = billingDetails.shippingAddress.postalCode; - shipping.country = billingDetails.shippingAddress.country; - - orderWC.shipping = shipping; - - orderWC.shippingLines = []; - Map shippingLineFeeObj = - CheckoutSession.getInstance.shippingType.toShippingLineFee(); - if (shippingLineFeeObj != null) { - ShippingLines shippingLine = ShippingLines(); - shippingLine.methodId = shippingLineFeeObj['method_id']; - shippingLine.methodTitle = shippingLineFeeObj['method_title']; - shippingLine.total = shippingLineFeeObj['total']; - orderWC.shippingLines.add(shippingLine); - } - - if (_taxRate != null) { - orderWC.feeLines = []; - FeeLines feeLines = FeeLines(); - feeLines.name = _taxRate.name; - feeLines.total = await Cart.getInstance.taxAmount(_taxRate); - feeLines.taxClass = ""; - feeLines.taxStatus = "taxable"; - orderWC.feeLines.add(feeLines); - } - - return orderWC; - } - - _pay() async { - WooSignal wsStore = await WooSignal.getInstance(config: wsConfig); - - String cartTotal = await CheckoutSession.getInstance - .total(withFormat: false, taxRate: _taxRate); - - FlutterStripePayment.setStripeSettings( - stripeAccount: app_stripe_account, liveMode: app_stripe_live_mode); - - var paymentResponse = await FlutterStripePayment.addPaymentMethod(); - - if (paymentResponse.status == PaymentResponseStatus.succeeded) { - setState(() { - _showFullLoader = true; - }); - - BillingDetails checkoutDetails = - CheckoutSession.getInstance.billingDetails; - - Map address = { - "name": checkoutDetails.billingAddress.nameFull(), - "line1": checkoutDetails.shippingAddress.addressLine, - "city": checkoutDetails.shippingAddress.city, - "postal_code": checkoutDetails.shippingAddress.postalCode, - "country": checkoutDetails.shippingAddress.country - }; - - String cartShortDesc = await Cart.getInstance.cartShortDesc(); - - dynamic rsp = await wsStore.stripePaymentIntent( - amount: cartTotal, - email: checkoutDetails.billingAddress.emailAddress, - desc: cartShortDesc, - shipping: address); - - if (rsp == null) { - showToastNetworkError(); - setState(() { - _showFullLoader = false; - }); - return false; - } - - String clientSecret = rsp["client_secret"]; - var intentResponse = await FlutterStripePayment.confirmPaymentIntent( - clientSecret, - paymentResponse.paymentMethodId, - (double.parse(cartTotal) * 100)); - - if (intentResponse.status == PaymentResponseStatus.succeeded) { - OrderWC orderWC = await _buildOrderWC(); - WS.Order order = await wsStore.createOrder(orderWC); - - if (order != null) { - Cart.getInstance.clear(); - Navigator.pushNamed(context, "/checkout-status", arguments: order); - } else { - showEdgeAlertWith(context, - title: trans(context, "Error"), - desc: trans( - context, "Something went wrong, please contact our store")); - setState(() { - _showFullLoader = false; - }); - } - } else if (intentResponse.status == PaymentResponseStatus.failed) { - if (app_debug) { - print(intentResponse.errorMessage); - } - showEdgeAlertWith(context, - title: trans(context, "Error"), desc: intentResponse.errorMessage); - setState(() { - _showFullLoader = false; - }); - } else { - setState(() { - _showFullLoader = false; - }); - } - } + CheckoutSession.getInstance.paymentType + .pay(context, state: this, taxRate: _taxRate); } } diff --git a/LabelStoreMax/lib/pages/checkout_details.dart b/LabelStoreMax/lib/pages/checkout_details.dart index 20f7ee3..b3930dc 100644 --- a/LabelStoreMax/lib/pages/checkout_details.dart +++ b/LabelStoreMax/lib/pages/checkout_details.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,6 +10,10 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/billing_details.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/models/customer_address.dart'; +import 'package:label_storemax/widgets/buttons.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/app_country_options.dart'; @@ -82,27 +86,34 @@ class _CheckoutDetailsPageState extends State { wsModalBottom(context, title: trans(context, "Select a country"), bodyWidget: Expanded( - child: ListView.builder( - itemCount: appCountryOptions.length, - itemBuilder: (BuildContext context, int index) { - Map strName = appCountryOptions[index]; + child: ListView.separated( + itemCount: appCountryOptions.length, + itemBuilder: (BuildContext context, int index) { + Map strName = appCountryOptions[index]; - return InkWell( - child: Container( - child: Text(strName["name"], - style: Theme.of(context).primaryTextTheme.body2), - padding: EdgeInsets.only(top: 25, bottom: 25), - ), - splashColor: Colors.grey, - highlightColor: Colors.black12, - onTap: () { - setState(() { - _strBillingCountry = strName["name"]; - Navigator.of(context).pop(); - }); - }, - ); - }), + return InkWell( + child: Container( + child: Text(strName["name"], + style: Theme.of(context).primaryTextTheme.body2), + padding: EdgeInsets.only(top: 25, bottom: 25), + ), + splashColor: Colors.grey, + highlightColor: Colors.black12, + onTap: () { + setState(() { + _strBillingCountry = strName["name"]; + Navigator.of(context).pop(); + }); + }, + ); + }, + separatorBuilder: (cxt, i) { + return Divider( + height: 0, + color: Colors.black12, + ); + }, + ), )); } diff --git a/LabelStoreMax/lib/pages/checkout_payment_type.dart b/LabelStoreMax/lib/pages/checkout_payment_type.dart index 5ae4d4e..7553c6d 100644 --- a/LabelStoreMax/lib/pages/checkout_payment_type.dart +++ b/LabelStoreMax/lib/pages/checkout_payment_type.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,6 +10,8 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/widgets/buttons.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; class CheckoutPaymentTypePage extends StatefulWidget { @@ -26,6 +28,12 @@ class _CheckoutPaymentTypePageState extends State { @override void initState() { super.initState(); + + if (CheckoutSession.getInstance.paymentType == null) { + if (getPaymentTypes() != null && getPaymentTypes().length > 0) { + CheckoutSession.getInstance.paymentType = getPaymentTypes().first; + } + } } @override @@ -78,12 +86,16 @@ class _CheckoutPaymentTypePageState extends State { width: 60, fit: BoxFit.fitHeight, alignment: Alignment.center), - title: Text(getPaymentTypes()[index].name, + title: Text(getPaymentTypes()[index].desc, style: Theme.of(context) .primaryTextTheme .subhead), selected: true, - trailing: Icon(Icons.check), + trailing: (CheckoutSession + .getInstance.paymentType == + getPaymentTypes()[index] + ? Icon(Icons.check) + : null), onTap: () { CheckoutSession.getInstance.paymentType = getPaymentTypes()[index]; diff --git a/LabelStoreMax/lib/pages/checkout_shipping_type.dart b/LabelStoreMax/lib/pages/checkout_shipping_type.dart index ff205b6..3c65db6 100644 --- a/LabelStoreMax/lib/pages/checkout_shipping_type.dart +++ b/LabelStoreMax/lib/pages/checkout_shipping_type.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,9 +10,14 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/models/customer_address.dart'; +import 'package:label_storemax/models/shipping_type.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:label_storemax/widgets/buttons.dart'; import 'package:woosignal/models/response/shipping_method.dart'; -import 'package:label_storemax/widgets/woosignal_ui.dart'; -import 'package:woosignal/woosignal.dart'; import 'package:label_storemax/app_country_options.dart'; class CheckoutShippingTypePage extends StatefulWidget { @@ -43,8 +48,9 @@ class _CheckoutShippingTypePageState extends State { } _getShippingMethods() async { - WooSignal wooSignal = await WooSignal.getInstance(config: wsConfig); - List wsShipping = await wooSignal.getShippingMethods(); + List wsShipping = await appWooSignal((api) { + return api.getShippingMethods(); + }); CustomerAddress customerAddress = CheckoutSession.getInstance.billingDetails.shippingAddress; String postalCode = customerAddress.postalCode; @@ -96,7 +102,7 @@ class _CheckoutShippingTypePageState extends State { if (_shipping.methods.freeShipping != null) { _shipping.methods.freeShipping.forEach((freeShipping) { - if (_isNumeric(freeShipping.cost)) { + if (isNumeric(freeShipping.cost)) { Map tmpShippingOption = {}; tmpShippingOption = { "id": freeShipping.id, @@ -120,13 +126,6 @@ class _CheckoutShippingTypePageState extends State { }); } - bool _isNumeric(String str) { - if(str == null) { - return false; - } - return double.tryParse(str) != null; - } - Future _getShippingPrice(int index) async { double total = 0; List cartLineItem = await Cart.getInstance.getCart(); diff --git a/LabelStoreMax/lib/pages/checkout_status.dart b/LabelStoreMax/lib/pages/checkout_status.dart index 4f426c8..1a03c39 100644 --- a/LabelStoreMax/lib/pages/checkout_status.dart +++ b/LabelStoreMax/lib/pages/checkout_status.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,19 +10,21 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; -import 'package:label_storemax/labelconfig.dart'; import 'package:woosignal/models/response/products.dart' as WS; import 'package:woosignal/models/response/order.dart' as WS; +import '../widgets/woosignal_ui.dart'; + class CheckoutStatusPage extends StatefulWidget { - CheckoutStatusPage(); + final WS.Order order; + CheckoutStatusPage({Key key, @required this.order}) : super(key: key); @override - _CheckoutStatusState createState() => _CheckoutStatusState(); + _CheckoutStatusState createState() => _CheckoutStatusState(this.order); } class _CheckoutStatusState extends State { - _CheckoutStatusState(); + _CheckoutStatusState(this._order); WS.Order _order; @@ -31,19 +33,13 @@ class _CheckoutStatusState extends State { super.initState(); } - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _order = ModalRoute.of(context).settings.arguments; - } - @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Colors.white, elevation: 0.0, - title: Image.network(app_logo_url, height: 100), + title: storeLogo(height: 60), automaticallyImplyLeading: false, centerTitle: true, ), diff --git a/LabelStoreMax/lib/pages/error_page.dart b/LabelStoreMax/lib/pages/error_page.dart new file mode 100644 index 0000000..2367f1c --- /dev/null +++ b/LabelStoreMax/lib/pages/error_page.dart @@ -0,0 +1,62 @@ +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/widgets/buttons.dart'; + +class ErrorPage extends StatefulWidget { + ErrorPage(); + + @override + _ErrorPageState createState() => _ErrorPageState(); +} + +class _ErrorPageState extends State { + _ErrorPageState(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SafeArea( + minimum: safeAreaDefault(), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon( + Icons.error_outline, + size: 100, + color: Colors.black54, + ), + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + trans(context, "Sorry, something went wrong"), + style: Theme.of(context).primaryTextTheme.body1, + textAlign: TextAlign.center, + ), + ), + wsLinkButton(context, title: trans(context, "Back"), action: () { + Navigator.pop(context); + }), + ], + ), + ), + ), + ); + } +} diff --git a/LabelStoreMax/lib/pages/home.dart b/LabelStoreMax/lib/pages/home.dart index 16fe5e3..884aaea 100644 --- a/LabelStoreMax/lib/pages/home.dart +++ b/LabelStoreMax/lib/pages/home.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,9 +10,10 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:label_storemax/widgets/cart_icon.dart'; import 'package:woosignal/models/response/product_category.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS; -import 'package:woosignal/woosignal.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; class HomePage extends StatefulWidget { @@ -42,9 +43,33 @@ class _HomePageState extends State { _isLoading = true; _page = 1; + _home(); + _addScrollListener(); + } + + _home() async { + await _fetchProducts(); + await _fetchCategories(); _shouldStopRequests = false; waitForNextRequest = false; + setState(() { + _isLoading = false; + }); + } + _fetchProducts() async { + _products = await appWooSignal((api) { + return api.getProducts(perPage: 50, page: _page, status: "publish"); + }); + } + + _fetchCategories() async { + _categories = await appWooSignal((api) { + return api.getProductCategories(); + }); + } + + _addScrollListener() async { _productsController.addListener(() { double maxScroll = _productsController.position.maxScrollExtent; double currentScroll = _productsController.position.pixels; @@ -56,86 +81,75 @@ class _HomePageState extends State { if (waitForNextRequest) { return; } - WooSignal.getInstance(config: wsConfig).then((wcStore) { - waitForNextRequest = true; - _page = _page + 1; - wcStore - .getProducts(perPage: 50, page: _page, status: "publish") - .then((products) { - waitForNextRequest = false; - if (products.length == 0) { - _shouldStopRequests = true; - } - _products.addAll(products.toList()); - setState(() {}); - }); - }); + _fetchMoreProducts(); } }); + } - WooSignal.getInstance(config: wsConfig).then((wcStore) { - wcStore - .getProducts(perPage: 50, page: _page, status: "publish") - .then((products) { - _products = products; - setState(() { - _isLoading = false; - }); - }); - - wcStore.getProductCategories().then((categories) { - _categories = categories; - setState(() {}); - }); + _fetchMoreProducts() async { + waitForNextRequest = true; + List products = await appWooSignal((api) { + _page = _page + 1; + return api.getProducts(perPage: 50, page: _page, status: "publish"); + }); + if (products.length == 0) { + _shouldStopRequests = true; + } + setState(() { + _products.addAll(products.toList()); }); } void _modalBottomSheetMenu() { showModalBottomSheet( - context: context, - backgroundColor: Colors.transparent, - builder: (builder) { - return new Container( - height: double.infinity, - width: double.infinity - 10, - color: Colors.transparent, - child: new Container( - padding: EdgeInsets.only(top: 25, left: 18, right: 18), - decoration: new BoxDecoration( - color: Colors.white, - borderRadius: new BorderRadius.only( - topLeft: const Radius.circular(10.0), - topRight: const Radius.circular(10.0))), - child: Column( - children: [ - Text(trans(context, "Categories"), - style: Theme.of(context).primaryTextTheme.display1, - textAlign: TextAlign.left), - Expanded( - child: new ListView.builder( - itemCount: _categories.length, - itemBuilder: (BuildContext context, int index) { - return InkWell( - child: Container( - child: Text(_categories[index].name), - padding: EdgeInsets.all(15), - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: HexColor("#f2f2f2"), - width: 2))), - ), - onTap: () { - Navigator.pushNamed(context, "/browse-category", - arguments: _categories[index]); - }, - ); - })) - ], - ), + context: context, + backgroundColor: Colors.transparent, + builder: (builder) { + return new Container( + height: double.infinity, + width: double.infinity - 10, + color: Colors.transparent, + child: new Container( + padding: EdgeInsets.only(top: 25, left: 18, right: 18), + decoration: new BoxDecoration( + color: Colors.white, + borderRadius: new BorderRadius.only( + topLeft: const Radius.circular(10.0), + topRight: const Radius.circular(10.0)), ), - ); - }); + child: Column( + children: [ + Text(trans(context, "Categories"), + style: Theme.of(context).primaryTextTheme.display1, + textAlign: TextAlign.left), + Expanded( + child: new ListView.builder( + itemCount: _categories.length, + itemBuilder: (BuildContext context, int index) { + return InkWell( + child: Container( + child: Text(_categories[index].name), + padding: EdgeInsets.all(15), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: HexColor("#f2f2f2"), width: 2), + ), + ), + ), + onTap: () { + Navigator.pushNamed(context, "/browse-category", + arguments: _categories[index]); + }, + ); + }), + ) + ], + ), + ), + ); + }, + ); } @override @@ -207,12 +221,13 @@ class _HomePageState extends State { ? Expanded(child: showAppLoader()) : Expanded( child: GridView.count( - controller: _productsController, - crossAxisCount: 2, - children: List.generate(_products.length, (index) { - return wsCardProductItem(context, - index: index, product: _products[index]); - })), + controller: _productsController, + crossAxisCount: 2, + children: List.generate(_products.length, (index) { + return wsCardProductItem(context, + index: index, product: _products[index]); + }), + ), flex: 1, )), ], diff --git a/LabelStoreMax/lib/pages/home_menu.dart b/LabelStoreMax/lib/pages/home_menu.dart index 865cc91..f853207 100644 --- a/LabelStoreMax/lib/pages/home_menu.dart +++ b/LabelStoreMax/lib/pages/home_menu.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -9,10 +9,11 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; -import 'package:label_storemax/labelconfig.dart'; -import 'package:label_storemax/widgets/woosignal_ui.dart'; +import 'package:label_storemax/widgets/menu_item.dart'; import 'package:label_storemax/helpers/tools.dart'; +import '../widgets/woosignal_ui.dart'; + class HomeMenuPage extends StatefulWidget { HomeMenuPage(); @@ -50,7 +51,7 @@ class _HomeMenuPageState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Image.network(app_logo_url, height: 100), + storeLogo(height: 100), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, diff --git a/LabelStoreMax/lib/pages/home_search.dart b/LabelStoreMax/lib/pages/home_search.dart index ee73298..ba2c32f 100644 --- a/LabelStoreMax/lib/pages/home_search.dart +++ b/LabelStoreMax/lib/pages/home_search.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,8 +10,9 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/helpers/tools.dart'; -import 'package:label_storemax/labelconfig.dart'; -import 'package:label_storemax/widgets/woosignal_ui.dart'; +import 'package:label_storemax/widgets/buttons.dart'; + +import '../widgets/woosignal_ui.dart'; class HomeSearchPage extends StatefulWidget { HomeSearchPage(); @@ -45,8 +46,7 @@ class _HomeSearchPageState extends State { return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, - title: Image.network(app_logo_url, - height: 60, alignment: Alignment.center), + title: storeLogo(height: 60), centerTitle: true, ), body: SafeArea( @@ -60,14 +60,21 @@ class _HomeSearchPageState extends State { margin: EdgeInsets.only(bottom: 20), ), TextField( - controller: _txtSearchController, - style: Theme.of(context).primaryTextTheme.display2, - keyboardType: TextInputType.text, - autocorrect: false, - autofocus: true, - textCapitalization: TextCapitalization.sentences), - wsPrimaryButton(context, - title: trans(context, "Search"), action: _actionSearch) + controller: _txtSearchController, + style: Theme.of(context).primaryTextTheme.display2, + keyboardType: TextInputType.text, + autocorrect: false, + autofocus: true, + textCapitalization: TextCapitalization.sentences, + ), + Padding( + padding: const EdgeInsets.only(top: 10), + child: wsPrimaryButton( + context, + title: trans(context, "Search"), + action: _actionSearch, + ), + ) ], ), ), diff --git a/LabelStoreMax/lib/pages/product_detail.dart b/LabelStoreMax/lib/pages/product_detail.dart index 2350940..3c6ab7b 100644 --- a/LabelStoreMax/lib/pages/product_detail.dart +++ b/LabelStoreMax/lib/pages/product_detail.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -9,27 +9,53 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. import 'package:flutter/material.dart'; +import 'package:flutter/painting.dart'; import 'package:label_storemax/helpers/tools.dart'; -import 'package:label_storemax/labelconfig.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; +import 'package:label_storemax/widgets/buttons.dart'; +import 'package:label_storemax/widgets/cart_icon.dart'; import 'package:woosignal/models/response/product_variation.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS; -import 'package:woosignal/woosignal.dart'; import 'package:flutter_swiper/flutter_swiper.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:cached_network_image/cached_network_image.dart'; +class ProductDetailPage extends StatefulWidget { + final WS.Product product; + const ProductDetailPage({Key key, @required this.product}) : super(key: key); + + @override + _ProductDetailState createState() => _ProductDetailState(this.product); +} + class _ProductDetailState extends State { - _ProductDetailState(); + _ProductDetailState(this._product); bool _isLoading; WS.Product _product; + int _quantityIndicator = 1; List _productVariations = []; @override void initState() { super.initState(); + if (_product.type == "variable") { + _isLoading = true; + _fetchProductVariations(); + } else { + _isLoading = false; + } + } - _isLoading = true; + _fetchProductVariations() async { + _productVariations = await appWooSignal((api) { + return api.getProductVariations(_product.id); + }); + setState(() { + _isLoading = false; + }); } Map _tmpAttributeObj = {}; @@ -94,159 +120,146 @@ class _ProductDetailState extends State { _itemAddToCart({CartLineItem cartLineItem}) { Cart.getInstance.addToCart(cartLineItem: cartLineItem); - showToastWith(message: trans(context, "Added to cart"), statusType: ""); + showStatusAlert(context, + title: "Success", + subtitle: trans(context, "Added to cart"), + duration: 1, + icon: Icons.add_shopping_cart); setState(() {}); } void _modalBottomSheetAttributes() { - wsModalBottom(context, - title: trans(context, "Options"), - bodyWidget: Expanded( - child: ListView.separated( - itemCount: _product.attributes.length, - separatorBuilder: (BuildContext context, int index) => Divider( - color: Colors.black12, - thickness: 1, - ), - itemBuilder: (BuildContext context, int index) { - return ListTile( - title: Text(_product.attributes[index].name, - style: Theme.of(context).primaryTextTheme.subhead), - subtitle: (_tmpAttributeObj.isNotEmpty && - _tmpAttributeObj.containsKey(index)) - ? Text(_tmpAttributeObj[index]["value"], - style: Theme.of(context).primaryTextTheme.body2) - : Text(trans(context, "Select a") + - " " + - _product.attributes[index].name), - trailing: (_tmpAttributeObj.isNotEmpty && - _tmpAttributeObj.containsKey(index)) - ? Icon(Icons.check, color: Colors.blueAccent) - : null, - onTap: () { - _modalBottomSheetOptionsForAttribute(index); - }, - ); - }, - )), - extraWidget: Container( - decoration: BoxDecoration( - border: Border(top: BorderSide(color: Colors.black12, width: 1))), - padding: EdgeInsets.only(top: 10), - child: Column( - children: [ - Text( - (findProductVariation() != null - ? trans(context, "Price") + - ": " + - formatStringCurrency( - total: findProductVariation().price) - : (((_product.attributes.length == - _tmpAttributeObj.values.length) && - findProductVariation() == null) - ? trans(context, "This variation is unavailable") - : trans(context, "Choose your options"))), - style: Theme.of(context).primaryTextTheme.subhead), - Text( + wsModalBottom( + context, + title: trans(context, "Options"), + bodyWidget: Expanded( + child: ListView.separated( + itemCount: _product.attributes.length, + separatorBuilder: (BuildContext context, int index) => Divider( + color: Colors.black12, + thickness: 1, + ), + itemBuilder: (BuildContext context, int index) { + return ListTile( + title: Text(_product.attributes[index].name, + style: Theme.of(context).primaryTextTheme.subhead), + subtitle: (_tmpAttributeObj.isNotEmpty && + _tmpAttributeObj.containsKey(index)) + ? Text(_tmpAttributeObj[index]["value"], + style: Theme.of(context).primaryTextTheme.body2) + : Text(trans(context, "Select a") + + " " + + _product.attributes[index].name), + trailing: (_tmpAttributeObj.isNotEmpty && + _tmpAttributeObj.containsKey(index)) + ? Icon(Icons.check, color: Colors.blueAccent) + : null, + onTap: () { + _modalBottomSheetOptionsForAttribute(index); + }, + ); + }, + )), + extraWidget: Container( + decoration: BoxDecoration( + border: Border(top: BorderSide(color: Colors.black12, width: 1))), + padding: EdgeInsets.only(top: 10), + child: Column( + children: [ + Text( (findProductVariation() != null - ? findProductVariation().stockStatus != "instock" - ? trans(context, "Out of stock") - : "" - : ""), - style: Theme.of(context).primaryTextTheme.subhead, - ), - wsPrimaryButton(context, title: trans(context, "Add to cart"), - action: () { - if (_product.attributes.length != - _tmpAttributeObj.values.length) { + ? trans(context, "Price") + + ": " + + formatStringCurrency( + total: findProductVariation().price) + : (((_product.attributes.length == + _tmpAttributeObj.values.length) && + findProductVariation() == null) + ? trans(context, "This variation is unavailable") + : trans(context, "Choose your options"))), + style: Theme.of(context).primaryTextTheme.subhead), + Text( + (findProductVariation() != null + ? findProductVariation().stockStatus != "instock" + ? trans(context, "Out of stock") + : "" + : ""), + style: Theme.of(context).primaryTextTheme.subhead, + ), + wsPrimaryButton(context, title: trans(context, "Add to cart"), + action: () { + if (_product.attributes.length != + _tmpAttributeObj.values.length) { + showEdgeAlertWith(context, + title: trans(context, "Oops"), + desc: trans(context, "Please select valid options first"), + style: EdgeAlertStyle.WARNING); + return; + } + + if (findProductVariation() == null) { + showEdgeAlertWith(context, + title: trans(context, "Oops"), + desc: trans(context, "Product variation does not exist"), + style: EdgeAlertStyle.WARNING); + return; + } + + if (findProductVariation() != null) { + if (findProductVariation().stockStatus != "instock") { showEdgeAlertWith(context, - title: trans(context, "Oops"), - desc: trans(context, "Please select valid options first"), + title: trans(context, "Sorry"), + desc: trans(context, "This item is not in stock"), style: EdgeAlertStyle.WARNING); return; } + } - if (findProductVariation() == null) { - showEdgeAlertWith(context, - title: trans(context, "Oops"), - desc: trans(context, "Product variation does not exist"), - style: EdgeAlertStyle.WARNING); - return; - } + List options = []; + _tmpAttributeObj.forEach((k, v) { + options.add(v["name"] + ": " + v["value"]); + }); - if (findProductVariation() != null) { - if (findProductVariation().stockStatus != "instock") { - showEdgeAlertWith(context, - title: trans(context, "Sorry"), - desc: trans(context, "This item is not in stock"), - style: EdgeAlertStyle.WARNING); - return; - } - } + CartLineItem cartLineItem = CartLineItem( + name: _product.name, + productId: _product.id, + variationId: findProductVariation().id, + quantity: 1, + taxStatus: findProductVariation().taxStatus, + shippingClassId: + findProductVariation().shippingClassId.toString(), + subtotal: findProductVariation().price, + stockQuantity: findProductVariation().stockQuantity, + isManagedStock: findProductVariation().manageStock, + taxClass: findProductVariation().taxClass, + imageSrc: (findProductVariation().image != null + ? findProductVariation().image.src + : _product.images.first.src), + shippingIsTaxable: _product.shippingTaxable, + variationOptions: options.join(", "), + total: findProductVariation().price); - List options = []; - _tmpAttributeObj.forEach((k, v) { - options.add(v["name"] + ": " + v["value"]); - }); - - CartLineItem cartLineItem = CartLineItem( - name: _product.name, - productId: _product.id, - variationId: findProductVariation().id, - quantity: 1, - taxStatus: findProductVariation().taxStatus, - shippingClassId: - findProductVariation().shippingClassId.toString(), - subtotal: findProductVariation().price, - stockQuantity: findProductVariation().stockQuantity, - isManagedStock: findProductVariation().manageStock, - taxClass: findProductVariation().taxClass, - imageSrc: (findProductVariation().image != null - ? findProductVariation().image.src - : _product.images.first.src), - shippingIsTaxable: _product.shippingTaxable, - variationOptions: options.join(", "), - total: findProductVariation().price); - - _itemAddToCart(cartLineItem: cartLineItem); - Navigator.of(context).pop(); - }), - ], - ), - margin: EdgeInsets.only(bottom: 10), - )); + _itemAddToCart(cartLineItem: cartLineItem); + Navigator.of(context).pop(); + }), + ], + ), + margin: EdgeInsets.only(bottom: 10), + ), + ); } void _modalBottomSheetMenu() { - wsModalBottom(context, - title: trans(context, "Description"), - bodyWidget: Expanded( - child: SingleChildScrollView( - child: Text(parseHtmlString(_product.description)), - ), - flex: 1, - )); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - if (_isLoading) { - _product = ModalRoute.of(context).settings.arguments; - - if (_product.type == "variable") { - WooSignal.getInstance(config: wsConfig).then((wcStore) { - wcStore.getProductVariations(_product.id).then((productVariations) { - _productVariations = productVariations; - _isLoading = false; - setState(() {}); - }); - }); - } else { - _isLoading = false; - setState(() {}); - } - } + wsModalBottom( + context, + title: trans(context, "Description"), + bodyWidget: Expanded( + child: SingleChildScrollView( + child: Text(parseHtmlString(_product.description)), + ), + flex: 1, + ), + ); } @override @@ -254,170 +267,276 @@ class _ProductDetailState extends State { return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, - actions: [wsCartIcon(context)], - title: storeLogo(height: 50), + actions: [ + wsCartIcon(context), + ], + title: storeLogo(height: 55), centerTitle: true, ), body: SafeArea( - minimum: safeAreaDefault(), child: _isLoading ? showAppLoader() : Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Flexible( - flex: 3, - child: SizedBox( - child: new Swiper( - itemBuilder: (BuildContext context, int index) { - return CachedNetworkImage( - imageUrl: _product.images[index].src, - placeholder: (context, url) => - new CircularProgressIndicator( - strokeWidth: 2, - backgroundColor: Colors.black12), - errorWidget: (context, url, error) => - new Icon(Icons.error), - fit: BoxFit.contain); - }, - itemCount: _product.images.length, - viewportFraction: 0.8, - scale: 0.9, - onTap: (i) { - setState(() {}); - }, - ), - ), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, + Expanded( + child: ListView( children: [ - Flexible( - child: Text( - _product.name, - style: Theme.of(context).primaryTextTheme.body2, - textAlign: TextAlign.left, + SizedBox( + height: MediaQuery.of(context).size.height * 0.40, + child: SizedBox( + child: new Swiper( + itemBuilder: (BuildContext context, int index) { + return CachedNetworkImage( + imageUrl: _product.images[index].src, + placeholder: (context, url) => + new CircularProgressIndicator( + strokeWidth: 2, + backgroundColor: Colors.black12, + ), + errorWidget: (context, url, error) => + new Icon(Icons.error), + fit: BoxFit.contain, + ); + }, + itemCount: _product.images.length, + viewportFraction: 0.85, + scale: 0.9, + onTap: (i) { + setState(() {}); + }, + ), ), - flex: 4, ), - Flexible( - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.center, + Container( + height: 100, + padding: EdgeInsets.symmetric( + vertical: 10, horizontal: 16), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - formatStringCurrency(total: _product.price), - style: - Theme.of(context).primaryTextTheme.subhead, - textAlign: TextAlign.right, + Flexible( + child: Text( + _product.name, + style: + Theme.of(context).primaryTextTheme.body2, + textAlign: TextAlign.left, + overflow: TextOverflow.ellipsis, + maxLines: 2, + ), + flex: 4, ), - Text( - ((_product.stockStatus != "instock" - ? trans(context, "Out of stock") - : trans(context, "In Stock"))), - style: Theme.of(context).primaryTextTheme.body1, - textAlign: TextAlign.right, + Flexible( + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + formatStringCurrency( + total: _product.price), + style: Theme.of(context) + .primaryTextTheme + .display1 + .copyWith( + fontSize: 20, + ), + textAlign: TextAlign.right, + ), + ], + ), + flex: 2, + ) + ], + ), + ), + Container( + color: Colors.white, + padding: + EdgeInsets.symmetric(vertical: 4, horizontal: 16), + height: 180, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + trans(context, "Description"), + style: Theme.of(context) + .primaryTextTheme + .caption + .copyWith(fontSize: 18), + textAlign: TextAlign.left, + ), + MaterialButton( + child: Text( + trans(context, "Full description"), + style: Theme.of(context) + .primaryTextTheme + .body1 + .copyWith(fontSize: 14), + textAlign: TextAlign.right, + ), + height: 50, + minWidth: 60, + onPressed: () { + _modalBottomSheetMenu(); + }, + ), + ], + ), + Flexible( + child: Text( + (_product.shortDescription != null && + _product.shortDescription != "" + ? parseHtmlString( + _product.shortDescription) + : parseHtmlString(_product.description)), + ), + flex: 3, ), ], ), - flex: 2, + ), + ], + ), + ), + Container( + padding: EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: Colors.black12, + blurRadius: 15.0, + spreadRadius: -17, + offset: Offset( + 0, + -10, + ), ) ], ), - ), - Divider( - color: Colors.black12, - thickness: 1, - ), - Expanded( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - trans(context, "Description"), - style: Theme.of(context).primaryTextTheme.body1, - textAlign: TextAlign.left, + "Quantity", + style: Theme.of(context).primaryTextTheme.body2, ), - MaterialButton( + Row( + children: [ + IconButton( + icon: Icon( + Icons.remove_circle_outline, + size: 28, + ), + onPressed: () { + if ((_quantityIndicator - 1) >= 1) { + setState(() { + _quantityIndicator--; + }); + } + }, + ), + Text( + _quantityIndicator.toString(), + style: + Theme.of(context).primaryTextTheme.body2, + ), + IconButton( + icon: Icon( + Icons.add_circle_outline, + size: 28, + ), + onPressed: () { + if (_quantityIndicator != 0) { + setState(() { + _quantityIndicator++; + }); + } + }, + ), + ], + ) + ], + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Align( child: Text( - trans(context, "Full description"), + formatStringCurrency( + total: (double.parse(_product.price) * + _quantityIndicator) + .toString()), style: - Theme.of(context).primaryTextTheme.caption, - textAlign: TextAlign.right, + Theme.of(context).primaryTextTheme.display1, + textAlign: TextAlign.center, + ), + alignment: Alignment.centerLeft, + )), + Flexible( + child: wsPrimaryButton( + context, + title: trans(context, "Add to cart"), + action: () { + _addItemToCart(); + }, ), - height: 50, - minWidth: 60, - onPressed: () { - _modalBottomSheetMenu(); - }, ), ], ), - Flexible( - child: Text( - (_product.shortDescription != null && - _product.shortDescription != "" - ? parseHtmlString(_product.shortDescription) - : parseHtmlString(_product.description)), - ), - flex: 3, - ), ], ), - flex: 1, - ), - wsPrimaryButton( - context, - title: trans(context, "ADD TO CART"), - action: () { - CartLineItem cartLineItem = CartLineItem( - name: _product.name, - productId: _product.id, - quantity: 1, - 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 ? "" : _product.images.first.src, - total: _product.price); - - if (_product.type != "simple") { - _modalBottomSheetAttributes(); - return; - } - if (_product.stockStatus == "instock") { - _itemAddToCart(cartLineItem: cartLineItem); - } else { - showEdgeAlertWith(context, - title: trans(context, "Sorry"), - desc: trans(context, "This item is out of stock"), - style: EdgeAlertStyle.WARNING, - icon: Icons.local_shipping); - } - }, + height: 140, ), ], ), ), ); } -} -class ProductDetailPage extends StatefulWidget { - ProductDetailPage(); + _addItemToCart() { + CartLineItem 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.first.src, + total: _product.price, + ); - @override - _ProductDetailState createState() => _ProductDetailState(); + if (_product.type != "simple") { + _modalBottomSheetAttributes(); + return; + } + if (_product.stockStatus == "instock") { + _itemAddToCart(cartLineItem: cartLineItem); + } else { + showEdgeAlertWith(context, + title: trans(context, "Sorry"), + desc: trans(context, "This item is out of stock"), + style: EdgeAlertStyle.WARNING, + icon: Icons.local_shipping); + } + } } diff --git a/LabelStoreMax/lib/providers/stripe_pay.dart b/LabelStoreMax/lib/providers/stripe_pay.dart new file mode 100644 index 0000000..e0288b1 --- /dev/null +++ b/LabelStoreMax/lib/providers/stripe_pay.dart @@ -0,0 +1,106 @@ +// +// LabelCore +// Label StoreMAX +// +// Created by Anthony Gordon. +// Copyright © 2020 WooSignal. 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:label_storemax/helpers/data/order_wc.dart'; +import 'package:label_storemax/helpers/tools.dart'; +import 'package:label_storemax/labelconfig.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/pages/checkout_confirmation.dart'; +import 'package:woosignal/models/payload/order_wc.dart'; +import 'package:woosignal/models/response/order.dart'; +import 'package:woosignal/models/response/tax_rate.dart'; +import 'package:woosignal_stripe/woosignal_stripe.dart'; + +stripePay(context, + {@required CheckoutConfirmationPageState state, + TaxRate taxRate}) async { + + // CONFIGURE STRIPE + FlutterStripePayment.setStripeSettings( + stripeAccount: app_stripe_account, liveMode: app_stripe_live_mode); + + var paymentResponse = await FlutterStripePayment.addPaymentMethod(); + + // CHECK STATUS FROM STRIPE + if (paymentResponse.status == PaymentResponseStatus.succeeded) { + state.reloadState(showLoader: true); + + // CHECKOUT HELPER + await checkout(taxRate, (total, billingDetails, cart) async { + + Map address = { + "name": billingDetails.billingAddress.nameFull(), + "line1": billingDetails.shippingAddress.addressLine, + "city": billingDetails.shippingAddress.city, + "postal_code": billingDetails.shippingAddress.postalCode, + "country": billingDetails.shippingAddress.country + }; + + String cartShortDesc = await cart.cartShortDesc(); + + dynamic rsp = await appWooSignal((api) { + return api.stripePaymentIntent( + amount: total, + email: billingDetails.billingAddress.emailAddress, + desc: cartShortDesc, + shipping: address, + ); + }); + + if (rsp == null) { + showToastNetworkError(); + state.reloadState(showLoader: false); + return; + } + + String clientSecret = rsp["client_secret"]; + var intentResponse = await FlutterStripePayment.confirmPaymentIntent( + clientSecret, + paymentResponse.paymentMethodId, + (double.parse(total) * 100), + ); + + if (intentResponse.status == PaymentResponseStatus.succeeded) { + OrderWC orderWC = await buildOrderWC(taxRate: taxRate); + Order order = await appWooSignal((api) { + return api.createOrder(orderWC); + }); + + if (order != null) { + Cart.getInstance.clear(); + Navigator.pushNamed(context, "/checkout-status", arguments: order); + } else { + showEdgeAlertWith( + context, + title: trans(context, "Error"), + desc: + trans(context, "Something went wrong, please contact our store"), + ); + state.reloadState(showLoader: false); + } + } else if (intentResponse.status == PaymentResponseStatus.failed) { + if (app_debug) { + print(intentResponse.errorMessage); + } + showEdgeAlertWith( + context, + title: trans(context, "Error"), + desc: intentResponse.errorMessage, + ); + state.reloadState(showLoader: false); + } else { + state.reloadState(showLoader: false); + } + }); + } +} diff --git a/LabelStoreMax/lib/widgets/app_loader.dart b/LabelStoreMax/lib/widgets/app_loader.dart new file mode 100644 index 0000000..0370660 --- /dev/null +++ b/LabelStoreMax/lib/widgets/app_loader.dart @@ -0,0 +1,7 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_spinkit/flutter_spinkit.dart'; +import '../helpers/tools.dart'; + +Widget showAppLoader() { + return SpinKitDoubleBounce(color: HexColor("#393318")); +} diff --git a/LabelStoreMax/lib/widgets/buttons.dart b/LabelStoreMax/lib/widgets/buttons.dart new file mode 100644 index 0000000..3cb88dc --- /dev/null +++ b/LabelStoreMax/lib/widgets/buttons.dart @@ -0,0 +1,52 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../helpers/tools.dart'; + +Widget wsPrimaryButton(BuildContext context, + {@required String title, void Function() action}) { + return Container( + height: 55, + child: RaisedButton( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), + padding: EdgeInsets.all(8), + child: Text( + title, + style: Theme.of(context).primaryTextTheme.button.copyWith(fontSize: 16), + ), + onPressed: action ?? null, + elevation: 0, + ), + ); +} + +Widget wsSecondaryButton(BuildContext context, + {String title, void Function() action}) { + return Container( + height: 60, + margin: EdgeInsets.only(top: 10), + child: RaisedButton( + padding: EdgeInsets.all(10), + child: Text(title, + style: Theme.of(context).primaryTextTheme.body2, + textAlign: TextAlign.center), + onPressed: action, + color: HexColor("#f6f6f9"), + elevation: 0), + ); +} + +Widget wsLinkButton(BuildContext context, + {String title, void Function() action}) { + return Container( + height: 60, + margin: EdgeInsets.only(top: 10), + child: MaterialButton( + padding: EdgeInsets.all(10), + child: Text(title, + style: Theme.of(context).primaryTextTheme.body2, + textAlign: TextAlign.left), + onPressed: action, + elevation: 0), + ); +} diff --git a/LabelStoreMax/lib/widgets/cart_icon.dart b/LabelStoreMax/lib/widgets/cart_icon.dart new file mode 100644 index 0000000..6030f3e --- /dev/null +++ b/LabelStoreMax/lib/widgets/cart_icon.dart @@ -0,0 +1,45 @@ +import 'package:flutter/material.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; + +Widget wsCartIcon(BuildContext context) { + return IconButton( + icon: Stack( + children: [ + Positioned.fill( + child: Align( + child: Icon(Icons.shopping_cart, size: 20, color: Colors.black87), + alignment: Alignment.bottomCenter, + ), + bottom: 0), + Positioned.fill( + child: Align( + child: FutureBuilder>( + future: Cart.getInstance.getCart(), + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return Text(""); + default: + if (snapshot.hasError) + return Text(""); + else + return new Text( + snapshot.data.length.toString(), + style: Theme.of(context).primaryTextTheme.body2, + textAlign: TextAlign.center, + ); + } + }, + ), + alignment: Alignment.topCenter, + ), + top: 0) + ], + ), + onPressed: () { + Navigator.pushNamed(context, "/cart"); + }, + ); +} diff --git a/LabelStoreMax/lib/widgets/menu_item.dart b/LabelStoreMax/lib/widgets/menu_item.dart new file mode 100644 index 0000000..3b13523 --- /dev/null +++ b/LabelStoreMax/lib/widgets/menu_item.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +Widget wsMenuItem(BuildContext context, + {String title, Widget leading, void Function() action}) { + return Flexible( + child: InkWell( + child: Card( + child: Container( + width: double.infinity, + padding: EdgeInsets.only(top: 15, bottom: 15), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + leading, + Text(" " + title, + style: Theme.of(context).primaryTextTheme.body1), + ], + ), + ), + elevation: 1, + margin: EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8), + ), + onTap: action, + ), + ); +} diff --git a/LabelStoreMax/lib/widgets/woosignal_ui.dart b/LabelStoreMax/lib/widgets/woosignal_ui.dart index ac47a0b..069c8a6 100644 --- a/LabelStoreMax/lib/widgets/woosignal_ui.dart +++ b/LabelStoreMax/lib/widgets/woosignal_ui.dart @@ -1,7 +1,7 @@ // Label StoreMAX // // Created by Anthony Gordon. -// Copyright © 2019 WooSignal. All rights reserved. +// Copyright © 2020 WooSignal. All rights reserved. // // Unless required by applicable law or agreed to in writing, software @@ -10,6 +10,10 @@ import 'package:flutter/material.dart'; import 'package:label_storemax/labelconfig.dart'; +import 'package:label_storemax/models/cart.dart'; +import 'package:label_storemax/models/cart_line_item.dart'; +import 'package:label_storemax/models/checkout_session.dart'; +import 'package:label_storemax/widgets/app_loader.dart'; import 'package:woosignal/models/response/products.dart'; import 'package:label_storemax/helpers/tools.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -17,118 +21,6 @@ import 'package:woosignal/models/response/tax_rate.dart'; const appFontFamily = "Overpass"; -Widget wsCartIcon(BuildContext context) { - return IconButton( - icon: Stack( - children: [ - Positioned.fill( - child: Align( - child: Icon(Icons.shopping_cart, size: 20, color: Colors.black87), - alignment: Alignment.bottomCenter, - ), - bottom: 0), - Positioned.fill( - child: Align( - child: FutureBuilder>( - future: Cart.getInstance.getCart(), - builder: (BuildContext context, - AsyncSnapshot> snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return Text(""); - default: - if (snapshot.hasError) - return Text(""); - else - return new Text( - snapshot.data.length.toString(), - style: Theme.of(context).primaryTextTheme.body2, - textAlign: TextAlign.center, - ); - } - }, - ), - alignment: Alignment.topCenter, - ), - top: 0) - ], - ), - onPressed: () { - Navigator.pushNamed(context, "/cart"); - }, - ); -} - -Widget wsMenuItem(BuildContext context, - {String title, Widget leading, void Function() action}) { - return Flexible( - child: InkWell( - child: Card( - child: Container( - width: double.infinity, - padding: EdgeInsets.only(top: 15, bottom: 15), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - leading, - Text(" " + title, - style: Theme.of(context).primaryTextTheme.body1), - ], - ), - ), - elevation: 1, - margin: EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8), - ), - onTap: action, - ), - ); -} - -Widget wsPrimaryButton(BuildContext context, - {String title, void Function() action}) { - return Container( - height: 60, - margin: EdgeInsets.only(top: 10), - child: RaisedButton( - padding: EdgeInsets.all(10), - child: Text(title, style: Theme.of(context).primaryTextTheme.button), - onPressed: action, - elevation: 0), - ); -} - -Widget wsSecondaryButton(BuildContext context, - {String title, void Function() action}) { - return Container( - height: 60, - margin: EdgeInsets.only(top: 10), - child: RaisedButton( - padding: EdgeInsets.all(10), - child: Text(title, - style: Theme.of(context).primaryTextTheme.body2, - textAlign: TextAlign.center), - onPressed: action, - color: HexColor("#f6f6f9"), - elevation: 0), - ); -} - -Widget wsLinkButton(BuildContext context, - {String title, void Function() action}) { - return Container( - height: 60, - margin: EdgeInsets.only(top: 10), - child: MaterialButton( - padding: EdgeInsets.all(10), - child: Text(title, - style: Theme.of(context).primaryTextTheme.body2, - textAlign: TextAlign.left), - onPressed: action, - elevation: 0), - ); -} - Widget wsRow2Text(BuildContext context, {String text1, String text2}) { return Row( crossAxisAlignment: CrossAxisAlignment.start, @@ -142,7 +34,11 @@ Widget wsRow2Text(BuildContext context, {String text1, String text2}) { ), Flexible( child: Container( - child: Text(text2, style: Theme.of(context).primaryTextTheme.body2), + child: Text(text2, + style: Theme.of(context) + .primaryTextTheme + .body2 + .copyWith(fontSize: 16, color: Colors.black87)), ), flex: 3, ) @@ -168,45 +64,46 @@ Widget wsCheckoutRow(BuildContext context, return Flexible( child: InkWell( child: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Padding( - child: Text(heading, - style: Theme.of(context).primaryTextTheme.body1), - padding: EdgeInsets.only(bottom: 8), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - leadImage, - Container( - child: Text(leadTitle, - style: Theme.of(context).primaryTextTheme.subhead, - maxLines: 2, - overflow: TextOverflow.ellipsis, - softWrap: false), - padding: EdgeInsets.only(left: 15), - ) - ], - ), - Icon(Icons.arrow_forward_ios) - ], - ) - ], - ), - padding: EdgeInsets.all(8), - decoration: showBorderBottom == true - ? BoxDecoration( - border: Border( - bottom: BorderSide(color: Colors.black12, width: 1))) - : BoxDecoration()), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + child: Text(heading, + style: Theme.of(context).primaryTextTheme.body1), + padding: EdgeInsets.only(bottom: 8), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + leadImage, + Container( + child: Text(leadTitle, + style: Theme.of(context).primaryTextTheme.subhead, + maxLines: 2, + overflow: TextOverflow.ellipsis, + softWrap: false), + padding: EdgeInsets.only(left: 15), + ) + ], + ), + 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), ), @@ -335,14 +232,18 @@ void wsModalBottom(BuildContext context, child: new Container( padding: EdgeInsets.only(top: 25, left: 18, right: 18), decoration: new BoxDecoration( - color: Colors.white, - borderRadius: new BorderRadius.only( - topLeft: const Radius.circular(10.0), - topRight: const Radius.circular(10.0))), + color: Colors.white, + borderRadius: new BorderRadius.only( + topLeft: const Radius.circular(10.0), + topRight: const Radius.circular(10.0)), + ), child: Column( children: [ Text(title, - style: Theme.of(context).primaryTextTheme.display1, + style: Theme.of(context) + .primaryTextTheme + .display1 + .copyWith(fontSize: 20), textAlign: TextAlign.left), bodyWidget, extraWidget ?? Container() @@ -481,12 +382,13 @@ Widget wsCardCartItem(BuildContext context, void Function() actionRemoveItem}) { return Container( decoration: BoxDecoration( + color: Colors.white, border: Border( bottom: BorderSide( - color: Colors.black12, - width: 1, - ))), - padding: EdgeInsets.all(8), + color: Colors.black12, + width: 1, + ))), + padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8), child: Column( children: [ Row( @@ -508,8 +410,12 @@ Widget wsCardCartItem(BuildContext context, crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text(cartLineItem.name, - style: Theme.of(context).primaryTextTheme.subhead), + Text( + cartLineItem.name, + style: Theme.of(context).primaryTextTheme.subhead, + overflow: TextOverflow.ellipsis, + maxLines: 3, + ), (cartLineItem.variationOptions != null ? Text(cartLineItem.variationOptions, style: Theme.of(context).primaryTextTheme.body2) @@ -575,9 +481,10 @@ Widget wsCardCartItem(BuildContext context, )); } -Widget storeLogo({double height}) { +Widget storeLogo({double height, double width}) { return cachedImage(app_logo_url, - height: height, placeholder: Container(height: height, width: height)); + height: height, + placeholder: Container(height: height ?? 100, width: width ?? 100)); } Widget cachedImage(image, {double height, Widget placeholder, BoxFit fit}) { diff --git a/LabelStoreMax/pubspec.lock b/LabelStoreMax/pubspec.lock index 26758c6..a2ec461 100644 --- a/LabelStoreMax/pubspec.lock +++ b/LabelStoreMax/pubspec.lock @@ -7,7 +7,7 @@ packages: name: archive url: "https://pub.dartlang.org" source: hosted - version: "2.0.10" + version: "2.0.11" args: dependency: transitive description: @@ -21,7 +21,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.4.0" boolean_selector: dependency: transitive description: @@ -35,7 +35,7 @@ packages: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "2.0.0" charcode: dependency: transitive description: @@ -50,13 +50,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.14.11" - connectivity: - dependency: "direct main" - description: - name: connectivity - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.4" convert: dependency: transitive description: @@ -98,7 +91,7 @@ packages: name: dio url: "https://pub.dartlang.org" source: hosted - version: "3.0.4" + version: "3.0.9" edge_alert: dependency: "direct main" description: @@ -106,6 +99,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.1" + flare_dart: + dependency: transitive + description: + name: flare_dart + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.3" + flare_flutter: + dependency: transitive + description: + name: flare_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "1.8.3" flutter: dependency: "direct main" description: flutter @@ -117,14 +124,14 @@ packages: name: flutter_cache_manager url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.1.3" flutter_launcher_icons: dependency: "direct main" description: name: flutter_launcher_icons url: "https://pub.dartlang.org" source: hosted - version: "0.7.3" + version: "0.7.4" flutter_localizations: dependency: "direct main" description: flutter @@ -150,7 +157,7 @@ packages: name: flutter_spinkit url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.1.2+1" flutter_swiper: dependency: "direct main" description: @@ -170,13 +177,18 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.11.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" fluttertoast: dependency: "direct main" description: name: fluttertoast url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "4.0.1" html: dependency: "direct main" description: @@ -204,49 +216,42 @@ packages: name: image url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "2.1.4" intl: - dependency: transitive + dependency: "direct overridden" description: name: intl url: "https://pub.dartlang.org" source: hosted version: "0.15.8" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.5" + version: "0.12.6" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.7" + version: "1.1.8" package_info: dependency: "direct main" description: name: package_info url: "https://pub.dartlang.org" source: hosted - version: "0.4.0+6" + version: "0.4.0+16" page_transition: dependency: "direct main" description: name: page_transition url: "https://pub.dartlang.org" source: hosted - version: "1.1.4" + version: "1.1.5" path: dependency: transitive description: @@ -282,13 +287,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.2.1" - pref_dessert: - dependency: "direct main" - description: - name: pref_dessert - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.0+1" quiver: dependency: transitive description: @@ -302,7 +300,28 @@ packages: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "0.5.4+3" + version: "0.5.6+3" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+6" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2+4" sky_engine: dependency: transitive description: flutter @@ -329,6 +348,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.9.3" + status_alert: + dependency: "direct main" + description: + name: status_alert + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.1" stream_channel: dependency: transitive description: @@ -363,7 +389,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.5" + version: "0.2.11" transformer_page_view: dependency: transitive description: @@ -405,7 +431,7 @@ packages: name: woosignal_stripe url: "https://pub.dartlang.org" source: hosted - version: "0.0.2" + version: "0.0.4" xml: dependency: transitive description: @@ -421,5 +447,5 @@ packages: source: hosted version: "2.2.0" sdks: - dart: ">2.4.0 <3.0.0" - flutter: ">=1.6.7 <2.0.0" + dart: ">=2.5.0 <3.0.0" + flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/LabelStoreMax/pubspec.yaml b/LabelStoreMax/pubspec.yaml index 6d84ea8..f173ed4 100644 --- a/LabelStoreMax/pubspec.yaml +++ b/LabelStoreMax/pubspec.yaml @@ -24,21 +24,20 @@ environment: dependencies: woosignal: ^1.0.2 - woosignal_stripe: ^0.0.2 - connectivity: ^0.4.4 - shared_preferences: ^0.5.3+4 + woosignal_stripe: ^0.0.4 + shared_preferences: ^0.5.6+3 cached_network_image: ^2.0.0 - page_transition: ^1.1.4 - package_info: ^0.4.0+6 - flutter_money_formatter: ^0.8.2 + page_transition: ^1.1.5 + package_info: ^0.4.0+16 + flutter_money_formatter: ^0.8.3 flutter_web_browser: ^0.11.0 - dio: ^3.0.2 + dio: ^3.0.9 flutter_swiper: ^1.1.6 edge_alert: ^0.0.1 - fluttertoast: ^3.1.3 - flutter_spinkit: ^4.0.0 - pref_dessert: ^0.4.0+1 - flutter_launcher_icons: ^0.7.3 + status_alert: ^0.1.1 + fluttertoast: ^4.0.1 + flutter_spinkit: ^4.1.2+1 + flutter_launcher_icons: ^0.7.4 html: ^0.14.0+3 flutter: sdk: flutter