Changes and tweaks

This commit is contained in:
Anthony 2020-03-28 04:53:06 +00:00
parent b578ac63d4
commit b3eef2047d
46 changed files with 2277 additions and 1612 deletions

View File

@ -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":[]}]}

View File

@ -25,6 +25,12 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 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 { android {
compileSdkVersion 28 compileSdkVersion 28
@ -37,7 +43,6 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.woosignal.label_storemax" applicationId "com.woosignal.label_storemax"
minSdkVersion 28 minSdkVersion 28
targetSdkVersion 28 targetSdkVersion 28
@ -47,13 +52,20 @@ android {
multiDexEnabled = true multiDexEnabled = true
} }
buildTypes { signingConfigs {
release { release {
// TODO: Add your own signing config for the release build. keyAlias keystoreProperties['keyAlias']
// Signing with the debug keys for now, so `flutter run --release` works. keyPassword keystoreProperties['keyPassword']
signingConfig signingConfigs.debug storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
} }
} }
buildTypes {
release {
signingConfig signingConfigs.release
}
}
} }
flutter { flutter {

View File

@ -0,0 +1,4 @@
storePassword=<password>
keyPassword=<password>
keyAlias=key
storeFile=<location of the key store file, e.g. /Users/<user name>/key.jks>

View File

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

90
LabelStoreMax/ios/Podfile Normal file
View File

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

View File

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

View File

@ -90,5 +90,7 @@
"About Us": "About Us", "About Us": "About Us",
"Something went wrong": "Something went wrong", "Something went wrong": "Something went wrong",
"Product variation does not exist": "Product variation does not exist", "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"
} }

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software

View File

@ -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<PaymentType> 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
// ),
// ),
];

View File

@ -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"}
];

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // 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/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import '../labelconfig.dart';
class AppLocalizations { class AppLocalizations {
final Locale locale; final Locale locale;
@ -48,7 +50,8 @@ class _AppLocalizationsDelegate
const _AppLocalizationsDelegate(); const _AppLocalizationsDelegate();
@override @override
bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode); bool isSupported(Locale locale) =>
app_locales_supported.contains(locale.languageCode);
@override @override
bool shouldReload(_AppLocalizationsDelegate old) => false; bool shouldReload(_AppLocalizationsDelegate old) => false;

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software

View File

@ -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<OrderWC> 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> lineItems = [];
List<CartLineItem> 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<String, dynamic> 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;
}

View File

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

View File

@ -1,50 +1,42 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:label_storemax/app_payment_methods.dart';
import 'package:label_storemax/helpers/app_localizations.dart'; import 'package:label_storemax/helpers/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/labelconfig.dart';
import 'package:edge_alert/edge_alert.dart'; import 'package:edge_alert/edge_alert.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:label_storemax/models/billing_details.dart';
import 'package:shared_preferences/shared_preferences.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:html/parser.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart'; import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'dart:convert';
import 'package:flutter_money_formatter/flutter_money_formatter.dart'; 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/models/response/tax_rate.dart';
import 'package:woosignal/woosignal.dart';
// CONFIG FOR WOOSIGNAL API appWooSignal(Function(WooSignal) api) async {
var wsConfig = {"appKey": app_key, "debugMode": app_debug}; WooSignal wooSignal = await WooSignal.getInstance(
config: {"appKey": app_key, "debugMode": app_debug});
// MARK: PaymentMethodType return await api(wooSignal);
class PaymentType {
int id;
String name;
String assetImage;
PaymentType({this.id, this.name, this.assetImage});
} }
List<PaymentType> arrPaymentMethods = [
(paymentMethods.contains("Stripe")
? (PaymentType(
id: 1,
name: "Debit or Credit Card",
assetImage: "dark_powered_by_stripe.png"))
: null)
];
List<PaymentType> getPaymentTypes() { List<PaymentType> 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 { class HexColor extends Color {
@ -65,29 +57,12 @@ String truncateWithEllipsis(int cutoff, String myString) {
: '${myString.substring(0, cutoff)}...'; : '${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}) { void showToastWith({String message, String statusType}) {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: message, msg: message,
toastLength: Toast.LENGTH_SHORT, toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER, gravity: ToastGravity.CENTER,
timeInSecForIos: 3, timeInSecForIosWeb: 3,
backgroundColor: backgroundColor:
(statusType == "error" ? HexColor("#b5123a") : Colors.grey), (statusType == "error" ? HexColor("#b5123a") : Colors.grey),
textColor: (statusType == "error" ? Colors.white : Colors.black), textColor: (statusType == "error" ? Colors.white : Colors.black),
@ -98,26 +73,15 @@ void showToastNetworkError() {
showToastWith(message: "Oops, something went wrong"); showToastWith(message: "Oops, something went wrong");
} }
bool isEmail(String em) { showStatusAlert(context,
String p = {@required String title, String subtitle, IconData icon, int duration}) {
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,}))$'; StatusAlert.show(
RegExp regExp = new RegExp(p); context,
return regExp.hasMatch(em); duration: Duration(seconds: duration ?? 2),
} title: title,
subtitle: subtitle,
// 6 LENGTH, 1 DIGIT configuration: IconConfiguration(icon: icon ?? Icons.done, size: 50),
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);
} }
class PaymentMethodType { 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) { String parseHtmlString(String htmlString) {
var document = parse(htmlString); var document = parse(htmlString);
String parsedString = parse(document.body.text).documentElement.text; String parsedString = parse(document.body.text).documentElement.text;
return parsedString; 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<String, dynamic> 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<String, dynamic> 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<String> tmpArrAddress = new List<String>();
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<String> tmpArrName = new List<String>();
if (firstName != "") {
tmpArrName.add(firstName);
}
if (lastName != "") {
tmpArrName.add(lastName);
}
return tmpArrName.join(", ");
}
CustomerAddress.fromJson(Map<String, dynamic> 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<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
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}) { String formatDoubleCurrency({double total}) {
FlutterMoneyFormatter fmf = FlutterMoneyFormatter( FlutterMoneyFormatter fmf = FlutterMoneyFormatter(
amount: total, amount: total,
settings: MoneyFormatterSettings( settings: MoneyFormatterSettings(
symbol: app_currency_symbol, symbol: app_currency_symbol,
)); ),
);
return fmf.output.symbolOnLeft; return fmf.output.symbolOnLeft;
} }
@ -399,338 +164,15 @@ String formatStringCurrency({String total}) {
tmpVal = double.parse(total); tmpVal = double.parse(total);
} }
FlutterMoneyFormatter fmf = FlutterMoneyFormatter( FlutterMoneyFormatter fmf = FlutterMoneyFormatter(
amount: tmpVal, amount: tmpVal,
settings: MoneyFormatterSettings( settings: MoneyFormatterSettings(
symbol: app_currency_symbol, symbol: app_currency_symbol,
)); ),
);
return fmf.output.symbolOnLeft; return fmf.output.symbolOnLeft;
} }
class ShippingType { openBrowserTab({@required String url}) async {
String methodId;
String cost;
dynamic object;
ShippingType({this.methodId, this.object, this.cost});
Map<String, dynamic> 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<String, dynamic> toShippingLineFee() {
if (this.methodId != null && this.object != null) {
Map<String, dynamic> 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<CustomerAddress> 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<String> 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<List<CartLineItem>> getCart() async {
List<CartLineItem> cartLineItems = [];
SharedPref sharedPref = SharedPref();
String currentCartArrJSON = (await sharedPref.read(_keyCart) as String);
if (currentCartArrJSON == null) {
cartLineItems = List<CartLineItem>();
} else {
cartLineItems = (jsonDecode(currentCartArrJSON) as List<dynamic>)
.map((i) => CartLineItem.fromJson(i))
.toList();
}
return cartLineItems;
}
void addToCart({CartLineItem cartLineItem}) async {
List<CartLineItem> 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<String> getTotal({bool withFormat}) async {
List<CartLineItem> 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<String> getSubtotal({bool withFormat}) async {
List<CartLineItem> 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<CartLineItem> cartLineItems = await getCart();
List<CartLineItem> tmpCartItem = new List<CartLineItem>();
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<String> cartShortDesc() async {
List<CartLineItem> 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<CartLineItem> cartLineItems = await getCart();
cartLineItems.removeAt(index);
saveCartToPref(cartLineItems: cartLineItems);
}
void clear() {
SharedPref sharedPref = SharedPref();
List<CartLineItem> cartLineItems = new List<CartLineItem>();
String jsonArrCartItems =
jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
sharedPref.save(_keyCart, jsonArrCartItems);
}
void saveCartToPref({List<CartLineItem> cartLineItems}) {
SharedPref sharedPref = SharedPref();
String jsonArrCartItems =
jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
sharedPref.save(_keyCart, jsonArrCartItems);
}
Future<String> taxAmount(TaxRate taxRate) async {
double subtotal = 0;
double shippingTotal = 0;
List<CartLineItem> cartItems = await Cart.getInstance.getCart();
if (cartItems.every((c) => c.taxStatus == 'none')) {
return "0";
}
List<CartLineItem> taxableCartLines =
cartItems.where((c) => c.taxStatus == 'taxable').toList();
double cartSubtotal = 0;
if (taxableCartLines.length > 0) {
cartSubtotal = taxableCartLines
.map<double>((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 {
await FlutterWebBrowser.openWebPage( await FlutterWebBrowser.openWebPage(
url: url, androidToolbarColor: Colors.white70); url: url, androidToolbarColor: Colors.white70);
} }
@ -739,26 +181,21 @@ EdgeInsets safeAreaDefault() {
return EdgeInsets.only(left: 16, right: 16, bottom: 8); return EdgeInsets.only(left: 16, right: 16, bottom: 8);
} }
class SlideRightRoute extends PageRouteBuilder {
final Widget widget;
SlideRightRoute({this.widget})
: super(pageBuilder: (BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return widget;
}, transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return new SlideTransition(
position: new Tween<Offset>(
begin: const Offset(-1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: child,
);
});
}
String trans(BuildContext context, String key) { String trans(BuildContext context, String key) {
return AppLocalizations.of(context).trans(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);
}

View File

@ -3,7 +3,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -14,7 +14,7 @@
Developer Notes Developer Notes
SUPPORT EMAIL - support@woosignal.com SUPPORT EMAIL - support@woosignal.com
VERSION - 1.0 VERSION - 2.0
https://woosignal.com https://woosignal.com
*/ */
@ -22,7 +22,8 @@
const app_name = "MyApp"; 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"; const app_logo_url = "https://woosignal.com/images/120x120_woosignal.png";
@ -31,7 +32,9 @@ const app_privacy_url = "https://yourdomain.com/privacy";
/*<! ------ STRIPE (OPTIONAL) ------!>*/ /*<! ------ STRIPE (OPTIONAL) ------!>*/
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 const app_stripe_live_mode = false; // SET true for live payments
/*<! ------ APP CURRENCY ------!>*/ /*<! ------ APP CURRENCY ------!>*/
@ -40,7 +43,7 @@ const app_currency_symbol = "\£";
const app_currency_iso = "gbp"; const app_currency_iso = "gbp";
const app_locales_supported = ['en']; const app_locales_supported = ['en'];
const paymentMethods = ["Stripe"]; const app_payment_methods = ["Stripe", "RazorPay"];
/*<! ------ DEBUGGER ENABLED ------!>*/ /*<! ------ DEBUGGER ENABLED ------!>*/

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,6 +10,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:label_storemax/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 'labelconfig.dart';
import 'package:label_storemax/pages/checkout_details.dart'; import 'package:label_storemax/pages/checkout_details.dart';
import 'package:label_storemax/pages/home.dart'; import 'package:label_storemax/pages/home.dart';
@ -46,43 +50,106 @@ void main() async {
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'/home': (BuildContext context) => new HomePage(), '/home': (BuildContext context) => new HomePage(),
'/cart': (BuildContext context) => new CartPage(), '/cart': (BuildContext context) => new CartPage(),
'/browse-category': (BuildContext context) => new BrowseCategoryPage(), '/error': (BuildContext context) => new ErrorPage(),
'/product-search': (BuildContext context) => new BrowseSearchPage(),
'/product-detail': (BuildContext context) => new ProductDetailPage(),
'/checkout': (BuildContext context) => new CheckoutConfirmationPage(), '/checkout': (BuildContext context) => new CheckoutConfirmationPage(),
'/checkout-status': (BuildContext context) => new CheckoutStatusPage(),
}, },
onGenerateRoute: (settings) { onGenerateRoute: (settings) {
switch (settings.name) { 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': case '/home-menu':
return PageTransition( return PageTransition(
child: HomeMenuPage(), type: PageTransitionType.leftToRight); child: HomeMenuPage(),
type: PageTransitionType.leftToRightWithFade,
);
case '/checkout-details': case '/checkout-details':
return PageTransition( return PageTransition(
child: CheckoutDetailsPage(), child: CheckoutDetailsPage(),
type: PageTransitionType.downToUp); type: PageTransitionType.downToUp,
);
case '/about': case '/about':
return PageTransition( return PageTransition(
child: AboutPage(), type: PageTransitionType.leftToRight); child: AboutPage(),
type: PageTransitionType.leftToRightWithFade,
);
case '/checkout-payment-type': case '/checkout-payment-type':
return PageTransition( return PageTransition(
child: CheckoutPaymentTypePage(), child: CheckoutPaymentTypePage(),
type: PageTransitionType.downToUp); type: PageTransitionType.downToUp,
);
case '/checkout-shipping-type': case '/checkout-shipping-type':
return PageTransition( return PageTransition(
child: CheckoutShippingTypePage(), child: CheckoutShippingTypePage(),
type: PageTransitionType.downToUp); type: PageTransitionType.downToUp,
);
case '/home-search': case '/home-search':
return PageTransition( return PageTransition(
child: HomeSearchPage(), type: PageTransitionType.downToUp); child: HomeSearchPage(),
type: PageTransitionType.downToUp,
);
default: default:
return null; return null;
} }
}, },
supportedLocales: [Locale('en')], supportedLocales: [
Locale('en'),
],
localizationsDelegates: [ localizationsDelegates: [
AppLocalizations.delegate, AppLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
@ -106,14 +173,15 @@ void main() async {
), ),
), ),
appBarTheme: AppBarTheme( appBarTheme: AppBarTheme(
color: Colors.white, color: Colors.white,
textTheme: textThemeAppBar(), textTheme: textThemeAppBar(),
elevation: 0.0, elevation: 0.0,
brightness: Brightness.light, brightness: Brightness.light,
iconTheme: IconThemeData(color: Colors.black), iconTheme: IconThemeData(color: Colors.black),
actionsIconTheme: IconThemeData( actionsIconTheme: IconThemeData(
color: Colors.black, color: Colors.black,
)), ),
),
accentColor: Colors.black, accentColor: Colors.black,
accentTextTheme: textThemeAccent(), accentTextTheme: textThemeAccent(),
textTheme: textThemeMain(), textTheme: textThemeMain(),

View File

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

View File

@ -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<List<CartLineItem>> getCart() async {
List<CartLineItem> cartLineItems = [];
SharedPref sharedPref = SharedPref();
String currentCartArrJSON = (await sharedPref.read(_keyCart) as String);
if (currentCartArrJSON == null) {
cartLineItems = List<CartLineItem>();
} else {
cartLineItems = (jsonDecode(currentCartArrJSON) as List<dynamic>)
.map((i) => CartLineItem.fromJson(i))
.toList();
}
return cartLineItems;
}
void addToCart({CartLineItem cartLineItem}) async {
List<CartLineItem> 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<String> getTotal({bool withFormat}) async {
List<CartLineItem> 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<String> getSubtotal({bool withFormat}) async {
List<CartLineItem> 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<CartLineItem> cartLineItems = await getCart();
List<CartLineItem> tmpCartItem = new List<CartLineItem>();
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<String> cartShortDesc() async {
List<CartLineItem> 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<CartLineItem> cartLineItems = await getCart();
cartLineItems.removeAt(index);
saveCartToPref(cartLineItems: cartLineItems);
}
void clear() {
SharedPref sharedPref = SharedPref();
List<CartLineItem> cartLineItems = new List<CartLineItem>();
String jsonArrCartItems =
jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
sharedPref.save(_keyCart, jsonArrCartItems);
}
void saveCartToPref({List<CartLineItem> cartLineItems}) {
SharedPref sharedPref = SharedPref();
String jsonArrCartItems =
jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
sharedPref.save(_keyCart, jsonArrCartItems);
}
Future<String> taxAmount(TaxRate taxRate) async {
double subtotal = 0;
double shippingTotal = 0;
List<CartLineItem> cartItems = await Cart.getInstance.getCart();
if (cartItems.every((c) => c.taxStatus == 'none')) {
return "0";
}
List<CartLineItem> taxableCartLines =
cartItems.where((c) => c.taxStatus == 'taxable').toList();
double cartSubtotal = 0;
if (taxableCartLines.length > 0) {
cartSubtotal = taxableCartLines
.map<double>((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();
}
}

View File

@ -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<String, dynamic> 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<String, dynamic> 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,
};
}

View File

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

View File

@ -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<String> tmpArrAddress = new List<String>();
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<String> tmpArrName = new List<String>();
if (firstName != "") {
tmpArrName.add(firstName);
}
if (lastName != "") {
tmpArrName.add(lastName);
}
return tmpArrName.join(", ");
}
CustomerAddress.fromJson(Map<String, dynamic> 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<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
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;
}
}

View File

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

View File

@ -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<String, dynamic> 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<String, dynamic> toShippingLineFee() {
if (this.methodId != null && this.object != null) {
Map<String, dynamic> 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;
}
}

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -11,6 +11,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/labelconfig.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:label_storemax/widgets/woosignal_ui.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,20 +10,23 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/widgets/app_loader.dart';
import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/products.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS;
import 'package:woosignal/woosignal.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
class BrowseCategoryPage extends StatefulWidget { class BrowseCategoryPage extends StatefulWidget {
BrowseCategoryPage(); final ProductCategory productCategory;
const BrowseCategoryPage({Key key, @required this.productCategory})
: super(key: key);
@override @override
_BrowseCategoryPageState createState() => _BrowseCategoryPageState(); _BrowseCategoryPageState createState() =>
_BrowseCategoryPageState(productCategory);
} }
class _BrowseCategoryPageState extends State<BrowseCategoryPage> { class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
_BrowseCategoryPageState(); _BrowseCategoryPageState(this._selectedCategory);
List<WS.Product> _products = []; List<WS.Product> _products = [];
var _productsController = ScrollController(); var _productsController = ScrollController();
@ -44,6 +47,11 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
_shouldStopRequests = false; _shouldStopRequests = false;
waitForNextRequest = false; waitForNextRequest = false;
_fetchProductsForCategory();
_addScrollListener();
}
_addScrollListener() async {
_productsController.addListener(() { _productsController.addListener(() {
double maxScroll = _productsController.position.maxScrollExtent; double maxScroll = _productsController.position.maxScrollExtent;
double currentScroll = _productsController.position.pixels; double currentScroll = _productsController.position.pixels;
@ -55,44 +63,35 @@ class _BrowseCategoryPageState extends State<BrowseCategoryPage> {
if (waitForNextRequest) { if (waitForNextRequest) {
return; return;
} }
WooSignal.getInstance(config: wsConfig).then((wcStore) {
waitForNextRequest = true; _fetchMoreProducts();
_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(() {});
});
});
} }
}); });
} }
_fetchProductsForCategory() { _fetchMoreProducts() async {
WooSignal.getInstance(config: wsConfig).then((wcStore) { waitForNextRequest = true;
wcStore List<WS.Product> products = await appWooSignal((api) {
.getProducts(category: _selectedCategory.id.toString(), perPage: 50) return api.getProducts(perPage: 50, page: _page, status: "publish");
.then((products) {
_products = products;
setState(() {
_isLoading = false;
});
});
}); });
_products.addAll(products);
waitForNextRequest = false;
_page = _page + 1;
waitForNextRequest = false;
if (products.length == 0) {
_shouldStopRequests = true;
}
} }
@override _fetchProductsForCategory() async {
void didChangeDependencies() { _products = await appWooSignal((api) {
super.didChangeDependencies(); return api.getProducts(
if (_isLoading) { category: _selectedCategory.id.toString(), perPage: 50);
_selectedCategory = ModalRoute.of(context).settings.arguments; });
_fetchProductsForCategory(); setState(() {
} _isLoading = false;
});
} }
@override @override

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,19 +10,20 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/widgets/app_loader.dart';
import 'package:woosignal/models/response/products.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'; import 'package:label_storemax/widgets/woosignal_ui.dart';
class BrowseSearchPage extends StatefulWidget { class BrowseSearchPage extends StatefulWidget {
BrowseSearchPage(); final String search;
BrowseSearchPage({Key key, @required this.search}) : super(key: key);
@override @override
_BrowseSearchState createState() => _BrowseSearchState(); _BrowseSearchState createState() => _BrowseSearchState(search);
} }
class _BrowseSearchState extends State<BrowseSearchPage> { class _BrowseSearchState extends State<BrowseSearchPage> {
_BrowseSearchState(); _BrowseSearchState(this._search);
var _productsController = ScrollController(); var _productsController = ScrollController();
List<WS.Product> _products = []; List<WS.Product> _products = [];
@ -41,6 +42,11 @@ class _BrowseSearchState extends State<BrowseSearchPage> {
_shouldStopRequests = false; _shouldStopRequests = false;
waitForNextRequest = false; waitForNextRequest = false;
_fetchProductsForSearch(_page);
_addScrollListener();
}
_addScrollListener() async {
_productsController.addListener(() { _productsController.addListener(() {
double maxScroll = _productsController.position.maxScrollExtent; double maxScroll = _productsController.position.maxScrollExtent;
double currentScroll = _productsController.position.pixels; double currentScroll = _productsController.position.pixels;
@ -57,33 +63,20 @@ class _BrowseSearchState extends State<BrowseSearchPage> {
}); });
} }
_fetchProductsForSearch(int page) { _fetchProductsForSearch(int page) async {
WooSignal.getInstance(config: wsConfig).then((wcStore) { waitForNextRequest = true;
waitForNextRequest = true; List<WS.Product> products = await appWooSignal((api) {
_page = _page + 1; _page = _page + 1;
wcStore return api.getProducts(
.getProducts( search: _search, perPage: 100, page: page, status: "publish");
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;
});
});
}); });
} if (products.length == 0) {
_shouldStopRequests = true;
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (_isLoading) {
_search = ModalRoute.of(context).settings.arguments;
_fetchProductsForSearch(_page);
} }
setState(() {
_products.addAll(products.toList());
_isLoading = false;
});
} }
@override @override
@ -122,10 +115,14 @@ class _BrowseSearchState extends State<BrowseSearchPage> {
? GridView.count( ? GridView.count(
crossAxisCount: 2, crossAxisCount: 2,
controller: _productsController, controller: _productsController,
children: List.generate(_products.length, (index) { children: List.generate(
return wsCardProductItem(context, _products.length,
index: index, product: _products[index]); (index) {
})) return wsCardProductItem(context,
index: index, product: _products[index]);
},
),
)
: wsNoResults(context)), : wsNoResults(context)),
flex: 1, flex: 1,
), ),

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -11,8 +11,13 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.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:label_storemax/widgets/woosignal_ui.dart';
import 'package:woosignal/woosignal.dart';
class CartPage extends StatefulWidget { class CartPage extends StatefulWidget {
CartPage(); CartPage();
@ -45,10 +50,12 @@ class _CartPageState extends State<CartPage> {
}); });
return []; return [];
} }
WooSignal wooSignal = await WooSignal.getInstance(config: wsConfig);
List<Map<String, dynamic>> cartJSON = cart.map((c) => c.toJson()).toList(); List<Map<String, dynamic>> cartJSON = cart.map((c) => c.toJson()).toList();
List<dynamic> cartRes = await wooSignal.cartCheck(cartJSON); List<dynamic> cartRes = await appWooSignal((api) {
return api.cartCheck(cartJSON);
});
_cartLines = cartRes.map((json) => CartLineItem.fromJson(json)).toList(); _cartLines = cartRes.map((json) => CartLineItem.fromJson(json)).toList();
if (_cartLines.length > 0) { if (_cartLines.length > 0) {
Cart.getInstance.saveCartToPref(cartLineItems: _cartLines); Cart.getInstance.saveCartToPref(cartLineItems: _cartLines);

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // 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. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/app_payment_methods.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/models/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:label_storemax/widgets/woosignal_ui.dart';
import 'package:woosignal/models/response/tax_rate.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'; import 'package:label_storemax/app_country_options.dart';
class CheckoutConfirmationPage extends StatefulWidget { class CheckoutConfirmationPage extends StatefulWidget {
CheckoutConfirmationPage(); CheckoutConfirmationPage({Key key}) : super(key: key);
@override @override
_CheckoutConfirmationPageState createState() => CheckoutConfirmationPageState createState() =>
_CheckoutConfirmationPageState(); CheckoutConfirmationPageState();
} }
class _CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> { class CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_CheckoutConfirmationPageState(); CheckoutConfirmationPageState();
GlobalKey<CheckoutConfirmationPageState> _key = GlobalKey<CheckoutConfirmationPageState>();
bool _showFullLoader; bool _showFullLoader;
@ -48,9 +49,17 @@ class _CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
_getTaxes(); _getTaxes();
} }
void reloadState({bool showLoader}) {
setState(() {
_showFullLoader = showLoader ?? false;
});
}
_getTaxes() async { _getTaxes() async {
WooSignal wooSignal = await WooSignal.getInstance(config: wsConfig); _taxRates = await appWooSignal((api) {
_taxRates = await wooSignal.getTaxRates(page: 1, perPage: 100); return api.getTaxRates(page: 1, perPage: 100);
});
if (CheckoutSession.getInstance.billingDetails.shippingAddress == null) { if (CheckoutSession.getInstance.billingDetails.shippingAddress == null) {
setState(() { setState(() {
_showFullLoader = false; _showFullLoader = false;
@ -150,7 +159,8 @@ class _CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
30, 30,
CheckoutSession.getInstance CheckoutSession.getInstance
.billingDetails.billingAddress .billingDetails.billingAddress
.addressFull())), .addressFull(),
)),
action: _actionCheckoutDetails, action: _actionCheckoutDetails,
showBorderBottom: true) showBorderBottom: true)
: wsCheckoutRow(context, : wsCheckoutRow(context,
@ -170,7 +180,7 @@ class _CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
.paymentType.assetImage), .paymentType.assetImage),
width: 70), width: 70),
leadTitle: CheckoutSession leadTitle: CheckoutSession
.getInstance.paymentType.name, .getInstance.paymentType.desc,
action: _actionPayWith, action: _actionPayWith,
showBorderBottom: true) showBorderBottom: true)
: wsCheckoutRow(context, : wsCheckoutRow(context,
@ -236,8 +246,13 @@ class _CheckoutConfirmationPageState extends State<CheckoutConfirmationPage> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
showAppLoader(), showAppLoader(),
Text(trans(context, "One moment") + "...", Padding(
style: Theme.of(context).primaryTextTheme.subhead) 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<CheckoutConfirmationPage> {
return; return;
} }
_pay(); CheckoutSession.getInstance.paymentType
} .pay(context, state: this, taxRate: _taxRate);
Future<OrderWC> _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> lineItems = [];
List<CartLineItem> 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<String, dynamic> 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<String, dynamic> 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;
});
}
}
} }
} }

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,6 +10,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/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/widgets/woosignal_ui.dart';
import 'package:label_storemax/app_country_options.dart'; import 'package:label_storemax/app_country_options.dart';
@ -82,27 +86,34 @@ class _CheckoutDetailsPageState extends State<CheckoutDetailsPage> {
wsModalBottom(context, wsModalBottom(context,
title: trans(context, "Select a country"), title: trans(context, "Select a country"),
bodyWidget: Expanded( bodyWidget: Expanded(
child: ListView.builder( child: ListView.separated(
itemCount: appCountryOptions.length, itemCount: appCountryOptions.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
Map<String, String> strName = appCountryOptions[index]; Map<String, String> strName = appCountryOptions[index];
return InkWell( return InkWell(
child: Container( child: Container(
child: Text(strName["name"], child: Text(strName["name"],
style: Theme.of(context).primaryTextTheme.body2), style: Theme.of(context).primaryTextTheme.body2),
padding: EdgeInsets.only(top: 25, bottom: 25), padding: EdgeInsets.only(top: 25, bottom: 25),
), ),
splashColor: Colors.grey, splashColor: Colors.grey,
highlightColor: Colors.black12, highlightColor: Colors.black12,
onTap: () { onTap: () {
setState(() { setState(() {
_strBillingCountry = strName["name"]; _strBillingCountry = strName["name"];
Navigator.of(context).pop(); Navigator.of(context).pop();
}); });
}, },
); );
}), },
separatorBuilder: (cxt, i) {
return Divider(
height: 0,
color: Colors.black12,
);
},
),
)); ));
} }

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,6 +10,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/models/checkout_session.dart';
import 'package:label_storemax/widgets/buttons.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
class CheckoutPaymentTypePage extends StatefulWidget { class CheckoutPaymentTypePage extends StatefulWidget {
@ -26,6 +28,12 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
if (CheckoutSession.getInstance.paymentType == null) {
if (getPaymentTypes() != null && getPaymentTypes().length > 0) {
CheckoutSession.getInstance.paymentType = getPaymentTypes().first;
}
}
} }
@override @override
@ -78,12 +86,16 @@ class _CheckoutPaymentTypePageState extends State<CheckoutPaymentTypePage> {
width: 60, width: 60,
fit: BoxFit.fitHeight, fit: BoxFit.fitHeight,
alignment: Alignment.center), alignment: Alignment.center),
title: Text(getPaymentTypes()[index].name, title: Text(getPaymentTypes()[index].desc,
style: Theme.of(context) style: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.subhead), .subhead),
selected: true, selected: true,
trailing: Icon(Icons.check), trailing: (CheckoutSession
.getInstance.paymentType ==
getPaymentTypes()[index]
? Icon(Icons.check)
: null),
onTap: () { onTap: () {
CheckoutSession.getInstance.paymentType = CheckoutSession.getInstance.paymentType =
getPaymentTypes()[index]; getPaymentTypes()[index];

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,9 +10,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/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: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'; import 'package:label_storemax/app_country_options.dart';
class CheckoutShippingTypePage extends StatefulWidget { class CheckoutShippingTypePage extends StatefulWidget {
@ -43,8 +48,9 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
} }
_getShippingMethods() async { _getShippingMethods() async {
WooSignal wooSignal = await WooSignal.getInstance(config: wsConfig); List<WSShipping> wsShipping = await appWooSignal((api) {
List<WSShipping> wsShipping = await wooSignal.getShippingMethods(); return api.getShippingMethods();
});
CustomerAddress customerAddress = CustomerAddress customerAddress =
CheckoutSession.getInstance.billingDetails.shippingAddress; CheckoutSession.getInstance.billingDetails.shippingAddress;
String postalCode = customerAddress.postalCode; String postalCode = customerAddress.postalCode;
@ -96,7 +102,7 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
if (_shipping.methods.freeShipping != null) { if (_shipping.methods.freeShipping != null) {
_shipping.methods.freeShipping.forEach((freeShipping) { _shipping.methods.freeShipping.forEach((freeShipping) {
if (_isNumeric(freeShipping.cost)) { if (isNumeric(freeShipping.cost)) {
Map<String, dynamic> tmpShippingOption = {}; Map<String, dynamic> tmpShippingOption = {};
tmpShippingOption = { tmpShippingOption = {
"id": freeShipping.id, "id": freeShipping.id,
@ -120,13 +126,6 @@ class _CheckoutShippingTypePageState extends State<CheckoutShippingTypePage> {
}); });
} }
bool _isNumeric(String str) {
if(str == null) {
return false;
}
return double.tryParse(str) != null;
}
Future<String> _getShippingPrice(int index) async { Future<String> _getShippingPrice(int index) async {
double total = 0; double total = 0;
List<CartLineItem> cartLineItem = await Cart.getInstance.getCart(); List<CartLineItem> cartLineItem = await Cart.getInstance.getCart();

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,19 +10,21 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/labelconfig.dart';
import 'package:woosignal/models/response/products.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS;
import 'package:woosignal/models/response/order.dart' as WS; import 'package:woosignal/models/response/order.dart' as WS;
import '../widgets/woosignal_ui.dart';
class CheckoutStatusPage extends StatefulWidget { class CheckoutStatusPage extends StatefulWidget {
CheckoutStatusPage(); final WS.Order order;
CheckoutStatusPage({Key key, @required this.order}) : super(key: key);
@override @override
_CheckoutStatusState createState() => _CheckoutStatusState(); _CheckoutStatusState createState() => _CheckoutStatusState(this.order);
} }
class _CheckoutStatusState extends State<CheckoutStatusPage> { class _CheckoutStatusState extends State<CheckoutStatusPage> {
_CheckoutStatusState(); _CheckoutStatusState(this._order);
WS.Order _order; WS.Order _order;
@ -31,19 +33,13 @@ class _CheckoutStatusState extends State<CheckoutStatusPage> {
super.initState(); super.initState();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_order = ModalRoute.of(context).settings.arguments;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.white, backgroundColor: Colors.white,
elevation: 0.0, elevation: 0.0,
title: Image.network(app_logo_url, height: 100), title: storeLogo(height: 60),
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
centerTitle: true, centerTitle: true,
), ),

View File

@ -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<ErrorPage> {
_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: <Widget>[
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);
}),
],
),
),
),
);
}
}

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,9 +10,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/widgets/app_loader.dart';
import 'package:label_storemax/widgets/cart_icon.dart';
import 'package:woosignal/models/response/product_category.dart' as WS; import 'package:woosignal/models/response/product_category.dart' as WS;
import 'package:woosignal/models/response/products.dart' as WS; import 'package:woosignal/models/response/products.dart' as WS;
import 'package:woosignal/woosignal.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
@ -42,9 +43,33 @@ class _HomePageState extends State<HomePage> {
_isLoading = true; _isLoading = true;
_page = 1; _page = 1;
_home();
_addScrollListener();
}
_home() async {
await _fetchProducts();
await _fetchCategories();
_shouldStopRequests = false; _shouldStopRequests = false;
waitForNextRequest = 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(() { _productsController.addListener(() {
double maxScroll = _productsController.position.maxScrollExtent; double maxScroll = _productsController.position.maxScrollExtent;
double currentScroll = _productsController.position.pixels; double currentScroll = _productsController.position.pixels;
@ -56,86 +81,75 @@ class _HomePageState extends State<HomePage> {
if (waitForNextRequest) { if (waitForNextRequest) {
return; return;
} }
WooSignal.getInstance(config: wsConfig).then((wcStore) { _fetchMoreProducts();
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(() {});
});
});
} }
}); });
}
WooSignal.getInstance(config: wsConfig).then((wcStore) { _fetchMoreProducts() async {
wcStore waitForNextRequest = true;
.getProducts(perPage: 50, page: _page, status: "publish") List<WS.Product> products = await appWooSignal((api) {
.then((products) { _page = _page + 1;
_products = products; return api.getProducts(perPage: 50, page: _page, status: "publish");
setState(() { });
_isLoading = false; if (products.length == 0) {
}); _shouldStopRequests = true;
}); }
setState(() {
wcStore.getProductCategories().then((categories) { _products.addAll(products.toList());
_categories = categories;
setState(() {});
});
}); });
} }
void _modalBottomSheetMenu() { void _modalBottomSheetMenu() {
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
builder: (builder) { builder: (builder) {
return new Container( return new Container(
height: double.infinity, height: double.infinity,
width: double.infinity - 10, width: double.infinity - 10,
color: Colors.transparent, color: Colors.transparent,
child: new Container( child: new Container(
padding: EdgeInsets.only(top: 25, left: 18, right: 18), padding: EdgeInsets.only(top: 25, left: 18, right: 18),
decoration: new BoxDecoration( decoration: new BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: new BorderRadius.only( borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0), topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))), topRight: const Radius.circular(10.0)),
child: Column(
children: <Widget>[
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]);
},
);
}))
],
),
), ),
); child: Column(
}); children: <Widget>[
Text(trans(context, "Categories"),
style: Theme.of(context).primaryTextTheme.display1,
textAlign: TextAlign.left),
Expanded(
child: new ListView.builder(
itemCount: _categories.length,
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 @override
@ -207,12 +221,13 @@ class _HomePageState extends State<HomePage> {
? Expanded(child: showAppLoader()) ? Expanded(child: showAppLoader())
: Expanded( : Expanded(
child: GridView.count( child: GridView.count(
controller: _productsController, controller: _productsController,
crossAxisCount: 2, crossAxisCount: 2,
children: List.generate(_products.length, (index) { children: List.generate(_products.length, (index) {
return wsCardProductItem(context, return wsCardProductItem(context,
index: index, product: _products[index]); index: index, product: _products[index]);
})), }),
),
flex: 1, flex: 1,
)), )),
], ],

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // 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. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/widgets/menu_item.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import '../widgets/woosignal_ui.dart';
class HomeMenuPage extends StatefulWidget { class HomeMenuPage extends StatefulWidget {
HomeMenuPage(); HomeMenuPage();
@ -50,7 +51,7 @@ class _HomeMenuPageState extends State<HomeMenuPage> {
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Image.network(app_logo_url, height: 100), storeLogo(height: 100),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,8 +10,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/widgets/buttons.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart';
import '../widgets/woosignal_ui.dart';
class HomeSearchPage extends StatefulWidget { class HomeSearchPage extends StatefulWidget {
HomeSearchPage(); HomeSearchPage();
@ -45,8 +46,7 @@ class _HomeSearchPageState extends State<HomeSearchPage> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
title: Image.network(app_logo_url, title: storeLogo(height: 60),
height: 60, alignment: Alignment.center),
centerTitle: true, centerTitle: true,
), ),
body: SafeArea( body: SafeArea(
@ -60,14 +60,21 @@ class _HomeSearchPageState extends State<HomeSearchPage> {
margin: EdgeInsets.only(bottom: 20), margin: EdgeInsets.only(bottom: 20),
), ),
TextField( TextField(
controller: _txtSearchController, controller: _txtSearchController,
style: Theme.of(context).primaryTextTheme.display2, style: Theme.of(context).primaryTextTheme.display2,
keyboardType: TextInputType.text, keyboardType: TextInputType.text,
autocorrect: false, autocorrect: false,
autofocus: true, autofocus: true,
textCapitalization: TextCapitalization.sentences), textCapitalization: TextCapitalization.sentences,
wsPrimaryButton(context, ),
title: trans(context, "Search"), action: _actionSearch) Padding(
padding: const EdgeInsets.only(top: 10),
child: wsPrimaryButton(
context,
title: trans(context, "Search"),
action: _actionSearch,
),
)
], ],
), ),
), ),

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // 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. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:label_storemax/labelconfig.dart'; import 'package:label_storemax/models/cart.dart';
import 'package:label_storemax/models/cart_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/product_variation.dart' as WS;
import 'package:woosignal/models/response/products.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:flutter_swiper/flutter_swiper.dart';
import 'package:label_storemax/widgets/woosignal_ui.dart'; import 'package:label_storemax/widgets/woosignal_ui.dart';
import 'package:cached_network_image/cached_network_image.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<ProductDetailPage> { class _ProductDetailState extends State<ProductDetailPage> {
_ProductDetailState(); _ProductDetailState(this._product);
bool _isLoading; bool _isLoading;
WS.Product _product; WS.Product _product;
int _quantityIndicator = 1;
List<WS.ProductVariation> _productVariations = []; List<WS.ProductVariation> _productVariations = [];
@override @override
void initState() { void initState() {
super.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<int, dynamic> _tmpAttributeObj = {}; Map<int, dynamic> _tmpAttributeObj = {};
@ -94,159 +120,146 @@ class _ProductDetailState extends State<ProductDetailPage> {
_itemAddToCart({CartLineItem cartLineItem}) { _itemAddToCart({CartLineItem cartLineItem}) {
Cart.getInstance.addToCart(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(() {}); setState(() {});
} }
void _modalBottomSheetAttributes() { void _modalBottomSheetAttributes() {
wsModalBottom(context, wsModalBottom(
title: trans(context, "Options"), context,
bodyWidget: Expanded( title: trans(context, "Options"),
child: ListView.separated( bodyWidget: Expanded(
itemCount: _product.attributes.length, child: ListView.separated(
separatorBuilder: (BuildContext context, int index) => Divider( itemCount: _product.attributes.length,
color: Colors.black12, separatorBuilder: (BuildContext context, int index) => Divider(
thickness: 1, color: Colors.black12,
), thickness: 1,
itemBuilder: (BuildContext context, int index) { ),
return ListTile( itemBuilder: (BuildContext context, int index) {
title: Text(_product.attributes[index].name, return ListTile(
style: Theme.of(context).primaryTextTheme.subhead), title: Text(_product.attributes[index].name,
subtitle: (_tmpAttributeObj.isNotEmpty && style: Theme.of(context).primaryTextTheme.subhead),
_tmpAttributeObj.containsKey(index)) subtitle: (_tmpAttributeObj.isNotEmpty &&
? Text(_tmpAttributeObj[index]["value"], _tmpAttributeObj.containsKey(index))
style: Theme.of(context).primaryTextTheme.body2) ? Text(_tmpAttributeObj[index]["value"],
: Text(trans(context, "Select a") + style: Theme.of(context).primaryTextTheme.body2)
" " + : Text(trans(context, "Select a") +
_product.attributes[index].name), " " +
trailing: (_tmpAttributeObj.isNotEmpty && _product.attributes[index].name),
_tmpAttributeObj.containsKey(index)) trailing: (_tmpAttributeObj.isNotEmpty &&
? Icon(Icons.check, color: Colors.blueAccent) _tmpAttributeObj.containsKey(index))
: null, ? Icon(Icons.check, color: Colors.blueAccent)
onTap: () { : null,
_modalBottomSheetOptionsForAttribute(index); onTap: () {
}, _modalBottomSheetOptionsForAttribute(index);
); },
}, );
)), },
extraWidget: Container( )),
decoration: BoxDecoration( extraWidget: Container(
border: Border(top: BorderSide(color: Colors.black12, width: 1))), decoration: BoxDecoration(
padding: EdgeInsets.only(top: 10), border: Border(top: BorderSide(color: Colors.black12, width: 1))),
child: Column( padding: EdgeInsets.only(top: 10),
children: <Widget>[ child: Column(
Text( children: <Widget>[
(findProductVariation() != null Text(
? 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() != null
? findProductVariation().stockStatus != "instock" ? trans(context, "Price") +
? trans(context, "Out of stock") ": " +
: "" formatStringCurrency(
: ""), total: findProductVariation().price)
style: Theme.of(context).primaryTextTheme.subhead, : (((_product.attributes.length ==
), _tmpAttributeObj.values.length) &&
wsPrimaryButton(context, title: trans(context, "Add to cart"), findProductVariation() == null)
action: () { ? trans(context, "This variation is unavailable")
if (_product.attributes.length != : trans(context, "Choose your options"))),
_tmpAttributeObj.values.length) { 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, showEdgeAlertWith(context,
title: trans(context, "Oops"), title: trans(context, "Sorry"),
desc: trans(context, "Please select valid options first"), desc: trans(context, "This item is not in stock"),
style: EdgeAlertStyle.WARNING); style: EdgeAlertStyle.WARNING);
return; return;
} }
}
if (findProductVariation() == null) { List<String> options = [];
showEdgeAlertWith(context, _tmpAttributeObj.forEach((k, v) {
title: trans(context, "Oops"), options.add(v["name"] + ": " + v["value"]);
desc: trans(context, "Product variation does not exist"), });
style: EdgeAlertStyle.WARNING);
return;
}
if (findProductVariation() != null) { CartLineItem cartLineItem = CartLineItem(
if (findProductVariation().stockStatus != "instock") { name: _product.name,
showEdgeAlertWith(context, productId: _product.id,
title: trans(context, "Sorry"), variationId: findProductVariation().id,
desc: trans(context, "This item is not in stock"), quantity: 1,
style: EdgeAlertStyle.WARNING); taxStatus: findProductVariation().taxStatus,
return; 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<String> options = []; _itemAddToCart(cartLineItem: cartLineItem);
_tmpAttributeObj.forEach((k, v) { Navigator.of(context).pop();
options.add(v["name"] + ": " + v["value"]); }),
}); ],
),
CartLineItem cartLineItem = CartLineItem( margin: EdgeInsets.only(bottom: 10),
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),
));
} }
void _modalBottomSheetMenu() { void _modalBottomSheetMenu() {
wsModalBottom(context, wsModalBottom(
title: trans(context, "Description"), context,
bodyWidget: Expanded( title: trans(context, "Description"),
child: SingleChildScrollView( bodyWidget: Expanded(
child: Text(parseHtmlString(_product.description)), child: SingleChildScrollView(
), child: Text(parseHtmlString(_product.description)),
flex: 1, ),
)); 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(() {});
}
}
} }
@override @override
@ -254,170 +267,276 @@ class _ProductDetailState extends State<ProductDetailPage> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
actions: <Widget>[wsCartIcon(context)], actions: <Widget>[
title: storeLogo(height: 50), wsCartIcon(context),
],
title: storeLogo(height: 55),
centerTitle: true, centerTitle: true,
), ),
body: SafeArea( body: SafeArea(
minimum: safeAreaDefault(),
child: _isLoading child: _isLoading
? showAppLoader() ? showAppLoader()
: Column( : Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Flexible( Expanded(
flex: 3, child: ListView(
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,
children: <Widget>[ children: <Widget>[
Flexible( SizedBox(
child: Text( height: MediaQuery.of(context).size.height * 0.40,
_product.name, child: SizedBox(
style: Theme.of(context).primaryTextTheme.body2, child: new Swiper(
textAlign: TextAlign.left, 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( Container(
child: Column( height: 100,
crossAxisAlignment: CrossAxisAlignment.end, padding: EdgeInsets.symmetric(
mainAxisAlignment: MainAxisAlignment.center, vertical: 10, horizontal: 16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Text( Flexible(
formatStringCurrency(total: _product.price), child: Text(
style: _product.name,
Theme.of(context).primaryTextTheme.subhead, style:
textAlign: TextAlign.right, Theme.of(context).primaryTextTheme.body2,
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
flex: 4,
), ),
Text( Flexible(
((_product.stockStatus != "instock" child: Column(
? trans(context, "Out of stock") crossAxisAlignment: CrossAxisAlignment.end,
: trans(context, "In Stock"))), mainAxisAlignment: MainAxisAlignment.center,
style: Theme.of(context).primaryTextTheme.body1, children: <Widget>[
textAlign: TextAlign.right, 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: <Widget>[
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
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( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Text( Text(
trans(context, "Description"), "Quantity",
style: Theme.of(context).primaryTextTheme.body1, style: Theme.of(context).primaryTextTheme.body2,
textAlign: TextAlign.left,
), ),
MaterialButton( Row(
children: <Widget>[
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: <Widget>[
Flexible(
child: Align(
child: Text( child: Text(
trans(context, "Full description"), formatStringCurrency(
total: (double.parse(_product.price) *
_quantityIndicator)
.toString()),
style: style:
Theme.of(context).primaryTextTheme.caption, Theme.of(context).primaryTextTheme.display1,
textAlign: TextAlign.right, 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, height: 140,
),
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);
}
},
), ),
], ],
), ),
), ),
); );
} }
}
class ProductDetailPage extends StatefulWidget { _addItemToCart() {
ProductDetailPage(); 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 if (_product.type != "simple") {
_ProductDetailState createState() => _ProductDetailState(); _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);
}
}
} }

View File

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

View File

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

View File

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

View File

@ -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: <Widget>[
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<List<CartLineItem>>(
future: Cart.getInstance.getCart(),
builder: (BuildContext context,
AsyncSnapshot<List<CartLineItem>> 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");
},
);
}

View File

@ -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: <Widget>[
leading,
Text(" " + title,
style: Theme.of(context).primaryTextTheme.body1),
],
),
),
elevation: 1,
margin: EdgeInsets.only(top: 8, bottom: 8, left: 8, right: 8),
),
onTap: action,
),
);
}

View File

@ -1,7 +1,7 @@
// Label StoreMAX // Label StoreMAX
// //
// Created by Anthony Gordon. // 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 // Unless required by applicable law or agreed to in writing, software
@ -10,6 +10,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:label_storemax/labelconfig.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:woosignal/models/response/products.dart';
import 'package:label_storemax/helpers/tools.dart'; import 'package:label_storemax/helpers/tools.dart';
import 'package:cached_network_image/cached_network_image.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"; const appFontFamily = "Overpass";
Widget wsCartIcon(BuildContext context) {
return IconButton(
icon: Stack(
children: <Widget>[
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<List<CartLineItem>>(
future: Cart.getInstance.getCart(),
builder: (BuildContext context,
AsyncSnapshot<List<CartLineItem>> 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: <Widget>[
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}) { Widget wsRow2Text(BuildContext context, {String text1, String text2}) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -142,7 +34,11 @@ Widget wsRow2Text(BuildContext context, {String text1, String text2}) {
), ),
Flexible( Flexible(
child: Container( 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, flex: 3,
) )
@ -168,45 +64,46 @@ Widget wsCheckoutRow(BuildContext context,
return Flexible( return Flexible(
child: InkWell( child: InkWell(
child: Container( child: Container(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Padding( Padding(
child: Text(heading, child: Text(heading,
style: Theme.of(context).primaryTextTheme.body1), style: Theme.of(context).primaryTextTheme.body1),
padding: EdgeInsets.only(bottom: 8), padding: EdgeInsets.only(bottom: 8),
), ),
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[ children: <Widget>[
leadImage, leadImage,
Container( Container(
child: Text(leadTitle, child: Text(leadTitle,
style: Theme.of(context).primaryTextTheme.subhead, style: Theme.of(context).primaryTextTheme.subhead,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: false), softWrap: false),
padding: EdgeInsets.only(left: 15), padding: EdgeInsets.only(left: 15),
) )
], ],
), ),
Icon(Icons.arrow_forward_ios) Icon(Icons.arrow_forward_ios)
], ],
) )
], ],
), ),
padding: EdgeInsets.all(8), padding: EdgeInsets.all(8),
decoration: showBorderBottom == true decoration: showBorderBottom == true
? BoxDecoration( ? BoxDecoration(
border: Border( border:
bottom: BorderSide(color: Colors.black12, width: 1))) Border(bottom: BorderSide(color: Colors.black12, width: 1)))
: BoxDecoration()), : BoxDecoration(),
),
onTap: action, onTap: action,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
@ -335,14 +232,18 @@ void wsModalBottom(BuildContext context,
child: new Container( child: new Container(
padding: EdgeInsets.only(top: 25, left: 18, right: 18), padding: EdgeInsets.only(top: 25, left: 18, right: 18),
decoration: new BoxDecoration( decoration: new BoxDecoration(
color: Colors.white, color: Colors.white,
borderRadius: new BorderRadius.only( borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0), topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))), topRight: const Radius.circular(10.0)),
),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Text(title, Text(title,
style: Theme.of(context).primaryTextTheme.display1, style: Theme.of(context)
.primaryTextTheme
.display1
.copyWith(fontSize: 20),
textAlign: TextAlign.left), textAlign: TextAlign.left),
bodyWidget, bodyWidget,
extraWidget ?? Container() extraWidget ?? Container()
@ -481,12 +382,13 @@ Widget wsCardCartItem(BuildContext context,
void Function() actionRemoveItem}) { void Function() actionRemoveItem}) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white,
border: Border( border: Border(
bottom: BorderSide( bottom: BorderSide(
color: Colors.black12, color: Colors.black12,
width: 1, width: 1,
))), ))),
padding: EdgeInsets.all(8), padding: EdgeInsets.symmetric(vertical: 8, horizontal: 8),
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Row( Row(
@ -508,8 +410,12 @@ Widget wsCardCartItem(BuildContext context,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Text(cartLineItem.name, Text(
style: Theme.of(context).primaryTextTheme.subhead), cartLineItem.name,
style: Theme.of(context).primaryTextTheme.subhead,
overflow: TextOverflow.ellipsis,
maxLines: 3,
),
(cartLineItem.variationOptions != null (cartLineItem.variationOptions != null
? Text(cartLineItem.variationOptions, ? Text(cartLineItem.variationOptions,
style: Theme.of(context).primaryTextTheme.body2) style: Theme.of(context).primaryTextTheme.body2)
@ -575,9 +481,10 @@ Widget wsCardCartItem(BuildContext context,
)); ));
} }
Widget storeLogo({double height}) { Widget storeLogo({double height, double width}) {
return cachedImage(app_logo_url, 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}) { Widget cachedImage(image, {double height, Widget placeholder, BoxFit fit}) {

View File

@ -7,7 +7,7 @@ packages:
name: archive name: archive
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.10" version: "2.0.11"
args: args:
dependency: transitive dependency: transitive
description: description:
@ -21,7 +21,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.3.0" version: "2.4.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -35,7 +35,7 @@ packages:
name: cached_network_image name: cached_network_image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.1" version: "2.0.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
@ -50,13 +50,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.14.11" version: "1.14.11"
connectivity:
dependency: "direct main"
description:
name: connectivity
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.4"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@ -98,7 +91,7 @@ packages:
name: dio name: dio
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.0.4" version: "3.0.9"
edge_alert: edge_alert:
dependency: "direct main" dependency: "direct main"
description: description:
@ -106,6 +99,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.1" 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: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -117,14 +124,14 @@ packages:
name: flutter_cache_manager name: flutter_cache_manager
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.1" version: "1.1.3"
flutter_launcher_icons: flutter_launcher_icons:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_launcher_icons name: flutter_launcher_icons
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.3" version: "0.7.4"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -150,7 +157,7 @@ packages:
name: flutter_spinkit name: flutter_spinkit
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.0.0" version: "4.1.2+1"
flutter_swiper: flutter_swiper:
dependency: "direct main" dependency: "direct main"
description: description:
@ -170,13 +177,18 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.11.0" version: "0.11.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
fluttertoast: fluttertoast:
dependency: "direct main" dependency: "direct main"
description: description:
name: fluttertoast name: fluttertoast
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.3" version: "4.0.1"
html: html:
dependency: "direct main" dependency: "direct main"
description: description:
@ -204,49 +216,42 @@ packages:
name: image name: image
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.5" version: "2.1.4"
intl: intl:
dependency: transitive dependency: "direct overridden"
description: description:
name: intl name: intl
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.15.8" version: "0.15.8"
json_annotation:
dependency: transitive
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.12.5" version: "0.12.6"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.7" version: "1.1.8"
package_info: package_info:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info name: package_info
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.4.0+6" version: "0.4.0+16"
page_transition: page_transition:
dependency: "direct main" dependency: "direct main"
description: description:
name: page_transition name: page_transition
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.1.4" version: "1.1.5"
path: path:
dependency: transitive dependency: transitive
description: description:
@ -282,13 +287,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.2.1" 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: quiver:
dependency: transitive dependency: transitive
description: description:
@ -302,7 +300,28 @@ packages:
name: shared_preferences name: shared_preferences
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted 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: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -329,6 +348,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.9.3" 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: stream_channel:
dependency: transitive dependency: transitive
description: description:
@ -363,7 +389,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.5" version: "0.2.11"
transformer_page_view: transformer_page_view:
dependency: transitive dependency: transitive
description: description:
@ -405,7 +431,7 @@ packages:
name: woosignal_stripe name: woosignal_stripe
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.0.2" version: "0.0.4"
xml: xml:
dependency: transitive dependency: transitive
description: description:
@ -421,5 +447,5 @@ packages:
source: hosted source: hosted
version: "2.2.0" version: "2.2.0"
sdks: sdks:
dart: ">2.4.0 <3.0.0" dart: ">=2.5.0 <3.0.0"
flutter: ">=1.6.7 <2.0.0" flutter: ">=1.12.13+hotfix.4 <2.0.0"

View File

@ -24,21 +24,20 @@ environment:
dependencies: dependencies:
woosignal: ^1.0.2 woosignal: ^1.0.2
woosignal_stripe: ^0.0.2 woosignal_stripe: ^0.0.4
connectivity: ^0.4.4 shared_preferences: ^0.5.6+3
shared_preferences: ^0.5.3+4
cached_network_image: ^2.0.0 cached_network_image: ^2.0.0
page_transition: ^1.1.4 page_transition: ^1.1.5
package_info: ^0.4.0+6 package_info: ^0.4.0+16
flutter_money_formatter: ^0.8.2 flutter_money_formatter: ^0.8.3
flutter_web_browser: ^0.11.0 flutter_web_browser: ^0.11.0
dio: ^3.0.2 dio: ^3.0.9
flutter_swiper: ^1.1.6 flutter_swiper: ^1.1.6
edge_alert: ^0.0.1 edge_alert: ^0.0.1
fluttertoast: ^3.1.3 status_alert: ^0.1.1
flutter_spinkit: ^4.0.0 fluttertoast: ^4.0.1
pref_dessert: ^0.4.0+1 flutter_spinkit: ^4.1.2+1
flutter_launcher_icons: ^0.7.3 flutter_launcher_icons: ^0.7.4
html: ^0.14.0+3 html: ^0.14.0+3
flutter: flutter:
sdk: flutter sdk: flutter