Compare commits

...

57 Commits
5.x ... 6.x

Author SHA1 Message Date
b279212a95 Launcher icon (all res.) changed to raster icon 2023-09-21 19:24:02 +02:00
ed1a9d70fb Changes reflecting personalization 2023-09-19 10:45:02 +02:00
4f11e7bb00 Upload files to 'LabelStoreMax/public/assets/app_icon' 2023-09-18 18:13:59 +00:00
Anthony
2f9118085c v6.9.1 2023-08-28 22:16:33 +01:00
Anthony
c620aa71cc v6.10.0 2023-08-21 02:54:53 +01:00
Anthony
63244606be v6.10.0 2023-08-21 02:54:18 +01:00
Anthony
3b350dbefb v6.9.0 2023-07-13 03:32:31 +01:00
Anthony
6deab507d8 v6.8.2 2023-07-05 00:00:42 +01:00
Anthony
a2698557ea v6.8.1 2023-07-03 21:00:28 +01:00
Anthony
fedd76fc67 v6.8.0 2023-07-03 07:46:19 +01:00
Anthony
456f313056 v6.7.0 2023-06-20 15:07:07 +07:00
Anthony
f67f486838 v6.6.2 2023-06-14 14:39:03 +07:00
Anthony
688ce6bec8 v6.6.1 updates 2023-05-28 22:49:11 +01:00
Anthony
05a7aedf54 Merge branch '6.x' of https://github.com/woosignal/flutter-woocommerce-app into 6.x 2023-05-28 22:37:50 +01:00
Anthony
adc32e730d v6.6.1 updates 2023-05-28 22:36:39 +01:00
Anthony Gordon
f25a5c7a18
Create Podfile 2023-05-19 12:35:10 +01:00
Anthony
54f7689e40 v6.6.0 updates 2023-05-19 12:06:15 +01:00
Anthony
ce9216ad94 update Pubspec.yaml 2023-05-19 11:10:46 +01:00
Anthony
da2301a2af v6.6.0 updates 2023-05-18 19:46:04 +01:00
Anthony
004c146967 v6.5.1 updates 2023-03-04 12:58:43 +07:00
Anthony
c980407287 v6.5.0 updates 2023-03-04 12:41:33 +07:00
Anthony
95c9697830 v6.4.1 updates 2023-02-23 11:23:06 +07:00
Anthony
a50cad6daa v6.4.0 updates 2023-01-06 16:11:58 -05:00
Anthony
7e43b678ea 6.3.1 updates 2022-11-04 14:01:21 +08:00
Anthony
8499fa8b07 update pubspec.lock 2022-11-03 16:08:14 +08:00
Anthony
683f67877e v6.3.0 updates 2022-11-03 15:43:16 +08:00
Anthony
31bb82d49b update CHANGELOG.md 2022-09-23 09:08:36 +08:00
Anthony
6dd9b73f9a ui tweaks 2022-09-23 08:57:08 +08:00
Anthony Gordon
f94a3e2fb5
Merge pull request #47 from jeanmatthieud/fix-checkout-phone-field
[FIX] Bug when phone number field is cleared during checkout
2022-09-23 08:54:17 +08:00
Anthony
b1847ff8f5 dependency updates 2022-09-23 08:31:11 +08:00
Anthony Gordon
234d0d3c7b
Merge pull request #50 from jeanmatthieud/fix-dark-theme
Dark theme fix for v6.2
2022-09-08 22:23:19 +08:00
Anthony Gordon
2383cd9e1d
Merge pull request #51 from jeanmatthieud/target-android-12
Android compile and target SDK 33
2022-09-08 22:19:44 +08:00
Jean-Matthieu DECHRISTE
1703fefd20 Android compile and target SDK 33 2022-09-08 09:39:31 +02:00
Jean-Matthieu DECHRISTE
0ef172887c Should fix dark theme #49 2022-09-08 09:36:21 +02:00
Jean-Matthieu DECHRISTE
5608484991 [FIX] Bug when phone number field is cleared during checkout 2022-09-06 11:22:02 +02:00
Anthony Gordon
94b989ad9d
Merge pull request #40 from jeanmatthieud/fix-checkout-details-validation
Fix email validation before submitting checkout details
2022-08-30 15:12:36 +10:00
Anthony Gordon
6670a50ad4
Merge pull request #42 from woosignal/dependency-updates
v6.2.0 - Dependency updates
2022-08-29 17:54:15 +10:00
Anthony Gordon
0276e8c217
Merge pull request #39 from jeanmatthieud/fix-woocommerce-user-role
Change user role after creation to match WooCommerce
2022-08-29 17:49:18 +10:00
Anthony Gordon
4d88cd08c7
Merge pull request #38 from jeanmatthieud/french-translation
Improved FR translation
2022-08-29 17:47:33 +10:00
Anthony Gordon
6cbf864cc9
Merge pull request #41 from woosignal/add-missing-translations
add missing translations
2022-08-29 17:46:21 +10:00
Anthony
f6d337fbfe update CHANGELOG.md 2022-08-29 15:43:49 +08:00
Anthony
0132c76569 dependency-updates 2022-08-29 15:34:56 +08:00
Anthony Gordon
29ab5a9eac
Merge branch '6.x' into add-missing-translations 2022-08-26 12:49:06 +08:00
Anthony
2b016a0bb0 add missing translations 2022-08-26 14:34:19 +10:00
Jean-Matthieu DECHRISTE
b4990cbe21 Fix email validation before submitting checkout details 2022-08-25 14:28:58 +02:00
Jean-Matthieu DECHRISTE
99db86f10c Change user role after creation to match WooCommerce 2022-08-25 14:27:45 +02:00
Jean-Matthieu DECHRISTE
7f88f152aa Improved FR translation 2022-08-25 14:27:02 +02:00
Anthony Gordon
faa62bb9ad
Merge pull request #36 from woosignal/master
6.1.0
2022-07-09 15:15:09 +07:00
Anthony Gordon
1e108c6c89
Merge branch '6.x' into master 2022-07-09 15:14:59 +07:00
Anthony
ab2a195032 update account_landing.dart 2022-07-09 15:12:30 +07:00
Anthony
ba5ddc1fa9 update .env 2022-07-09 15:04:28 +07:00
Anthony
c3420bb9bc 6.1.0 2022-07-09 15:01:12 +07:00
Anthony Gordon
7a77a0cb16
Merge pull request #35 from woosignal/master
v6.0.0 updates
2022-05-19 21:53:02 +01:00
Anthony
b2abd22753 v6.0.0 - refactor pages 2022-05-19 21:48:40 +01:00
Anthony
f5d22921b9 v6.0.0 - Flutter format 2022-05-19 21:46:20 +01:00
Anthony
e40b36a181 v6.0.0 updates 2022-05-19 21:43:55 +01:00
Anthony
9b187684b5 v5.9.0 updates 2022-05-19 21:37:41 +01:00
179 changed files with 6441 additions and 5221 deletions

3
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -1,21 +1,25 @@
# *<! ------ App ------!>* # *<! ------ App ------!>*
APP_NAME="MyApp" APP_NAME="Raster"
APP_ENV="local" APP_ENV="local"
APP_DEBUG="true" APP_DEBUG="true"
APP_URL="https://mywoocommercestore.com" APP_URL="https://rasterdoo.com"
ASSET_PATH_PUBLIC="public/assets/" ASSET_PATH_PUBLIC="public/assets/"
ASSET_PATH_IMAGES="public/assets/images" ASSET_PATH_IMAGES="public/assets/images"
TIMEZONE="UTC" TIMEZONE="UTC"
LIGHT_THEME_ID="default_light_theme"
DARK_THEME_ID="default_dark_theme"
# *<! ------ Language ------!>* # *<! ------ Language ------!>*
DEFAULT_LOCALE=null DEFAULT_LOCALE="en"
# supports: "en" (English), "es" (Spanish), "fr" (French), "hi" (Hindi), "it" (Italian), "pt" (Portuguese) or "zh" (Simplified Chinese) # supports: "en" (English), "es" (Spanish), "fr" (French), "hi" (Hindi), "it" (Italian), "pt" (Portuguese) or "zh" (Simplified Chinese)
# *<! ------ WooSignal Config ------!>* # *<! ------ WooSignal Config ------!>*
APP_KEY="your app key" APP_KEY="app_50818d11780aaba6b545076dea5b90"
# App key from WooSignal link: https://woosignal.com/dashboard # App key from WooSignal link: https://woosignal.com/dashboard
# *<! ------ STRIPE (OPTIONAL) ------!>* # *<! ------ STRIPE (OPTIONAL) ------!>*
@ -38,7 +42,17 @@ PAYPAL_LIVE_MODE=null
PAYPAL_LOCALE=null PAYPAL_LOCALE=null
# Use BCP-47 code from this link https://developer.paypal.com/docs/api/reference/locale-codes/ # Use BCP-47 code from this link https://developer.paypal.com/docs/api/reference/locale-codes/
# *<! ------ RAZORPAY (OPTIONAL) ------!>*
RAZORPAY_API_KEY=""
# *<! ------ EXTRAS ------!>* # *<! ------ EXTRAS ------!>*
PRODUCT_PLACEHOLDER_IMAGE="https://woosignal.com/images/woocommerce-placeholder.png" PRODUCT_PLACEHOLDER_IMAGE="https://woosignal.com/images/woocommerce-placeholder.png"
# Sets the default placeholder image for products with no image # Sets the default placeholder image for products with no image
AUTH_USER_KEY="AUTH_USER"
FCM_ENABLED=null
ENCRYPT_KEY=null
ENCRYPT_SECRET=null

View File

@ -1,3 +1,124 @@
## [6.10.1] - 2023-08-28
* Refactor project for Nylo 5.x.
* Fix AndroidManifest splash screen
* Pubspec.yaml dependency updates
## [6.10.0] - 2023-08-21
* Small refactor to project
* Pubspec.yaml dependency updates
## [6.9.0] - 2023-07-13
* Pull firebase config via woosignal api
* New encrypt key and secret added to .env
* fix fetchRelated to return "publish" products
* Pubspec.yaml dependency updates
## [6.8.2] - 2023-07-04
* Update gradle + kotlin versions.
* Pubspec.yaml dependency updates.
## [6.8.1] - 2023-07-03
* Fix auth bug.
* Pubspec.yaml dependency updates.
## [6.8.0] - 2023-07-03
* UI fixes.
* Fix price on coupon page error alerts.
* Fix issue where IOS builds were not using the correct build version.
* Small refactor to the project.
* Pubspec.yaml dependency updates.
## [6.7.0] - 2023-06-20
* Refactor project for Nylo 5.x.
* New Firebase provider for FCM.
* Pubspec.yaml dependency updates.
## [6.6.2] - 2023-06-14
* Page bug fixes
* Pubspec.yaml dependency updates.
## [6.6.1] - 2023-05-28
* Refactor widgets + bug fixes
* Refactor extensions.dart
* Pubspec.yaml dependency updates.
## [6.6.0] - 2023-05-18
* Nylo v5.0.0 migration
* Refactor project
* Flutter v3.10.0 compatibility
## [6.5.1] - 2023-03-04
* New translation added.
## [6.5.0] - 2023-03-04
* When making payments via Stripe, it will now save the card for later.
* Small UI changes to the checkout confirmation page.
* New translation added.
* Pubspec.yaml dependency updates.
## [6.4.1] - 2023-02-23
* Upgrade to Nylo v4.1.3
* Small refactor to TextStyle
* Fix the ThemeColor.get helper method to support ColorStyles.
* Pubspec.yaml dependency updates
## [6.4.0] - 2023-01-06
* Upgrade to Nylo v4.0.0
* Update copyright
* Refactor wp_json_api metadata
* Pubspec.yaml dependency updates
## [6.3.1] - 2022-11-04
* Fix email address bug in customer_address_input.dart
## [6.3.0] - 2022-11-03
* Ability to add Menu Links to the drawer widget through the WooSignal dashboard
* Fix wording when a shipping zone cannot be found to "Shipping is not supported for your location, sorry"
* Update account shipping widget to be uniform with the checkout shipping widget
* When logged in, the `CheckoutDetailsPage` will now populate shipping info from the users account
* Small refactor to resources/pages
* Pubspec.yaml dependency updates
## [6.2.0] - 2022-09-23
* Migration to use Nylo v3.4.0
* Pubspec.yaml dependency updates
* Increase the minimum targetSdkVersion to 31
* Merge #51, #50, #47, #40, #39 and #38 by @jeanmatthieud
* UI changes to the search page for a nicer experience
* More translations added throughout the app
## [6.1.0] - 2022-07-09
* Add RazorPay
* Null safety tweaks to widgets
* Ability for users to delete their accounts using WP_JSON
* Pubspec.yaml dependency updates
## [6.0.0] - 2022-05-19
* Migrate to Nylo 3.x
* Null safety
* Min dart version 2.17
* Refactor product detail screen
* Pubspec.yaml dependency updates
## [5.8.0] - 2022-03-29 ## [5.8.0] - 2022-03-29
* Add phone number to customer input form * Add phone number to customer input form

View File

@ -1,6 +1,6 @@
BSD 2-Clause License BSD 2-Clause License
Copyright (c) 2022, WooSignal Ltd Copyright (c) 2023, WooSignal Ltd
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

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

View File

@ -30,7 +30,7 @@ android {
exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/DEPENDENCIES'
} }
compileSdkVersion 31 compileSdkVersion 33
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
@ -44,7 +44,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.woosignal.android" applicationId "com.woosignal.android"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 33
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
multiDexEnabled true multiDexEnabled true

View File

@ -12,7 +12,7 @@
<application <application
android:name="${applicationName}" android:name="${applicationName}"
android:label="Label StoreMax" android:label="Raster Knjizara"
android:icon="@mipmap/launcher_icon"> android:icon="@mipmap/launcher_icon">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
@ -21,7 +21,8 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize"
android:exported="true">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
@ -30,15 +31,7 @@
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme"
/> />
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,12 +1,12 @@
buildscript { buildscript {
ext.kotlin_version = '1.6.10' ext.kotlin_version = '1.7.10'
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.0.1' classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
task clean(type: Delete) { tasks.register("clean", Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>9.0</string> <string>11.0</string>
</dict> </dict>
</plist> </plist>

49
LabelStoreMax/ios/Podfile Normal file
View File

@ -0,0 +1,49 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.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 flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
installer.generated_projects.each do |project|
project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
end
end

View File

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 51; objectVersion = 54;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -155,7 +155,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1300; LastUpgradeCheck = 1430;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
@ -199,10 +199,12 @@
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (
@ -213,6 +215,7 @@
}; };
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
@ -370,6 +373,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app; PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -508,6 +512,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app; PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@ -540,6 +545,7 @@
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/Flutter", "$(PROJECT_DIR)/Flutter",
); );
MARKETING_VERSION = 1.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app; PRODUCT_BUNDLE_IDENTIFIER = com.flutter.app;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1300" LastUpgradeVersion = "1430"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
@ -15,13 +17,9 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string> <string>$(MARKETING_VERSION)</string>
<key>NSCameraUsageDescription</key>
<string>You can take photos of your payment details.</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
@ -36,14 +34,20 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>MinimumOSVersion</key>
<string>13.0</string>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoads</key> <key>NSAllowsArbitraryLoads</key>
<true/> <true/>
</dict> </dict>
<key>NSCameraUsageDescription</key>
<string>You can take photos of your payment details.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "Der Versand wird für Ihr Land leider nicht unterstützt", "Shipping is not supported for your country, sorry": "Der Versand wird für Ihr Land leider nicht unterstützt",
"Search": "Suche", "Search": "Suche",
"Debit or Credit Card": "Debit- oder Kreditkarte", "Debit or Credit Card": "Debit- oder Kreditkarte",
"Cash on delivery": "Barzahlung bei Lieferung",
"Oops, something went wrong": "Ups! Irgendwas lief schief", "Oops, something went wrong": "Ups! Irgendwas lief schief",
"Tax": "MwSt", "Tax": "MwSt",
"No results": "Keine Ergebnisse", "No results": "Keine Ergebnisse",
@ -219,5 +220,14 @@
"Leave a review": "Hinterlassen Sie eine Bewertung", "Leave a review": "Hinterlassen Sie eine Bewertung",
"How would you rate": "Wie beurteilen Sie", "How would you rate": "Wie beurteilen Sie",
"Submit": "einreichen", "Submit": "einreichen",
"Your review has been submitted": "Ihre Bewertung wurde übermittelt" "Your review has been submitted": "Ihre Bewertung wurde übermittelt",
"Delete Account": "Konto löschen",
"Phone Number": "Telefonnummer",
"Delete your account": "Lösche deinen Account",
"Are you sure?": "Bist du dir sicher?",
"Yes, delete my account": "Ja, lösche mein Konto",
"Account deleted": "Konto gelöscht",
"Shipping is not supported for your location, sorry": "Der Versand wird für Ihren Standort nicht unterstützt, tut mir leid",
"Order Summary": "Bestellübersicht",
"By completing this order, I agree to all": "Mit Abschluss dieser Bestellung stimme ich allem zu"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "Shipping is not supported for your country, sorry", "Shipping is not supported for your country, sorry": "Shipping is not supported for your country, sorry",
"Search": "Search", "Search": "Search",
"Debit or Credit Card": "Debit or Credit Card", "Debit or Credit Card": "Debit or Credit Card",
"Cash on delivery": "Cash on delivery",
"Oops, something went wrong": "Oops, something went wrong", "Oops, something went wrong": "Oops, something went wrong",
"Tax": "Tax", "Tax": "Tax",
"No results": "No results", "No results": "No results",
@ -219,5 +220,14 @@
"Leave a review": "Leave a review", "Leave a review": "Leave a review",
"How would you rate": "How would you rate", "How would you rate": "How would you rate",
"Submit": "Submit", "Submit": "Submit",
"Your review has been submitted": "Your review has been submitted" "Your review has been submitted": "Your review has been submitted",
"Delete Account": "Delete Account",
"Phone Number": "Phone Number",
"Delete your account": "Delete your account",
"Are you sure?": "Are you sure?",
"Yes, delete my account": "Yes, delete my account",
"Account deleted": "Account deleted",
"Shipping is not supported for your location, sorry": "Shipping is not supported for your location, sorry",
"Order Summary": "Order Summary",
"By completing this order, I agree to all": "By completing this order, I agree to all"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "El envío no es compatible con su país, lo siento", "Shipping is not supported for your country, sorry": "El envío no es compatible con su país, lo siento",
"Search": "Buscar", "Search": "Buscar",
"Debit or Credit Card": "Tarjeta de débito o crédito", "Debit or Credit Card": "Tarjeta de débito o crédito",
"Cash on delivery": "Contra reembolso",
"Oops, something went wrong": "Huy! Algo salió mal", "Oops, something went wrong": "Huy! Algo salió mal",
"Tax": "Impuesto", "Tax": "Impuesto",
"No results": "No hay resultados", "No results": "No hay resultados",
@ -219,5 +220,14 @@
"Leave a review": "Dejar un comentario", "Leave a review": "Dejar un comentario",
"How would you rate": "Cómo calificarías", "How would you rate": "Cómo calificarías",
"Submit": "Entregar", "Submit": "Entregar",
"Your review has been submitted": "Tu reseña ha sido enviada" "Your review has been submitted": "Tu reseña ha sido enviada",
"Delete Account": "Borrar cuenta",
"Phone Number": "Número de teléfono",
"Delete your account": "eliminar su cuenta",
"Are you sure?": "¿Está seguro?",
"Yes, delete my account": "Sí, eliminar mi cuenta",
"Account deleted": "Cuenta borrada",
"Shipping is not supported for your location, sorry": "El envío no es compatible para su ubicación, lo siento",
"Order Summary": "Resumen del pedido",
"By completing this order, I agree to all": "Al completar este pedido, acepto todos"
} }

View File

@ -1,19 +1,19 @@
{ {
"Categories": "Les catégories", "Categories": "Catégories",
"Shop": "Boutique", "Shop": "Boutique",
"Newest": "Le plus récent", "Newest": "Le plus récent",
"Browse categories": "Parcourir les catégories", "Browse categories": "Parcourir les catégories",
"Cart": "Chariot", "Cart": "Panier",
"You need items in your cart to checkout": "Vous avez besoin d'articles dans votre panier pour passer à la caisse", "You need items in your cart to checkout": "Ajoutez d'abord des articles à votre panier !",
"Updated": "Mise à jour", "Updated": "Mise à jour",
"Item removed": "Élément supprimé", "Item removed": "Élément supprimé",
"Success": "Succès", "Success": "C'est fait !",
"Cart cleared": "Panier effacé", "Cart cleared": "Panier vidé",
"Shopping Cart": "Panier", "Shopping Cart": "Panier",
"Clear Cart": "Vider le panier", "Clear Cart": "Vider le panier",
"Empty Basket": "Panier vide", "Empty Basket": "Panier vide",
"PROCEED TO CHECKOUT": "PASSER À LA CAISSE", "PROCEED TO CHECKOUT": "PASSER AU PAIEMENT",
"Browse": "Feuilleter", "Browse": "Parcourir",
"Search results for": "Résultats de recherche pour", "Search results for": "Résultats de recherche pour",
"Select a": "Sélectionner un", "Select a": "Sélectionner un",
"Added to cart": "Ajouté au panier", "Added to cart": "Ajouté au panier",
@ -22,53 +22,53 @@
"Choose your options": "Choisissez vos options", "Choose your options": "Choisissez vos options",
"Out of stock": "En rupture de stock", "Out of stock": "En rupture de stock",
"In Stock": "En stock", "In Stock": "En stock",
"Add to cart": "Ajouter au chariot", "Add to cart": "Ajouter au panier",
"Oops": "Oops", "Oops": "Oups",
"Please select valid options first": "Veuillez d'abord sélectionner les options valides", "Please select valid options first": "Veuillez d'abord sélectionner les options valides",
"Sorry": "Désolé", "Sorry": "Désolé",
"This item is not in stock": "Cet article n'est pas en réserve", "This item is not in stock": "Cet article n'est pas en stock",
"Description": "La description", "Description": "Description",
"Full description": "Description complète", "Full description": "Description complète",
"ADD TO CART": "AJOUTER AU CHARIOT", "ADD TO CART": "AJOUTER AU PANIER",
"This item is out of stock": "L'article n'est plus en stock", "This item is out of stock": "L'article n'est plus en stock",
"Add your shipping details first": "Ajoutez d'abord vos détails d'expédition", "Add your shipping details first": "Ajoutez d'abord vos informations d'expédition",
"Checkout": "Check-out", "Checkout": "Commander",
"Billing/shipping details": "Détails de facturation / expédition", "Billing/shipping details": "Détails de facturation / expédition",
"Add billing & shipping details": "Ajouter les détails de facturation et d'expédition", "Add billing & shipping details": "Ajouter les détails de facturation et d'expédition",
"Payment method": "Mode de paiement", "Payment method": "Mode de paiement",
"Pay with": "Payer avec", "Pay with": "Payer avec",
"Select a payment method": "Choisissez une méthode de paiement", "Select a payment method": "Choisissez une méthode de paiement",
"Shipping selected": "Livraison sélectionnée", "Shipping selected": "Livraison sélectionnée",
"Select shipping": "Sélectionnez Livraison", "Select shipping": "Sélectionnez le mode de livraison",
"Select a shipping option": "Sélectionnez une option d'expédition", "Select a shipping option": "Sélectionnez une option d'expédition",
"Shipping fee": "Frais d'expédition", "Shipping fee": "Frais d'expédition",
"Subtotal": "Total", "Subtotal": "Total",
"Total": "Total", "Total": "Total",
"CHECKOUT": "CHECK-OUT", "CHECKOUT": "COMMANDER",
"One moment": "Un moment", "One moment": "Veuillez patienter",
"Please select add your billing/shipping address to proceed": "Veuillez sélectionner ajouter votre adresse de facturation / expédition pour continuer", "Please select add your billing/shipping address to proceed": "Veuillez sélectionner ajouter votre adresse de facturation / expédition pour continuer",
"Your billing/shipping details are incomplete": "Vos coordonnées de facturation / expédition sont incomplètes", "Your billing/shipping details are incomplete": "Vos coordonnées de facturation / expédition sont incomplètes",
"Please select a shipping method to proceed": "Veuillez sélectionner une méthode d'expédition pour continuer", "Please select a shipping method to proceed": "Veuillez sélectionner une méthode d'expédition pour continuer",
"Please select a payment method to proceed": "Veuillez sélectionner un mode de paiement pour continuer", "Please select a payment method to proceed": "Veuillez sélectionner un mode de paiement pour continuer",
"Something went wrong, please contact our store": "Quelque chose s'est mal passé, veuillez contacter notre magasin", "Something went wrong, please contact our store": "Quelque chose s'est mal passé, veuillez contacter notre équipe",
"Error": "Erreur", "Error": "Erreur",
"Order Status": "Statut de la commande", "Order Status": "Statut de la commande",
"Thank You!": "Merci!", "Thank You!": "Merci !",
"Your transaction details": "Vos détails de transaction", "Your transaction details": "Vos détails de transaction",
"Order Ref": "Réf commande", "Order Ref": "Réf commande",
"Items": "Articles", "Items": "Articles",
"Back to Home": "De retour à la maison", "Back to Home": "Retourner à l'accueil",
"Orders": "Ordres", "Orders": "Commandes",
"Billing & Shipping Details": "Détails de facturation et d'expédition", "Billing & Shipping Details": "Détails de facturation et d'expédition",
"First Name": "Prénom", "First Name": "Prénom",
"Last Name": "Nom de famille", "Last Name": "Nom de famille",
"Address Line": "Ligne d'adresse", "Address Line": "Adresse",
"City": "Ville", "City": "Ville",
"Postal code": "Code postal", "Postal code": "Code postal",
"Email address": "Adresse électronique", "Email address": "Adresse électronique",
"Selected": "Choisi", "Selected": "Sélectionné",
"Select country": "Choisissez le pays", "Select country": "Choisissez le pays",
"Remember my details": "Rappelez-vous mes coordonnées", "Remember my details": "Retenir mes coordonnées",
"USE SHIPPING ADDRESS": "UTILISER L'ADRESSE D'EXPÉDITION", "USE SHIPPING ADDRESS": "UTILISER L'ADRESSE D'EXPÉDITION",
"About": "À propos de", "About": "À propos de",
"Privacy policy": "Politique de confidentialité", "Privacy policy": "Politique de confidentialité",
@ -76,12 +76,13 @@
"Version": "Version", "Version": "Version",
"Payment Method": "Mode de paiement", "Payment Method": "Mode de paiement",
"CANCEL": "ANNULER", "CANCEL": "ANNULER",
"Shipping Methods": "méthodes de livraison", "Shipping Methods": "Méthodes de livraison",
"Shipping is not supported for your country, sorry": "La livraison n'est pas prise en charge pour votre pays, désolé", "Shipping is not supported for your country, sorry": "La livraison n'est pas prise en charge pour votre pays, désolé",
"Search": "Chercher", "Search": "Chercher",
"Debit or Credit Card": "Carte de débit ou de crédit", "Debit or Credit Card": "Carte de débit ou de crédit",
"Cash on delivery": "Paiement à la livraison",
"Oops, something went wrong": "Oups, quelque chose s'est mal passé", "Oops, something went wrong": "Oups, quelque chose s'est mal passé",
"Tax": "Impôt", "Tax": "TVA",
"No results": "Aucun résultat", "No results": "Aucun résultat",
"There is an item out of stock": "Il y a un article en rupture de stock", "There is an item out of stock": "Il y a un article en rupture de stock",
"Maximum stock reached": "Stock maximum atteint", "Maximum stock reached": "Stock maximum atteint",
@ -98,35 +99,35 @@
"Create an account": "Créer un compte", "Create an account": "Créer un compte",
"Login": "S'identifier", "Login": "S'identifier",
"Password": "Mot de passe", "Password": "Mot de passe",
"Oops!": "Oops!", "Oops!": "Oups !",
"Invalid login credentials": "Authentification invalide", "Invalid login credentials": "Authentification invalide",
"That email address is not valid": "Cette adresse e-mail n'est pas valide", "That email address is not valid": "Cette adresse e-mail n'est pas valide",
"Password must be a min 6 characters": "Le mot de passe doit contenir au moins 6 caractères", "Password must be a min 6 characters": "Le mot de passe doit contenir au moins 6 caractères",
"Please check your details": "S'il vous plaît vérifier vos informations", "Please check your details": "Veuillez vérifier vos informations",
"Invalid": "Invalide", "Invalid": "Invalide",
"Actions": "Actions", "Actions": "Actions",
"View Terms and Conditions or Privacy policy": "Afficher les conditions générales ou la politique de confidentialité", "View Terms and Conditions or Privacy policy": "Afficher les conditions générales ou la politique de confidentialité",
"Terms and Conditions": "Termes et conditions", "Terms and Conditions": "Mentions légales",
"Privacy Policy": "Politique de confidentialité", "Privacy Policy": "Politique de confidentialité",
"terms and conditions": "Termes et conditions", "terms and conditions": "mentions légales",
"and": "et", "and": "et",
"By tapping \"Register\" you agree to ": "En appuyant sur \"S'inscrire\", vous acceptez de ", "By tapping \"Register\" you agree to ": "En appuyant sur \"S'inscrire\", vous acceptez de ",
"privacy policy": "politique de confidentialité", "privacy policy": "politique de confidentialité",
"Sign up": "S'inscrire", "Sign up": "S'inscrire",
"Email": "Email", "Email": "Email",
"Update details": "Mettre à jour les détails", "Update details": "Informations personnelles",
"Settings": "Réglages", "Settings": "Paramètres",
"Account": "Compte", "Account": "Compte",
"Logout": "Se déconnecter", "Logout": "Se déconnecter",
"No orders found": "Aucune commande trouvée", "No orders found": "Aucune commande trouvée",
"items": "articles", "items": "articles",
"Update Details": "Détails de mise à jour", "Update Details": "Mettre à jour les informations",
"Invalid details": "Détails invalides", "Invalid details": "Informations invalides",
"Please check your email and password": "Veuillez vérifier votre e-mail et votre mot de passe", "Please check your email and password": "Veuillez vérifier votre e-mail et votre mot de passe",
"Something went wrong, please try again.": "Une erreur s'est produite. Veuillez réessayer.", "Something went wrong, please try again.": "Une erreur s'est produite. Veuillez réessayer.",
"Done": "Terminé", "Done": "Terminé",
"Billing Details": "Détails de la facturation", "Billing Details": "Facturation",
"Shipping Details": "Les détails d'expédition", "Shipping Details": "Expédition",
"Shipping Address": "Adresse de livraison", "Shipping Address": "Adresse de livraison",
"State": "Etat", "State": "Etat",
"Country": "Pays", "Country": "Pays",
@ -143,14 +144,14 @@
"Sort results": "Trier les résultats", "Sort results": "Trier les résultats",
"you're now logged in": "Vous êtes maintenant connecté", "you're now logged in": "Vous êtes maintenant connecté",
"Hello": "Bonjour", "Hello": "Bonjour",
"Welcome back": "Nous saluons le retour", "Welcome back": "Content de vous revoir",
"Quantity": "Quantité", "Quantity": "Quantité",
"Select a state": "Sélectionner un état", "Select a state": "Sélectionner un état",
"Select state": "Sélectionnez l'état", "Select state": "Sélectionnez l'état",
"Ship to a different address?": "Expédier à une adresse différente?", "Ship to a different address?": "Expédier à une adresse différente?",
"USE DETAILS": "DÉTAILS D'UTILISATION", "USE DETAILS": "METTRE À JOUR",
"Not supported, try a card payment": "Non pris en charge, essayez un paiement par carte", "Not supported, try a card payment": "Non pris en charge, essayez un paiement par carte",
"Invalid shipping address, please check your shipping details": "Adresse de livraison non valide, veuillez vérifier vos détails de livraison", "Invalid shipping address, please check your shipping details": "Adresse de livraison non valide, veuillez vérifier vos infos de livraison",
"Was": "Était", "Was": "Était",
"off": "de", "off": "de",
"Maximum quantity reached": "Quantité maximale atteinte", "Maximum quantity reached": "Quantité maximale atteinte",
@ -168,14 +169,14 @@
"A user already exists": "Un utilisateur existe déjà", "A user already exists": "Un utilisateur existe déjà",
"That email is taken, try another": "Cet e-mail est pris, essayez un autre", "That email is taken, try another": "Cet e-mail est pris, essayez un autre",
"The email field is empty": "Le champ e-mail est vide", "The email field is empty": "Le champ e-mail est vide",
"No more orders": "Plus de commandes", "No more orders": "Pas plus de commandes",
"Account updated": "Compte mis à jour", "Account updated": "Compte mis à jour",
"Spend a minimum of": "Dépensez un minimum de", "Spend a minimum of": "Dépensez un minimum de",
"for": "pour", "for": "pour",
"Buy Product": "Acheter un produit", "Buy Product": "Acheter un produit",
"Retry": "Recommencez", "Retry": "Recommencez",
"Retry later": "Réessayer plus tard", "Retry later": "Réessayer plus tard",
"Light Mode": "Mode lumière", "Light Mode": "Mode clair",
"Dark Mode": "Mode sombre", "Dark Mode": "Mode sombre",
"PayPal Checkout": "Paiement PayPal", "PayPal Checkout": "Paiement PayPal",
"Processing Payment": "Traitement du paiement", "Processing Payment": "Traitement du paiement",
@ -183,26 +184,26 @@
"If you are not automatically redirected to PayPal within 5 seconds": "Si vous n'etes pas automatiquement redirige vers PayPal dans les 5 secondes", "If you are not automatically redirected to PayPal within 5 seconds": "Si vous n'etes pas automatiquement redirige vers PayPal dans les 5 secondes",
"Payment Cancelled": "Paiement annulé", "Payment Cancelled": "Paiement annulé",
"The payment has been cancelled": "Le paiement a été annulé", "The payment has been cancelled": "Le paiement a été annulé",
"Must have": "Doit avoir", "Must have": "Produits à voir",
"Our selection of new items": "Notre sélection de nouveautés", "Our selection of new items": "Notre sélection de nouveautés",
"Register": "S'inscrire", "Register": "S'inscrire",
"No payment methods are available": "Aucun mode de paiement n'est disponible", "No payment methods are available": "Aucun mode de paiement n'est disponible",
"Please enter a valid billing email": "Veuillez saisir une adresse e-mail de facturation valide", "Please enter a valid billing email": "Veuillez saisir une adresse e-mail de facturation valide",
"Please enter a valid shipping email": "Veuillez saisir un e-mail de livraison valide", "Please enter a valid shipping email": "Veuillez saisir un e-mail de livraison valide",
"Free postage": "Sans frais de port", "Free postage": "Frais de port offerts",
"PROCESSING": "EN TRAITEMENT", "PROCESSING": "EN TRAITEMENT",
"Social": "Social", "Social": "Social",
"Please enter coupon to redeem": "Veuillez entrer le coupon pour l'utiliser", "Please enter coupon to redeem": "Veuillez entrer le code promo pour l'utiliser",
"Coupon": "Coupon", "Coupon": "Code promo",
"Apply": "Appliquer", "Apply": "Appliquer",
"Apply Coupon": "Appliquer Coupon", "Apply Coupon": "Appliquer code promo",
"Added to checkout": "Ajouté à la caisse", "Added to checkout": "Ajouté au panier",
"Redeem Coupon": "Échanger le coupon", "Redeem Coupon": "Échanger le code promo",
"Add coupon code": "Ajouter un code promo", "Add coupon code": "Ajouter un code promo",
"Coupon not found": "Coupon introuvable", "Coupon not found": "Code promo introuvable",
"Sorry, this coupon can not be used with your cart": "Désolé, ce coupon ne peut pas être utilisé avec votre panier", "Sorry, this coupon can not be used with your cart": "Désolé, ce code promo ne peut pas être utilisé avec votre panier",
"You cannot redeem this coupon": "Vous ne pouvez pas utiliser ce coupon", "You cannot redeem this coupon": "Vous ne pouvez pas utiliser ce code promo",
"This coupon has expired": "Ce coupon a expiré", "This coupon has expired": "Ce code promo a expiré",
"Usage limit has been reached": "La limite d'utilisation a été atteinte", "Usage limit has been reached": "La limite d'utilisation a été atteinte",
"View All": "Voir tout", "View All": "Voir tout",
"Wishlist": "Liste de souhaits", "Wishlist": "Liste de souhaits",
@ -213,11 +214,20 @@
"Spend less than maximumAmount to redeem": "Dépensez moins de {{maximumAmount}} de racheter", "Spend less than maximumAmount to redeem": "Dépensez moins de {{maximumAmount}} de racheter",
"Related products": "Produits connexes", "Related products": "Produits connexes",
"Reviews": "Commentaires", "Reviews": "Commentaires",
"There are no reviews yet.": "Il n'y a pas encore de critiques.", "There are no reviews yet.": "Il n'y a pas encore de commentaire.",
"More": "Suite", "More": "Suite",
"You may also like": "Tu pourrais aussi aimer", "You may also like": "Vous pourriez aussi aimer",
"Leave a review": "Laisser un commentaire", "Leave a review": "Laisser un commentaire",
"How would you rate": "Comment évalueriez-vous", "How would you rate": "Comment évalueriez-vous",
"Submit": "Soumettre", "Submit": "Envoyer",
"Your review has been submitted": "Votre avis a été soumis" "Your review has been submitted": "Votre avis a été soumis",
"Delete Account": "Supprimer le compte",
"Phone Number": "Numéro de téléphone",
"Delete your account": "Supprimer votre compte",
"Are you sure?": "Êtes-vous sûr?",
"Yes, delete my account": "Oui, supprimer mon compte",
"Account deleted": "Compte supprimé",
"Shipping is not supported for your location, sorry": "L'expédition n'est pas prise en charge pour votre emplacement, désolé",
"Order Summary": "Récapitulatif de la commande",
"By completing this order, I agree to all": "En remplissant cette commande, j'accepte toutes"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "shiping aapake desh ke lie samarthit nahin hai, kshama karen", "Shipping is not supported for your country, sorry": "shiping aapake desh ke lie samarthit nahin hai, kshama karen",
"Search": "khoj", "Search": "khoj",
"Debit or Credit Card": "debit ya kredit kaard", "Debit or Credit Card": "debit ya kredit kaard",
"Cash on delivery": "dilavaree par nakadee\n",
"Oops, something went wrong": "oh! kuchh galat ho gaya hai", "Oops, something went wrong": "oh! kuchh galat ho gaya hai",
"Tax": "kar", "Tax": "kar",
"No results": "koee parinaam nahin", "No results": "koee parinaam nahin",
@ -219,5 +220,14 @@
"Leave a review": "sameeksha likhen", "Leave a review": "sameeksha likhen",
"How would you rate": "aap ise kya ret karate hain", "How would you rate": "aap ise kya ret karate hain",
"Submit": "prastut karana", "Submit": "prastut karana",
"Your review has been submitted": "aapakee sameeksha jama ho chukee hai" "Your review has been submitted": "aapakee sameeksha jama ho chukee hai",
"Delete Account": "khaata hata do",
"Phone Number": "fon nambar",
"Delete your account": "apane khaate ko nasht karo",
"Are you sure?": "kya aapako yakeen hai?",
"Yes, delete my account": "haan, mera akaunt dileet kar do",
"Account deleted": "khaata hataaya gaya",
"Shipping is not supported for your location, sorry": "aapake sthaan ke lie shiping samarthit nahin hai, kshama karen",
"Order Summary": "aadesh saaraansh",
"By completing this order, I agree to all": "is aadesh ko poora karake, main sabhee ke lie sahamat hoon"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "La spedizione non è supportata per il tuo Paese, mi dispiace", "Shipping is not supported for your country, sorry": "La spedizione non è supportata per il tuo Paese, mi dispiace",
"Search": "Ricerca", "Search": "Ricerca",
"Debit or Credit Card": "Bancomat o carta di credito", "Debit or Credit Card": "Bancomat o carta di credito",
"Cash on delivery": "Pagamento alla consegna",
"Oops, something went wrong": "Oops! Qualcosa è andato storto", "Oops, something went wrong": "Oops! Qualcosa è andato storto",
"Tax": "Imposta", "Tax": "Imposta",
"No results": "Nessun risultato", "No results": "Nessun risultato",
@ -219,5 +220,14 @@
"Leave a review": "Lascia una recensione", "Leave a review": "Lascia una recensione",
"How would you rate": "Come valuteresti", "How would you rate": "Come valuteresti",
"Submit": "Invia", "Submit": "Invia",
"Your review has been submitted": "La tua recensione è stata inviata" "Your review has been submitted": "La tua recensione è stata inviata",
"Delete Account": "Eliminare l'account",
"Phone Number": "Numero di telefono",
"Delete your account": "cancella il tuo account",
"Are you sure?": "Sei sicuro?",
"Yes, delete my account": "Sì, elimina il mio account",
"Account deleted": "Account cancellato",
"Shipping is not supported for your location, sorry": "La spedizione non è supportata per la tua posizione, mi dispiace",
"Order Summary": "Riepilogo dell'ordine",
"By completing this order, I agree to all": "Completando questo ordine, accetto tutto"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "Verzending wordt niet ondersteund voor uw land, sorry", "Shipping is not supported for your country, sorry": "Verzending wordt niet ondersteund voor uw land, sorry",
"Search": "Zoekopdracht", "Search": "Zoekopdracht",
"Debit or Credit Card": "Debet- of creditcard", "Debit or Credit Card": "Debet- of creditcard",
"Cash on delivery": "Onder rembours",
"Oops, something went wrong": "Oeps! Er is iets misgegaan", "Oops, something went wrong": "Oeps! Er is iets misgegaan",
"Tax": "Belasting", "Tax": "Belasting",
"No results": "Geen resultaten", "No results": "Geen resultaten",
@ -219,5 +220,14 @@
"Leave a review": "Laat je mening achter", "Leave a review": "Laat je mening achter",
"How would you rate": "Hoe zou jij beoordelen", "How would you rate": "Hoe zou jij beoordelen",
"Submit": "Indienen", "Submit": "Indienen",
"Your review has been submitted": "Uw beoordeling is verzonden" "Your review has been submitted": "Uw beoordeling is verzonden",
"Delete Account": "Account verwijderen",
"Phone Number": "Telefoonnummer",
"Delete your account": "Verwijder je account",
"Are you sure?": "Weet je het zeker?",
"Yes, delete my account": "Ja, verwijder mijn account",
"Account deleted": "Account verwijderd",
"Shipping is not supported for your location, sorry": "Verzending wordt niet ondersteund voor uw locatie, sorry",
"Order Summary": "Overzicht van de bestelling",
"By completing this order, I agree to all": "Door deze bestelling te voltooien, ga ik akkoord met alles"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "O envio não é suportado pelo seu país, desculpe", "Shipping is not supported for your country, sorry": "O envio não é suportado pelo seu país, desculpe",
"Search": "Procurar", "Search": "Procurar",
"Debit or Credit Card": "Cartão de Débito ou Crédito", "Debit or Credit Card": "Cartão de Débito ou Crédito",
"Cash on delivery": "Dinheiro na entrega",
"Oops, something went wrong": "Ops, algo deu errado", "Oops, something went wrong": "Ops, algo deu errado",
"Tax": "Imposto", "Tax": "Imposto",
"No results": "Sem resultados", "No results": "Sem resultados",
@ -219,5 +220,14 @@
"Leave a review": "Deixe um comentário", "Leave a review": "Deixe um comentário",
"How would you rate": "Como você avaliaria", "How would you rate": "Como você avaliaria",
"Submit": "Enviar", "Submit": "Enviar",
"Your review has been submitted": "Sua avaliação foi enviada" "Your review has been submitted": "Sua avaliação foi enviada",
"Delete Account": "Deletar conta",
"Phone Number": "Número de telefone",
"Delete your account": "Deletar sua conta",
"Are you sure?": "Tem certeza?",
"Yes, delete my account": "Sim, excluir minha conta",
"Account deleted": "Conta excluída",
"Shipping is not supported for your location, sorry": "O envio não é suportado para a sua localização, desculpe",
"Order Summary": "Resumo do pedido",
"By completing this order, I agree to all": "Ao concluir este pedido, concordo com todos"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "Ülkeniz için gönderim desteklenmiyor, üzgünüm", "Shipping is not supported for your country, sorry": "Ülkeniz için gönderim desteklenmiyor, üzgünüm",
"Search": "Aramak", "Search": "Aramak",
"Debit or Credit Card": "Banka veya Kredi Kartı", "Debit or Credit Card": "Banka veya Kredi Kartı",
"Cash on delivery": "Kapıda ödeme",
"Oops, something went wrong": "Hoop! Birşeyler yanlış gitti", "Oops, something went wrong": "Hoop! Birşeyler yanlış gitti",
"Tax": "Vergi", "Tax": "Vergi",
"No results": "Sonuç yok", "No results": "Sonuç yok",
@ -219,5 +220,14 @@
"Leave a review": "İnceleme bırak", "Leave a review": "İnceleme bırak",
"How would you rate": "Nasıl değerlendirirsiniz", "How would you rate": "Nasıl değerlendirirsiniz",
"Submit": "Göndermek", "Submit": "Göndermek",
"Your review has been submitted": "İncelemeniz gönderildi" "Your review has been submitted": "İncelemeniz gönderildi",
"Delete Account": "Hesabı sil",
"Phone Number": "Telefon numarası",
"Delete your account": "Hesabını sil",
"Are you sure?": "Emin misin?",
"Yes, delete my account": "Evet, hesabımı sil",
"Account deleted": "Hesap silindi",
"Shipping is not supported for your location, sorry": "Bulunduğunuz yer için gönderim desteklenmiyor, üzgünüm",
"Order Summary": "Sipariş özeti",
"By completing this order, I agree to all": "Bu siparişi tamamlayarak, tümünü kabul ediyorum"
} }

View File

@ -80,6 +80,7 @@
"Shipping is not supported for your country, sorry": "您所在的国家/地区不支持运输,抱歉", "Shipping is not supported for your country, sorry": "您所在的国家/地区不支持运输,抱歉",
"Search": "搜索", "Search": "搜索",
"Debit or Credit Card": "借记卡或信用卡", "Debit or Credit Card": "借记卡或信用卡",
"Cash on delivery": "货到付款",
"Oops, something went wrong": "哎呀!出事了", "Oops, something went wrong": "哎呀!出事了",
"Tax": "税", "Tax": "税",
"No results": "没结果", "No results": "没结果",
@ -219,5 +220,14 @@
"Leave a review": "发表评论", "Leave a review": "发表评论",
"How would you rate": "你如何评价", "How would you rate": "你如何评价",
"Submit": "提交", "Submit": "提交",
"Your review has been submitted": "您的评论已提交" "Your review has been submitted": "您的评论已提交",
"Delete Account": "删除帐户",
"Phone Number": "电话号码",
"Delete your account": "删除您的帐户",
"Are you sure?": "你确定吗?",
"Yes, delete my account": "是的,删除我的帐户",
"Account deleted": "帐号已删除",
"Shipping is not supported for your location, sorry": "您所在的位置不支持送货,抱歉",
"Order Summary": "订单摘要",
"By completing this order, I agree to all": "通过完成此订单,我同意所有"
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,14 +1,14 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:nylo_support/controllers/controller.dart'; import 'package:nylo_framework/nylo_framework.dart';
/// Base Controller for the Nylo /// Base Controller for the Nylo
/// See more on controllers here - https://nylo.dev/docs/2.x/controllers /// See more on controllers here - https://nylo.dev/docs/2.x/controllers

View File

@ -1,14 +1,12 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/order.dart'; import 'package:woosignal/models/response/order.dart';
@ -17,9 +15,9 @@ class CustomerOrdersLoaderController
CustomerOrdersLoaderController(); CustomerOrdersLoaderController();
Future<void> loadOrders( Future<void> loadOrders(
{@required bool Function(bool hasProducts) hasResults, {required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish, required void Function() didFinish,
@required String userId}) async { required String userId}) async {
await load( await load(
hasResults: hasResults, hasResults: hasResults,
didFinish: didFinish, didFinish: didFinish,

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -12,10 +12,8 @@ import 'controller.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class LeaveReviewController extends Controller { class LeaveReviewController extends Controller {
@override @override
construct(BuildContext context) { construct(BuildContext context) {
super.construct(context); super.construct(context);
} }
} }

View File

@ -1,36 +1,35 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/product_category.dart'; import 'package:woosignal/models/response/product_category.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductCategorySearchLoaderController class ProductCategorySearchLoaderController
extends WooSignalApiLoaderController<Product> { extends WooSignalApiLoaderController<Product> {
ProductCategorySearchLoaderController(); ProductCategorySearchLoaderController();
Future<void> loadProducts( Future<void> loadProducts(
{@required bool Function(bool hasProducts) hasResults, {required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish, required void Function() didFinish,
@required ProductCategory productCategory}) async { required ProductCategory? productCategory}) async {
await load( await load(
hasResults: hasResults, hasResults: hasResults,
didFinish: didFinish, didFinish: didFinish,
apiQuery: (api) => api.getProducts( apiQuery: (api) => api.getProducts(
perPage: 50, perPage: 50,
category: productCategory.id.toString(), category: productCategory!.id.toString(),
page: page, page: page,
status: "publish", status: "publish",
stockStatus: "instock", stockStatus: "instock",
), ),
); );
} }
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,46 +14,48 @@ import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart'; import 'package:flutter_app/bootstrap/enums/wishlist_action_enums.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/product_variation.dart' import 'package:woosignal/models/response/product_variation.dart'
as ws_product_variation; as ws_product_variation;
import 'controller.dart'; import 'controller.dart';
class ProductDetailController extends Controller { class ProductDetailController extends Controller {
int quantity = 1; int quantity = 1;
Product product; Product? product;
@override @override
construct(BuildContext context) { construct(BuildContext context) {
super.construct(context); super.construct(context);
product = data() as Product; product = data() as Product?;
} }
viewExternalProduct() { viewExternalProduct() {
if (product.externalUrl != null && product.externalUrl.isNotEmpty) { if (product!.externalUrl != null && product!.externalUrl!.isNotEmpty) {
openBrowserTab(url: product.externalUrl); openBrowserTab(url: product!.externalUrl!);
} }
} }
itemAddToCart({@required CartLineItem cartLineItem, @required Function onSuccess}) async { itemAddToCart(
{required CartLineItem cartLineItem, required Function onSuccess}) async {
await Cart.getInstance.addToCart(cartLineItem: cartLineItem); await Cart.getInstance.addToCart(cartLineItem: cartLineItem);
showStatusAlert(context, showStatusAlert(
title: trans("Success"), context,
subtitle: trans("Added to cart"), title: trans("Success"),
duration: 1, subtitle: trans("Added to cart"),
icon: Icons.add_shopping_cart, duration: 1,
icon: Icons.add_shopping_cart,
); );
onSuccess(); onSuccess();
} }
addQuantityTapped({@required Function onSuccess}) { addQuantityTapped({required Function onSuccess}) {
if (product.manageStock != null && product.manageStock == true) { if (product!.manageStock != null && product!.manageStock == true) {
if (quantity >= product.stockQuantity) { if (quantity >= product!.stockQuantity!) {
showToastNotification(context, showToastNotification(context!,
title: trans("Maximum quantity reached"), title: trans("Maximum quantity reached"),
description: description:
"${trans("Sorry, only")} ${product.stockQuantity} ${trans("left")}", "${trans("Sorry, only")} ${product!.stockQuantity} ${trans("left")}",
style: ToastNotificationStyleType.INFO); style: ToastNotificationStyleType.INFO);
return; return;
} }
@ -64,14 +66,16 @@ class ProductDetailController extends Controller {
} }
} }
removeQuantityTapped({@required Function onSuccess}) { removeQuantityTapped({required Function onSuccess}) {
if ((quantity - 1) >= 1) { if ((quantity - 1) >= 1) {
quantity--; quantity--;
onSuccess(); onSuccess();
} }
} }
toggleWishList({@required Function onSuccess, @required WishlistAction wishlistAction}) async { toggleWishList(
{required Function onSuccess,
required WishlistAction wishlistAction}) async {
String subtitleMsg; String subtitleMsg;
if (wishlistAction == WishlistAction.remove) { if (wishlistAction == WishlistAction.remove) {
await removeWishlistProduct(product: product); await removeWishlistProduct(product: product);
@ -80,7 +84,8 @@ class ProductDetailController extends Controller {
await saveWishlistProduct(product: product); await saveWishlistProduct(product: product);
subtitleMsg = trans("This product has been added to your wishlist"); subtitleMsg = trans("This product has been added to your wishlist");
} }
showStatusAlert(context, showStatusAlert(
context,
title: trans("Success"), title: trans("Success"),
subtitle: subtitleMsg, subtitle: subtitleMsg,
icon: Icons.favorite, icon: Icons.favorite,
@ -90,18 +95,18 @@ class ProductDetailController extends Controller {
onSuccess(); onSuccess();
} }
ws_product_variation.ProductVariation findProductVariation( ws_product_variation.ProductVariation? findProductVariation(
{@required Map<int, dynamic> tmpAttributeObj, {required Map<int, dynamic> tmpAttributeObj,
@required List<ws_product_variation.ProductVariation> productVariations}) { required List<ws_product_variation.ProductVariation> productVariations}) {
ws_product_variation.ProductVariation tmpProductVariation; ws_product_variation.ProductVariation? tmpProductVariation;
Map<String, dynamic> tmpSelectedObj = {}; Map<String?, dynamic> tmpSelectedObj = {};
for (var attributeObj in tmpAttributeObj.values) { for (var attributeObj in tmpAttributeObj.values) {
tmpSelectedObj[attributeObj["name"]] = attributeObj["value"]; tmpSelectedObj[attributeObj["name"]] = attributeObj["value"];
} }
for (var productVariation in productVariations) { for (var productVariation in productVariations) {
Map<String, dynamic> tmpVariations = {}; Map<String?, dynamic> tmpVariations = {};
for (var attr in productVariation.attributes) { for (var attr in productVariation.attributes) {
tmpVariations[attr.name] = attr.option; tmpVariations[attr.name] = attr.option;
@ -114,4 +119,4 @@ class ProductDetailController extends Controller {
return tmpProductVariation; return tmpProductVariation;
} }
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,25 +1,23 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductLoaderController extends WooSignalApiLoaderController<Product> { class ProductLoaderController extends WooSignalApiLoaderController<Product> {
ProductLoaderController(); ProductLoaderController();
Future<void> loadProducts({ Future<void> loadProducts(
@required bool Function(bool hasProducts) hasResults, {required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish, required void Function() didFinish,
List<int> productIds = const [] List<int>? productIds = const []}) async {
}) async {
await load( await load(
hasResults: hasResults, hasResults: hasResults,
didFinish: didFinish, didFinish: didFinish,

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -12,11 +12,8 @@ import 'controller.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class ProductReviewsController extends Controller { class ProductReviewsController extends Controller {
@override @override
construct(BuildContext context) { construct(BuildContext context) {
super.construct(context); super.construct(context);
} }
}
}

View File

@ -1,34 +1,34 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/product_review.dart'; import 'package:woosignal/models/response/product_review.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductReviewsLoaderController extends WooSignalApiLoaderController<ProductReview> { class ProductReviewsLoaderController
extends WooSignalApiLoaderController<ProductReview> {
ProductReviewsLoaderController(); ProductReviewsLoaderController();
Future<void> loadProductReviews({ Future<void> loadProductReviews({
@required Product product, required Product? product,
@required bool Function(bool hasProducts) hasResults, required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish, required void Function() didFinish,
}) async { }) async {
await load( await load(
hasResults: hasResults, hasResults: hasResults,
didFinish: didFinish, didFinish: didFinish,
apiQuery: (api) => api.getProductReviews( apiQuery: (api) => api.getProductReviews(
product: [product.id], product: [product!.id!],
perPage: 50, perPage: 50,
page: page, page: page,
status: "approved", status: "approved",
)); ));
} }
} }

View File

@ -1,25 +1,24 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart'; import 'package:flutter_app/app/controllers/woosignal_api_loader_controller.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
class ProductSearchLoaderController class ProductSearchLoaderController
extends WooSignalApiLoaderController<Product> { extends WooSignalApiLoaderController<Product> {
ProductSearchLoaderController(); ProductSearchLoaderController();
Future<void> loadProducts( Future<void> loadProducts(
{@required bool Function(bool hasProducts) hasResults, {required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish, required void Function() didFinish,
@required String search}) async { required String? search}) async {
await load( await load(
hasResults: hasResults, hasResults: hasResults,
didFinish: didFinish, didFinish: didFinish,

View File

@ -1,14 +1,13 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:woosignal/woosignal.dart'; import 'package:woosignal/woosignal.dart';
@ -20,15 +19,15 @@ class WooSignalApiLoaderController<T> {
WooSignalApiLoaderController(); WooSignalApiLoaderController();
Future<void> load( Future<void> load(
{@required bool Function(bool hasProducts) hasResults, {required bool Function(bool hasProducts) hasResults,
@required void Function() didFinish, required void Function() didFinish,
@required Future<List<T>> Function(WooSignal query) apiQuery}) async { required Future<List<T>> Function(WooSignal query) apiQuery}) async {
if (_waitForNextRequest) { if (_waitForNextRequest) {
return; return;
} }
_waitForNextRequest = true; _waitForNextRequest = true;
List<T> apiResults = await appWooSignal((api) => apiQuery(api)); List<T> apiResults = await (appWooSignal((api) => apiQuery(api)));
if (!hasResults(apiResults.isNotEmpty)) { if (!hasResults(apiResults.isNotEmpty)) {
return; return;
@ -41,9 +40,7 @@ class WooSignalApiLoaderController<T> {
didFinish(); didFinish();
} }
List<T> getResults() { List<T> getResults() => _results;
return _results;
}
void clear() { void clear() {
_results = []; _results = [];

View File

@ -0,0 +1,15 @@
import 'package:nylo_framework/nylo_framework.dart';
class LoginEvent implements NyEvent {
@override
final listeners = {
DefaultListener: DefaultListener(),
};
}
class DefaultListener extends NyListener {
@override
handle(dynamic event) async {
// handle the payload from event
}
}

View File

@ -0,0 +1,13 @@
import 'package:nylo_framework/nylo_framework.dart';
class LogoutEvent implements NyEvent {
@override
final listeners = {DefaultListener: DefaultListener()};
}
class DefaultListener extends NyListener {
@override
handle(dynamic event) async {
// handle the payload from event
}
}

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,12 +11,76 @@
import 'package:flutter_app/app/models/customer_address.dart'; import 'package:flutter_app/app/models/customer_address.dart';
class BillingDetails { class BillingDetails {
CustomerAddress billingAddress; CustomerAddress? billingAddress;
CustomerAddress shippingAddress; CustomerAddress? shippingAddress;
bool rememberDetails; bool? rememberDetails;
BillingDetails();
void initSession() { void initSession() {
billingAddress = CustomerAddress(); billingAddress = CustomerAddress();
shippingAddress = CustomerAddress(); shippingAddress = CustomerAddress();
} }
Map<String, dynamic> createStripeDetails() => {
'address': {
if (billingAddress?.addressLine != null)
'line1': billingAddress?.addressLine,
if (billingAddress?.city != null) 'city': billingAddress?.city,
if (billingAddress?.postalCode != null)
'postal_code': billingAddress?.postalCode,
if (billingAddress?.customerCountry?.state?.name != null)
'state': billingAddress?.customerCountry?.state?.name,
if (billingAddress?.customerCountry?.countryCode != null)
'country': billingAddress?.customerCountry?.countryCode,
},
'shipping': {
if (shippingAddress?.nameFull() != null)
'name': shippingAddress?.nameFull(),
if (shippingAddress?.city != null) 'city': shippingAddress?.city,
if (shippingAddress?.postalCode != null)
'postal_code': shippingAddress?.postalCode,
if (shippingAddress?.customerCountry?.state?.name != null)
'state': shippingAddress?.customerCountry?.state?.name,
if (shippingAddress?.customerCountry?.countryCode != null)
'country': shippingAddress?.customerCountry?.countryCode,
},
if (billingAddress?.emailAddress != null)
'email': billingAddress?.emailAddress,
if (billingAddress?.nameFull() != null)
'name': billingAddress?.nameFull(),
if (billingAddress?.phoneNumber != null)
'phone': billingAddress?.phoneNumber
};
Map<String, String?> getShippingAddressStripe() => {
"name": shippingAddress?.nameFull(),
"line1": shippingAddress!.addressLine,
"city": shippingAddress!.city,
"postal_code": shippingAddress!.postalCode,
"country": (shippingAddress?.customerCountry?.name ?? "")
};
fromWpMeta(Map<String, String> data) async {
final Map<String, String> shippingDetailsWpMeta = <String, String>{},
billingDetailsWpMeta = <String, String>{};
shippingDetailsWpMeta.addEntries(data.entries
.where((element) => element.key.startsWith("shipping_"))
.map((shippingMeta) => MapEntry(
shippingMeta.key.replaceAll("shipping_", ""), shippingMeta.value)));
billingDetailsWpMeta.addEntries(data.entries
.where((element) => element.key.startsWith("billing_"))
.map((billingMeta) => MapEntry(
billingMeta.key.replaceAll("billing_", ""), billingMeta.value)));
CustomerAddress billingCustomerAddress = CustomerAddress();
await billingCustomerAddress.fromWpMetaData(billingDetailsWpMeta);
CustomerAddress shippingCustomerAddress = CustomerAddress();
await shippingCustomerAddress.fromWpMetaData(shippingDetailsWpMeta);
billingAddress = billingCustomerAddress;
shippingAddress = shippingCustomerAddress;
}
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -15,5 +15,8 @@ class BottomNavItem {
BottomNavigationBarItem bottomNavigationBarItem; BottomNavigationBarItem bottomNavigationBarItem;
Widget tabWidget; Widget tabWidget;
BottomNavItem({this.id, this.bottomNavigationBarItem, this.tabWidget}); BottomNavItem(
{required this.id,
required this.bottomNavigationBarItem,
required this.tabWidget});
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,14 +10,14 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/cupertino.dart'; import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter_app/app/models/cart_line_item.dart'; import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/app/models/checkout_session.dart'; import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/app/models/shipping_type.dart'; import 'package:flutter_app/app/models/shipping_type.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart'; import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:nylo_support/helpers/helper.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/shipping_method.dart'; import 'package:woosignal/models/response/shipping_method.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
@ -27,7 +27,7 @@ class Cart {
Future<List<CartLineItem>> getCart() async { Future<List<CartLineItem>> getCart() async {
List<CartLineItem> cartLineItems = []; List<CartLineItem> cartLineItems = [];
String currentCartArrJSON = await NyStorage.read(SharedKey.cart); String? currentCartArrJSON = await (NyStorage.read(SharedKey.cart));
if (currentCartArrJSON != null) { if (currentCartArrJSON != null) {
cartLineItems = (jsonDecode(currentCartArrJSON) as List<dynamic>) cartLineItems = (jsonDecode(currentCartArrJSON) as List<dynamic>)
@ -38,15 +38,14 @@ class Cart {
return cartLineItems; return cartLineItems;
} }
Future addToCart({@required CartLineItem cartLineItem}) async { Future addToCart({required CartLineItem cartLineItem}) async {
List<CartLineItem> cartLineItems = await getCart(); List<CartLineItem> cartLineItems = await getCart();
if (cartLineItem.variationId != null && if (cartLineItem.variationId != null &&
cartLineItems.firstWhere( cartLineItems.firstWhereOrNull((i) =>
(i) => (i.productId == cartLineItem.productId && (i.productId == cartLineItem.productId &&
i.variationId == cartLineItem.variationId && i.variationId == cartLineItem.variationId &&
i.variationOptions == cartLineItem.variationOptions), i.variationOptions == cartLineItem.variationOptions)) !=
orElse: () => null) !=
null) { null) {
cartLineItems.removeWhere((item) => cartLineItems.removeWhere((item) =>
item.productId == cartLineItem.productId && item.productId == cartLineItem.productId &&
@ -55,8 +54,8 @@ class Cart {
} }
if (cartLineItem.variationId == null && if (cartLineItem.variationId == null &&
cartLineItems.firstWhere((i) => i.productId == cartLineItem.productId, cartLineItems.firstWhereOrNull(
orElse: () => null) != (i) => i.productId == cartLineItem.productId) !=
null) { null) {
cartLineItems cartLineItems
.removeWhere((item) => item.productId == cartLineItem.productId); .removeWhere((item) => item.productId == cartLineItem.productId);
@ -80,7 +79,7 @@ class Cart {
total = total - double.parse(discountAmount); total = total - double.parse(discountAmount);
} }
if (withFormat != null && withFormat == true) { if (withFormat == true) {
return formatDoubleCurrency(total: total); return formatDoubleCurrency(total: total);
} }
return total.toStringAsFixed(2); return total.toStringAsFixed(2);
@ -92,15 +91,15 @@ class Cart {
for (var cartItem in cartLineItems) { for (var cartItem in cartLineItems) {
subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity); subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity);
} }
if (withFormat != null && withFormat == true) { if (withFormat == true) {
return formatDoubleCurrency(total: subtotal); return formatDoubleCurrency(total: subtotal);
} }
return subtotal.toStringAsFixed(2); return subtotal.toStringAsFixed(2);
} }
updateQuantity( updateQuantity(
{@required CartLineItem cartLineItem, {required CartLineItem cartLineItem,
@required int incrementQuantity}) async { required int incrementQuantity}) async {
List<CartLineItem> cartLineItems = await getCart(); List<CartLineItem> cartLineItems = await getCart();
List<CartLineItem> tmpCartItem = []; List<CartLineItem> tmpCartItem = [];
for (var cartItem in cartLineItems) { for (var cartItem in cartLineItems) {
@ -124,7 +123,7 @@ class Cart {
.join(","); .join(",");
} }
removeCartItemForIndex({@required int index}) async { removeCartItemForIndex({required int index}) async {
List<CartLineItem> cartLineItems = await getCart(); List<CartLineItem> cartLineItems = await getCart();
cartLineItems.removeAt(index); cartLineItems.removeAt(index);
await saveCartToPref(cartLineItems: cartLineItems); await saveCartToPref(cartLineItems: cartLineItems);
@ -132,12 +131,12 @@ class Cart {
clear() async => NyStorage.delete(SharedKey.cart); clear() async => NyStorage.delete(SharedKey.cart);
saveCartToPref({@required List<CartLineItem> cartLineItems}) async { saveCartToPref({required List<CartLineItem> cartLineItems}) async {
String json = jsonEncode(cartLineItems.map((i) => i.toJson()).toList()); String json = jsonEncode(cartLineItems.map((i) => i.toJson()).toList());
await NyStorage.store(SharedKey.cart, json); await NyStorage.store(SharedKey.cart, json);
} }
Future<String> taxAmount(TaxRate taxRate) async { Future<String> taxAmount(TaxRate? taxRate) async {
double subtotal = 0; double subtotal = 0;
double shippingTotal = 0; double shippingTotal = 0;
@ -150,7 +149,7 @@ class Cart {
cartItems.where((c) => c.taxStatus == 'taxable').toList(); cartItems.where((c) => c.taxStatus == 'taxable').toList();
double cartSubtotal = 0; double cartSubtotal = 0;
if (AppHelper.instance.appConfig.productPricesIncludeTax == 1 && if (AppHelper.instance.appConfig!.productPricesIncludeTax == 1 &&
taxableCartLines.isNotEmpty) { taxableCartLines.isNotEmpty) {
cartSubtotal = taxableCartLines cartSubtotal = taxableCartLines
.map<double>((m) => parseWcPrice(m.subtotal) * m.quantity) .map<double>((m) => parseWcPrice(m.subtotal) * m.quantity)
@ -163,22 +162,20 @@ class Cart {
subtotal = cartSubtotal; subtotal = cartSubtotal;
ShippingType shippingType = CheckoutSession.getInstance.shippingType; ShippingType? shippingType = CheckoutSession.getInstance.shippingType;
if (shippingType != null) { if (shippingType != null) {
switch (shippingType.methodId) { switch (shippingType.methodId) {
case "flat_rate": case "flat_rate":
FlatRate flatRate = (shippingType.object as FlatRate); FlatRate flatRate = (shippingType.object as FlatRate);
if (flatRate.taxable != null && flatRate.taxable) { if (flatRate.taxable != null && flatRate.taxable!) {
shippingTotal += parseWcPrice( shippingTotal +=
shippingType.cost == null || shippingType.cost == "" parseWcPrice(shippingType.cost == "" ? "0" : shippingType.cost);
? "0"
: shippingType.cost);
} }
break; break;
case "local_pickup": case "local_pickup":
LocalPickup localPickup = (shippingType.object as LocalPickup); LocalPickup localPickup = (shippingType.object as LocalPickup);
if (localPickup.taxable != null && localPickup.taxable) { if (localPickup.taxable != null && localPickup.taxable!) {
shippingTotal += parseWcPrice( shippingTotal += parseWcPrice(
(localPickup.cost == null || localPickup.cost == "" (localPickup.cost == null || localPickup.cost == ""
? "0" ? "0"
@ -192,10 +189,10 @@ class Cart {
double total = 0; double total = 0;
if (subtotal != 0) { if (subtotal != 0) {
total += ((parseWcPrice(taxRate.rate) * subtotal) / 100); total += ((parseWcPrice(taxRate!.rate) * subtotal) / 100);
} }
if (shippingTotal != 0) { if (shippingTotal != 0) {
total += ((parseWcPrice(taxRate.rate) * shippingTotal) / 100); total += ((parseWcPrice(taxRate!.rate) * shippingTotal) / 100);
} }
return (total).toStringAsFixed(2); return (total).toStringAsFixed(2);
} }
@ -213,10 +210,10 @@ class Cart {
for (var cartItem in cartLineItems) { for (var cartItem in cartLineItems) {
bool canContinue = true; bool canContinue = true;
if (checkoutSession.coupon.excludedProductCategories.isNotEmpty) { if (checkoutSession.coupon!.excludedProductCategories!.isNotEmpty) {
for (var excludedProductCategory for (var excludedProductCategory
in checkoutSession.coupon.excludedProductCategories) { in checkoutSession.coupon!.excludedProductCategories!) {
if (cartItem.categories if (cartItem.categories!
.map((category) => category.id) .map((category) => category.id)
.contains(excludedProductCategory)) { .contains(excludedProductCategory)) {
canContinue = false; canContinue = false;
@ -225,10 +222,10 @@ class Cart {
} }
} }
if (checkoutSession.coupon.productCategories.isNotEmpty) { if (checkoutSession.coupon!.productCategories!.isNotEmpty) {
for (var productCategories for (var productCategories
in checkoutSession.coupon.productCategories) { in checkoutSession.coupon!.productCategories!) {
if (cartItem.categories if (cartItem.categories!
.map((category) => category.id) .map((category) => category.id)
.contains(productCategories) == .contains(productCategories) ==
false) { false) {
@ -242,41 +239,41 @@ class Cart {
continue; continue;
} }
if (checkoutSession.coupon.excludeSaleItems == true && if (checkoutSession.coupon!.excludeSaleItems == true &&
cartItem.onSale == true) { cartItem.onSale == true) {
continue; continue;
} }
if (checkoutSession.coupon.excludedProductIds.isNotEmpty && if (checkoutSession.coupon!.excludedProductIds!.isNotEmpty &&
checkoutSession.coupon.excludedProductIds checkoutSession.coupon!.excludedProductIds!
.contains(cartItem.productId)) { .contains(cartItem.productId)) {
continue; continue;
} }
if (checkoutSession.coupon.productIds.isNotEmpty && if (checkoutSession.coupon!.productIds!.isNotEmpty &&
!checkoutSession.coupon.productIds.contains(cartItem.productId)) { !checkoutSession.coupon!.productIds!.contains(cartItem.productId)) {
continue; continue;
} }
subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity); subtotal += (parseWcPrice(cartItem.subtotal) * cartItem.quantity);
eligibleCartLineItems.add(cartItem); eligibleCartLineItems.add(cartItem);
} }
String discountType = checkoutSession.coupon.discountType; String? discountType = checkoutSession.coupon!.discountType;
String amount = checkoutSession.coupon.amount; String? amount = checkoutSession.coupon!.amount;
// Percentage // Percentage
if (discountType == 'percent') { if (discountType == 'percent') {
return ((subtotal * double.parse(amount)) / 100).toStringAsFixed(2); return ((subtotal * double.parse(amount!)) / 100).toStringAsFixed(2);
} }
// Fixed cart // Fixed cart
if (discountType == 'fixed_cart') { if (discountType == 'fixed_cart') {
return (double.parse(amount)).toStringAsFixed(2); return (double.parse(amount!)).toStringAsFixed(2);
} }
// Fixed product // Fixed product
if (discountType == 'fixed_product') { if (discountType == 'fixed_product') {
return (eligibleCartLineItems.length * double.parse(amount)) return (eligibleCartLineItems.length * double.parse(amount!))
.toStringAsFixed(2); .toStringAsFixed(2);
} }
return "0"; return "0";

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,27 +11,27 @@
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/product_variation.dart'; import 'package:woosignal/models/response/product_variation.dart';
import 'package:woosignal/models/response/products.dart' as ws_product; import 'package:woosignal/models/response/product.dart' as ws_product;
class CartLineItem { class CartLineItem {
String name; String? name;
int productId; int? productId;
int variationId; int? variationId;
int quantity; int quantity = 0;
bool isManagedStock; bool? isManagedStock;
int stockQuantity; int? stockQuantity;
String shippingClassId; String? shippingClassId;
String taxStatus; String? taxStatus;
String taxClass; String? taxClass;
bool shippingIsTaxable; bool? shippingIsTaxable;
String subtotal; String? subtotal;
String total; String? total;
String imageSrc; String? imageSrc;
String variationOptions; String? variationOptions;
List<ws_product.Category> categories; List<ws_product.Category>? categories;
bool onSale; bool? onSale;
String stockStatus; String? stockStatus;
Object metaData = {}; Object? metaData = {};
CartLineItem( CartLineItem(
{this.name, {this.name,
@ -39,7 +39,7 @@ class CartLineItem {
this.variationId, this.variationId,
this.isManagedStock, this.isManagedStock,
this.stockQuantity, this.stockQuantity,
this.quantity, this.quantity = 1,
this.stockStatus, this.stockStatus,
this.shippingClassId, this.shippingClassId,
this.taxStatus, this.taxStatus,
@ -57,10 +57,11 @@ class CartLineItem {
return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2); return (quantity * parseWcPrice(subtotal)).toStringAsFixed(2);
} }
CartLineItem.fromProduct({int quantityAmount, ws_product.Product product}) { CartLineItem.fromProduct(
{int? quantityAmount, required ws_product.Product product}) {
name = product.name; name = product.name;
productId = product.id; productId = product.id;
quantity = quantityAmount; quantity = quantityAmount ?? 1;
taxStatus = product.taxStatus; taxStatus = product.taxStatus;
shippingClassId = product.shippingClassId.toString(); shippingClassId = product.shippingClassId.toString();
subtotal = product.price; subtotal = product.price;
@ -76,21 +77,21 @@ class CartLineItem {
} }
CartLineItem.fromProductVariation( CartLineItem.fromProductVariation(
{int quantityAmount, {int? quantityAmount,
List<String> options, required List<String> options,
ws_product.Product product, required ws_product.Product product,
ProductVariation productVariation}) { required ProductVariation productVariation}) {
String imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE"); String? imageSrc = getEnv("PRODUCT_PLACEHOLDER_IMAGE");
if (product.images.isNotEmpty) { if (product.images.isNotEmpty) {
imageSrc = product.images.first.src; imageSrc = product.images.first.src;
} }
if (productVariation.image != null) { if (productVariation.image != null) {
imageSrc = productVariation.image.src; imageSrc = productVariation.image!.src;
} }
name = product.name; name = product.name;
productId = product.id; productId = product.id;
variationId = productVariation.id; variationId = productVariation.id;
quantity = quantityAmount; quantity = quantityAmount ?? 1;
taxStatus = productVariation.taxStatus; taxStatus = productVariation.taxStatus;
shippingClassId = productVariation.shippingClassId.toString(); shippingClassId = productVariation.shippingClassId.toString();
subtotal = productVariation.price; subtotal = productVariation.price;
@ -145,7 +146,7 @@ class CartLineItem {
'shipping_is_taxable': shippingIsTaxable, 'shipping_is_taxable': shippingIsTaxable,
'image_src': imageSrc, 'image_src': imageSrc,
'categories': categories != null 'categories': categories != null
? categories.map((e) => e.toJson()).toList() ? categories!.map((e) => e.toJson()).toList()
: [], : [],
'variation_options': variationOptions, 'variation_options': variationOptions,
'subtotal': subtotal, 'subtotal': subtotal,

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -16,21 +16,21 @@ import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/models/shipping_type.dart'; import 'package:flutter_app/app/models/shipping_type.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart'; import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:nylo_support/helpers/helper.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/coupon.dart'; import 'package:woosignal/models/response/coupon.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
class CheckoutSession { class CheckoutSession {
bool shipToDifferentAddress = false; bool? shipToDifferentAddress = false;
CheckoutSession._privateConstructor(); CheckoutSession._privateConstructor();
static final CheckoutSession getInstance = static final CheckoutSession getInstance =
CheckoutSession._privateConstructor(); CheckoutSession._privateConstructor();
BillingDetails billingDetails; BillingDetails? billingDetails;
ShippingType shippingType; ShippingType? shippingType;
PaymentType paymentType; PaymentType? paymentType;
Coupon coupon; Coupon? coupon;
void initSession() { void initSession() {
billingDetails = BillingDetails(); billingDetails = BillingDetails();
@ -45,8 +45,8 @@ class CheckoutSession {
} }
saveBillingAddress() async { saveBillingAddress() async {
CustomerAddress customerAddress = CustomerAddress? customerAddress =
CheckoutSession.getInstance.billingDetails.billingAddress; CheckoutSession.getInstance.billingDetails!.billingAddress;
if (customerAddress == null) { if (customerAddress == null) {
return; return;
@ -56,9 +56,9 @@ class CheckoutSession {
await NyStorage.store(SharedKey.customerBillingDetails, billingAddress); await NyStorage.store(SharedKey.customerBillingDetails, billingAddress);
} }
Future<CustomerAddress> getBillingAddress() async { Future<CustomerAddress?> getBillingAddress() async {
String strCheckoutDetails = String? strCheckoutDetails =
await NyStorage.read(SharedKey.customerBillingDetails); await (NyStorage.read(SharedKey.customerBillingDetails));
if (strCheckoutDetails != null && strCheckoutDetails != "") { if (strCheckoutDetails != null && strCheckoutDetails != "") {
return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails)); return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails));
@ -70,8 +70,8 @@ class CheckoutSession {
await NyStorage.delete(SharedKey.customerBillingDetails); await NyStorage.delete(SharedKey.customerBillingDetails);
saveShippingAddress() async { saveShippingAddress() async {
CustomerAddress customerAddress = CustomerAddress? customerAddress =
CheckoutSession.getInstance.billingDetails.shippingAddress; CheckoutSession.getInstance.billingDetails!.shippingAddress;
if (customerAddress == null) { if (customerAddress == null) {
return; return;
} }
@ -79,9 +79,9 @@ class CheckoutSession {
await NyStorage.store(SharedKey.customerShippingDetails, shippingAddress); await NyStorage.store(SharedKey.customerShippingDetails, shippingAddress);
} }
Future<CustomerAddress> getShippingAddress() async { Future<CustomerAddress?> getShippingAddress() async {
String strCheckoutDetails = String? strCheckoutDetails =
await NyStorage.read(SharedKey.customerShippingDetails); await (NyStorage.read(SharedKey.customerShippingDetails));
if (strCheckoutDetails != null && strCheckoutDetails != "") { if (strCheckoutDetails != null && strCheckoutDetails != "") {
return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails)); return CustomerAddress.fromJson(jsonDecode(strCheckoutDetails));
} }
@ -91,19 +91,19 @@ class CheckoutSession {
clearShippingAddress() async => clearShippingAddress() async =>
await NyStorage.delete(SharedKey.customerShippingDetails); await NyStorage.delete(SharedKey.customerShippingDetails);
Future<String> total({bool withFormat = false, TaxRate taxRate}) async { Future<String> total({bool withFormat = false, TaxRate? taxRate}) async {
double totalCart = parseWcPrice(await Cart.getInstance.getTotal()); double totalCart = parseWcPrice(await Cart.getInstance.getTotal());
double totalShipping = 0; double totalShipping = 0;
if (shippingType != null && shippingType.object != null) { if (shippingType != null && shippingType!.object != null) {
switch (shippingType.methodId) { switch (shippingType!.methodId) {
case "flat_rate": case "flat_rate":
totalShipping = parseWcPrice(shippingType.cost); totalShipping = parseWcPrice(shippingType!.cost);
break; break;
case "free_shipping": case "free_shipping":
totalShipping = parseWcPrice(shippingType.cost); totalShipping = parseWcPrice(shippingType!.cost);
break; break;
case "local_pickup": case "local_pickup":
totalShipping = parseWcPrice(shippingType.cost); totalShipping = parseWcPrice(shippingType!.cost);
break; break;
default: default:
break; break;

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,16 +9,19 @@
// 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_app/app/models/customer_country.dart'; import 'package:flutter_app/app/models/customer_country.dart';
import 'package:flutter_app/app/models/default_shipping.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:wp_json_api/models/wp_meta_meta.dart';
class CustomerAddress { class CustomerAddress {
String firstName; String? firstName;
String lastName; String? lastName;
String addressLine; String? addressLine;
String city; String? city;
String postalCode; String? postalCode;
String emailAddress; String? emailAddress;
String phoneNumber; String? phoneNumber;
CustomerCountry customerCountry; CustomerCountry? customerCountry;
CustomerAddress( CustomerAddress(
{this.firstName, {this.firstName,
@ -27,7 +30,7 @@ class CustomerAddress {
this.city, this.city,
this.postalCode, this.postalCode,
this.emailAddress, this.emailAddress,
this.phoneNumber, this.phoneNumber,
this.customerCountry}); this.customerCountry});
void initAddress() { void initAddress() {
@ -42,17 +45,17 @@ class CustomerAddress {
} }
bool hasMissingFields() => bool hasMissingFields() =>
(firstName.isEmpty || (firstName!.isEmpty ||
lastName.isEmpty || lastName!.isEmpty ||
addressLine.isEmpty || addressLine!.isEmpty ||
city.isEmpty || city!.isEmpty ||
postalCode.isEmpty) || postalCode!.isEmpty) ||
(customerCountry.hasState() == true (customerCountry!.hasState() == true
? (customerCountry?.state?.name ?? "").isEmpty ? (customerCountry?.state?.name ?? "").isEmpty
: false); : false);
String addressFull() { String addressFull() {
List<String> tmpArrAddress = []; List<String?> tmpArrAddress = [];
if (addressLine != null && addressLine != "") { if (addressLine != null && addressLine != "") {
tmpArrAddress.add(addressLine); tmpArrAddress.add(addressLine);
} }
@ -66,13 +69,13 @@ class CustomerAddress {
tmpArrAddress.add(customerCountry?.state?.name); tmpArrAddress.add(customerCountry?.state?.name);
} }
if (customerCountry != null && customerCountry?.name != null) { if (customerCountry != null && customerCountry?.name != null) {
tmpArrAddress.add(customerCountry.name); tmpArrAddress.add(customerCountry!.name);
} }
return tmpArrAddress.join(", "); return tmpArrAddress.join(", ");
} }
String nameFull() { String nameFull() {
List<String> tmpArrName = []; List<String?> tmpArrName = [];
if (firstName != "") { if (firstName != "") {
tmpArrName.add(firstName); tmpArrName.add(firstName);
} }
@ -102,16 +105,73 @@ class CustomerAddress {
data['address_line'] = addressLine; data['address_line'] = addressLine;
data['city'] = city; data['city'] = city;
data['postal_code'] = postalCode; data['postal_code'] = postalCode;
data['state'] = customerCountry.state; data['state'] = customerCountry!.state;
data['country'] = customerCountry.name; data['country'] = customerCountry!.name;
if (phoneNumber != null && phoneNumber != "") { if (phoneNumber != null && phoneNumber != "") {
data['phone_number'] = phoneNumber; data['phone_number'] = phoneNumber;
} }
data['email_address'] = emailAddress; data['email_address'] = emailAddress;
data['customer_country'] = null; data['customer_country'] = null;
if (customerCountry != null) { if (customerCountry != null) {
data['customer_country'] = customerCountry.toJson(); data['customer_country'] = customerCountry!.toJson();
} }
return data; return data;
} }
fromWpMetaData(Map<String, dynamic> data) async {
if (data.containsKey('first_name')) {
firstName = data['first_name'];
}
if (data.containsKey('last_name')) {
lastName = data['last_name'];
}
if (data.containsKey('address_1')) {
addressLine = data['address_1'];
}
if (data.containsKey('city')) {
city = data['city'];
}
if (data.containsKey('postcode')) {
postalCode = data['postcode'];
}
if (data.containsKey('email')) {
emailAddress = data['email'];
}
if (data.containsKey('phone')) {
phoneNumber = data['phone'];
}
if (data.containsKey('country')) {
DefaultShipping? defaultShipping =
await findCountryMetaForShipping(data['country']);
if (defaultShipping == null) {
return;
}
customerCountry = CustomerCountry.fromWpMeta(data, defaultShipping);
}
}
List<WpMetaData> toUserMetaDataItem(String type) {
return [
WpMetaData(key: "${type}_first_name", value: firstName),
WpMetaData(key: "${type}_last_name", value: lastName),
WpMetaData(key: "${type}_address_1", value: addressLine),
WpMetaData(key: "${type}_city", value: city),
WpMetaData(key: "${type}_postcode", value: postalCode),
WpMetaData(key: "${type}_phone", value: phoneNumber),
if (type != "shipping")
WpMetaData(key: "${type}_email", value: emailAddress),
WpMetaData(key: "${type}_country", value: customerCountry?.countryCode),
WpMetaData(
key: "${type}_state",
value: customerCountry?.state?.code
?.replaceAll("${customerCountry?.countryCode}:", "")),
];
}
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,23 +9,33 @@
// 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_app/app/models/default_shipping.dart'; import 'package:flutter_app/app/models/default_shipping.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
class CustomerCountry { class CustomerCountry {
String countryCode; String? countryCode;
String name; String? name;
DefaultShippingState state; DefaultShippingState? state;
CustomerCountry({this.countryCode, this.name, this.state}); CustomerCountry({this.countryCode, this.name, this.state});
CustomerCountry.fromDefaultShipping({DefaultShipping defaultShipping}) { CustomerCountry.fromDefaultShipping(
{required DefaultShipping defaultShipping}) {
countryCode = defaultShipping.code; countryCode = defaultShipping.code;
name = defaultShipping.country; name = defaultShipping.country;
if ((defaultShipping.states?.length ?? 0) == 1) { if ((defaultShipping.states.length) == 1) {
state = defaultShipping.states.first; state = defaultShipping.states.first;
} }
} }
CustomerCountry.fromJson(Map<String, dynamic> json) { CustomerCountry.fromWpMeta(
Map<String, dynamic> json, DefaultShipping defaultShipping) {
countryCode = json['country'];
name = defaultShipping.country;
state = findDefaultShippingStateByCode(
defaultShipping, "${json['country']}:${json['state']}");
}
CustomerCountry.fromJson(Map<String, dynamic>? json) {
if (json == null) { if (json == null) {
return; return;
} }
@ -40,7 +50,7 @@ class CustomerCountry {
} }
} }
bool hasState() => (state != null && state.name != null ? true : false); bool hasState() => (state != null && state!.name != null ? true : false);
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{}; final Map<String, dynamic> data = <String, dynamic>{};
@ -48,7 +58,7 @@ class CustomerCountry {
data['name'] = name; data['name'] = name;
data['state'] = null; data['state'] = null;
if (state != null) { if (state != null) {
data['state'] = state.toJson(); data['state'] = state!.toJson();
} }
return data; return data;
} }

View File

@ -1,28 +1,25 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
class DefaultShipping { class DefaultShipping {
String code; String code;
String country; String? country;
List<DefaultShippingState> states; List<DefaultShippingState> states;
DefaultShipping( DefaultShipping(
{@required this.code, @required this.country, @required this.states}); {required this.code, required this.country, required this.states});
} }
class DefaultShippingState { class DefaultShippingState {
String code; String? code;
String name; String? name;
DefaultShippingState({@required this.code, @required this.name}); DefaultShippingState({required this.code, required this.name});
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{}; final Map<String, dynamic> data = <String, dynamic>{};

View File

@ -1,15 +1,13 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
class PaymentType { class PaymentType {
int id; int id;
String name; String name;
@ -18,9 +16,9 @@ class PaymentType {
Function pay; Function pay;
PaymentType( PaymentType(
{@required this.id, {required this.id,
@required this.name, required this.name,
@required this.desc, required this.desc,
@required this.assetImage, required this.assetImage,
@required this.pay}); required this.pay});
} }

View File

@ -1,28 +1,26 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:flutter/cupertino.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:woosignal/models/response/shipping_method.dart'; import 'package:woosignal/models/response/shipping_method.dart';
class ShippingType { class ShippingType {
String methodId; String? methodId;
String cost; String cost;
String minimumValue; String? minimumValue;
dynamic object; dynamic object;
ShippingType( ShippingType(
{@required this.methodId, {required this.methodId,
this.object, this.object,
@required this.cost, required this.cost,
@required this.minimumValue}); required this.minimumValue});
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'methodId': methodId, 'methodId': methodId,
@ -31,24 +29,24 @@ class ShippingType {
'minimumValue': minimumValue 'minimumValue': minimumValue
}; };
String getTotal({bool withFormatting = false}) { String? getTotal({bool withFormatting = false}) {
if (object != null) { if (object != null) {
switch (methodId) { switch (methodId) {
case "flat_rate": case "flat_rate":
FlatRate flatRate = (object as FlatRate); FlatRate? flatRate = (object as FlatRate?);
return (withFormatting == true return (withFormatting == true
? formatStringCurrency(total: cost) ? formatStringCurrency(total: cost)
: flatRate.cost); : flatRate!.cost);
case "free_shipping": case "free_shipping":
FreeShipping freeShipping = (object as FreeShipping); FreeShipping? freeShipping = (object as FreeShipping?);
return (withFormatting == true return (withFormatting == true
? formatStringCurrency(total: cost) ? formatStringCurrency(total: cost)
: freeShipping.cost); : freeShipping!.cost);
case "local_pickup": case "local_pickup":
LocalPickup localPickup = (object as LocalPickup); LocalPickup? localPickup = (object as LocalPickup?);
return (withFormatting == true return (withFormatting == true
? formatStringCurrency(total: cost) ? formatStringCurrency(total: cost)
: localPickup.cost); : localPickup!.cost);
default: default:
return "0"; return "0";
} }
@ -56,7 +54,7 @@ class ShippingType {
return "0"; return "0";
} }
String getTitle() { String? getTitle() {
if (object != null) { if (object != null) {
switch (methodId) { switch (methodId) {
case "flat_rate": case "flat_rate":
@ -75,7 +73,7 @@ class ShippingType {
return ""; return "";
} }
Map<String, dynamic> toShippingLineFee() { Map<String, dynamic>? toShippingLineFee() {
if (object != null) { if (object != null) {
Map<String, dynamic> tmpShippingLinesObj = {}; Map<String, dynamic> tmpShippingLinesObj = {};

View File

@ -1,27 +1,25 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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:nylo_support/helpers/helper.dart'; import 'package:nylo_framework/nylo_framework.dart';
class User extends Storable { class User extends Model {
String userId; String? userId;
String token; String? token;
User(); User();
User.fromUserAuthResponse({this.userId, this.token}); User.fromUserAuthResponse({this.userId, this.token});
@override toJson() => {"token": token, "user_id": userId};
toStorage() => {"token": token, "user_id": userId};
@override User.fromJson(dynamic data) {
fromStorage(dynamic data) {
token = data['token']; token = data['token'];
userId = data['user_id']; userId = data['user_id'];
} }

View File

@ -1,11 +1,29 @@
// Label StoreMax import 'package:flutter/material.dart';
// import 'package:flutter_app/app/networking/dio/base_api_service.dart';
// Created by Anthony Gordon. import 'package:flutter_app/app/networking/dio/interceptors/logging_interceptor.dart';
// 2022, WooSignal Ltd. All rights reserved. import 'package:nylo_framework/nylo_framework.dart';
//
// 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. | ApiService
| -------------------------------------------------------------------------
| Define your API endpoints
| Learn more https://nylo.dev/docs/5.x/networking
|--------------------------------------------------------------------------
*/
class ApiService {} class ApiService extends BaseApiService {
ApiService({BuildContext? buildContext}) : super(buildContext);
@override
String get baseUrl => getEnv('API_BASE_URL');
@override
final interceptors = {LoggingInterceptor: LoggingInterceptor()};
Future<dynamic> fetchTestData() async {
return await network(
request: (request) => request.get("/endpoint-path"),
);
}
}

View File

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/app/networking/dio/interceptors/logging_interceptor.dart';
import 'package:flutter_app/config/decoders.dart';
import 'package:nylo_framework/networking/ny_base_networking.dart';
import 'package:nylo_framework/nylo_framework.dart';
class BaseApiService extends NyBaseApiService {
BaseApiService(BuildContext? context) : super(context);
/// Map decoders to modelDecoders
@override
final Map<Type, dynamic> decoders = modelDecoders;
/// Default interceptors
@override
final interceptors = {
if (getEnv('APP_DEBUG') == true) LoggingInterceptor: LoggingInterceptor()
};
}

View File

@ -0,0 +1,22 @@
import 'package:nylo_framework/nylo_framework.dart';
class BearerAuthInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
String? userToken = Backpack.instance.read('user_token');
if (userToken != null) {
options.headers.addAll({"Authorization": "Bearer $userToken"});
}
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
handler.next(err);
}
}

View File

@ -0,0 +1,26 @@
import 'dart:developer';
import 'package:nylo_framework/nylo_framework.dart';
class LoggingInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print(
'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
print('DATA: ${response.requestOptions.path}');
log(response.data.toString());
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
print(
'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}');
handler.next(err);
}
}

View File

@ -0,0 +1,107 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/config/decoders.dart';
import 'package:flutter_app/config/design.dart';
import 'package:flutter_app/config/theme.dart';
import 'package:flutter_app/config/validation_rules.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:flutter_app/config/localization.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/woosignal.dart';
import 'package:wp_json_api/wp_json_api.dart';
class AppProvider implements NyProvider {
@override
boot(Nylo nylo) async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
await WooSignal.instance
.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG'),
encryptKey: getEnv('ENCRYPT_KEY', defaultValue: null),
encryptSecret: getEnv('ENCRYPT_SECRET', defaultValue: null)
);
AppHelper.instance.appConfig = WooSignalApp();
AppHelper.instance.appConfig!.themeFont = "Poppins";
AppHelper.instance.appConfig!.themeColors = {
'light': {
'background': '0xFFFFFFFF',
'primary_text': '0xFF000000',
'button_background': '0xFF529cda',
'button_text': '0xFFFFFFFF',
'app_bar_background': '0xFFFFFFFF',
'app_bar_text': '0xFF3a3d40',
},
'dark': {
'background': '0xFF212121',
'primary_text': '0xFFE1E1E1',
'button_background': '0xFFFFFFFF',
'button_text': '0xFF232c33',
'app_bar_background': '0xFF2C2C2C',
'app_bar_text': '0xFFFFFFFF',
}
};
// WooSignal Setup
WooSignalApp? wooSignalApp = await (appWooSignal((api) => api.getApp(encrypted: shouldEncrypt())));
Locale locale = Locale('en');
if (wooSignalApp != null) {
AppHelper.instance.appConfig = wooSignalApp;
if (wooSignalApp.wpLoginEnabled == 1) {
if (wooSignalApp.wpLoginBaseUrl == null) {
AppHelper.instance.appConfig?.wpLoginEnabled = 0;
log('Set your stores domain on WooSignal. Go to Features > WP Login and add your domain to "Store Base Url"');
}
if (wooSignalApp.wpLoginWpApiPath == null) {
AppHelper.instance.appConfig?.wpLoginEnabled = 0;
log('Set your stores Wp JSON path on WooSignal. Go to Features > WP Login and add your Wp JSON path to "WP API Path"');
}
WPJsonAPI.instance.initWith(
baseUrl: wooSignalApp.wpLoginBaseUrl ?? "",
shouldDebug: getEnv('APP_DEBUG'),
wpJsonPath: wooSignalApp.wpLoginWpApiPath ?? "",
);
}
if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null &&
wooSignalApp.locale != null) {
locale = Locale(wooSignalApp.locale!);
} else {
locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en'));
}
}
/// NyLocalization
await NyLocalization.instance.init(
localeType: localeType,
languageCode: locale.languageCode,
languagesList: languagesList,
assetsDirectory: assetsDirectory,
valuesAsMap: valuesAsMap);
nylo.appThemes = appThemes;
nylo.appLoader = loader;
nylo.appLogo = logo;
nylo.addModelDecoders(modelDecoders);
nylo.addValidationRules(validationRules);
nylo.toastNotification = getToastNotificationWidget;
return nylo;
}
@override
afterBoot(Nylo nylo) async {
}
}

View File

@ -0,0 +1,16 @@
import 'package:flutter_app/config/events.dart';
import 'package:nylo_framework/nylo_framework.dart';
class EventProvider implements NyProvider {
@override
boot(Nylo nylo) async {
nylo.addEvents(events);
return nylo;
}
@override
afterBoot(Nylo nylo) async {
}
}

View File

@ -0,0 +1,49 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/firebase_options.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/woosignal.dart';
class FirebaseProvider implements NyProvider {
@override
boot(Nylo nylo) async {
return null;
}
@override
afterBoot(Nylo nylo) async {
bool? firebaseFcmIsEnabled = AppHelper.instance.appConfig?.firebaseFcmIsEnabled;
if (firebaseFcmIsEnabled == null) {
firebaseFcmIsEnabled = getEnv('FCM_ENABLED', defaultValue: false);
}
if (firebaseFcmIsEnabled != true) return;
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings.authorizationStatus != AuthorizationStatus.authorized) {
return;
}
String? token = await messaging.getToken();
if (token != null) {
WooSignal.instance.setFcmToken(token);
}
}
}

View File

@ -3,7 +3,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,18 +14,18 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart'; import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation.dart'; import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/order.dart'; import 'package:woosignal/models/response/order.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
cashOnDeliveryPay(context, cashOnDeliveryPay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { {required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
try { try {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: false); OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: false);
Order order = await appWooSignal((api) => api.createOrder(orderWC)); Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
if (order != null) { if (order != null) {
Navigator.pushNamed(context, "/checkout-status", arguments: order); Navigator.pushNamed(context, "/checkout-status", arguments: order);

View File

@ -3,7 +3,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart'; import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation.dart'; import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/order.dart'; import 'package:woosignal/models/response/order.dart';
@ -29,11 +29,19 @@ import 'package:woosignal/models/response/tax_rate.dart';
// //
// }); // });
// REMEMBER TO ADD THIS METHOD E.G. "examplePay" TO THE APP_PAYMENT_METHODS // TO USE A PAYMENT GATEWAY, FIRST OPEN /config/payment_gateways.dart.
// AS THE PAY METHOD // THEN ADD A NEW PAYMENT LIKE IN THE BELOW EXAMPLE
//
// addPayment(
// id: 6,
// name: "My Payment",
// description: trans("Debit or Credit Card"),
// assetImage: "payment_logo.png", E.g. /public/assets/images/payment_logo.png
// pay: examplePay,
// ),
examplePay(context, examplePay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { {required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
// HANDLE YOUR PAYMENT INTEGRATION HERE // HANDLE YOUR PAYMENT INTEGRATION HERE
// ... // ...
// ... // ...
@ -44,7 +52,7 @@ examplePay(context,
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true); OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true);
// CREATES ORDER IN WOOCOMMERCE // CREATES ORDER IN WOOCOMMERCE
Order order = await appWooSignal((api) => api.createOrder(orderWC)); Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
// CHECK IF ORDER IS NULL // CHECK IF ORDER IS NULL
if (order != null) { if (order != null) {

View File

@ -3,7 +3,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -15,7 +15,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/app/models/cart_line_item.dart'; import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart'; import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation.dart'; import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
import 'package:flutter_app/resources/widgets/checkout_paypal.dart'; import 'package:flutter_app/resources/widgets/checkout_paypal.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/payload/order_wc.dart';
@ -23,7 +23,7 @@ import 'package:woosignal/models/response/order.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
payPalPay(context, payPalPay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { {required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
await checkout(taxRate, (total, billingDetails, cart) async { await checkout(taxRate, (total, billingDetails, cart) async {
List<CartLineItem> cartLineItems = await cart.getCart(); List<CartLineItem> cartLineItems = await cart.getCart();
String description = await cart.cartShortDesc(); String description = await cart.cartShortDesc();
@ -35,7 +35,7 @@ payPalPay(context,
description: description, description: description,
amount: total, amount: total,
cartLineItems: cartLineItems))).then((value) async { cartLineItems: cartLineItems))).then((value) async {
if (!(value is Map<String, dynamic>)) { if (value is! Map<String, dynamic>) {
showToastNotification( showToastNotification(
context, context,
title: trans("Payment Cancelled"), title: trans("Payment Cancelled"),
@ -48,7 +48,7 @@ payPalPay(context,
state.reloadState(showLoader: true); state.reloadState(showLoader: true);
if (value.containsKey("status") && value["status"] == "success") { if (value.containsKey("status") && value["status"] == "success") {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true); OrderWC orderWC = await buildOrderWC(taxRate: taxRate, markPaid: true);
Order order = await appWooSignal((api) => api.createOrder(orderWC)); Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
if (order == null) { if (order == null) {
showToastNotification( showToastNotification(

View File

@ -0,0 +1,81 @@
//
// LabelCore
// Label StoreMAX
//
// Created by Anthony Gordon.
// 2023, WooSignal Ltd. All rights reserved.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
import 'package:flutter/widgets.dart';
import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:razorpay_flutter/razorpay_flutter.dart';
import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/order.dart';
razorPay(context,
{required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
Razorpay razorpay = Razorpay();
razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS,
(PaymentSuccessResponse response) async {
OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
Order? order = await appWooSignal((api) => api.createOrder(orderWC));
if (order != null) {
showToastNotification(
context,
title: "Error".tr(),
description: trans("Something went wrong, please contact our store"),
);
state.reloadState(showLoader: false);
return;
}
Cart.getInstance.clear();
Navigator.pushNamed(context, "/checkout-status", arguments: order);
});
razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, (PaymentFailureResponse response) {
showToastNotification(context,
title: trans("Error"),
description: response.message ?? "",
style: ToastNotificationStyleType.WARNING);
state.reloadState(showLoader: false);
});
razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet);
// CHECKOUT HELPER
await checkout(taxRate, (total, billingDetails, cart) async {
var options = {
'key': getEnv('RAZORPAY_API_KEY'),
'amount': (double.parse(total) * 100).toInt(),
'name': getEnv('APP_NAME'),
'description': await cart.cartShortDesc(),
'prefill': {
"name": [
billingDetails!.billingAddress?.firstName,
billingDetails.billingAddress?.lastName
].where((t) => t != null || t != "").toList().join(" "),
"method": "card",
'email': billingDetails.billingAddress?.emailAddress ?? ""
}
};
state.reloadState(showLoader: true);
razorpay.open(options);
});
}
void _handleExternalWallet(ExternalWalletResponse response) {}

View File

@ -3,7 +3,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -15,7 +15,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/data/order_wc.dart'; import 'package:flutter_app/bootstrap/data/order_wc.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/pages/checkout_confirmation.dart'; import 'package:flutter_app/resources/pages/checkout_confirmation_page.dart';
import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/payload/order_wc.dart';
@ -24,16 +24,16 @@ import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
stripePay(context, stripePay(context,
{@required CheckoutConfirmationPageState state, TaxRate taxRate}) async { {required CheckoutConfirmationPageState state, TaxRate? taxRate}) async {
WooSignalApp wooSignalApp = AppHelper.instance.appConfig; WooSignalApp? wooSignalApp = AppHelper.instance.appConfig;
bool liveMode = getEnv('STRIPE_LIVE_MODE') == null bool liveMode = getEnv('STRIPE_LIVE_MODE') == null
? !wooSignalApp.stripeLiveMode ? !wooSignalApp!.stripeLiveMode!
: getEnv('STRIPE_LIVE_MODE', defaultValue: false); : getEnv('STRIPE_LIVE_MODE', defaultValue: false);
// CONFIGURE STRIPE // CONFIGURE STRIPE
Stripe.stripeAccountId = Stripe.stripeAccountId =
getEnv('STRIPE_ACCOUNT') ?? wooSignalApp.stripeAccount; getEnv('STRIPE_ACCOUNT') ?? wooSignalApp!.stripeAccount;
Stripe.publishableKey = liveMode Stripe.publishableKey = liveMode
? "pk_live_IyS4Vt86L49jITSfaUShumzi" ? "pk_live_IyS4Vt86L49jITSfaUShumzi"
@ -47,24 +47,17 @@ stripePay(context,
} }
try { try {
dynamic rsp = {}; Map<String, dynamic>? rsp = {};
// // CHECKOUT HELPER // // CHECKOUT HELPER
await checkout(taxRate, (total, billingDetails, cart) async { 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?.customerCountry?.name ?? "")
};
String cartShortDesc = await cart.cartShortDesc(); String cartShortDesc = await cart.cartShortDesc();
rsp = await appWooSignal((api) => api.stripePaymentIntent( rsp = await appWooSignal((api) => api.stripePaymentIntentV2(
amount: total, amount: total,
email: billingDetails.billingAddress.emailAddress, email: billingDetails?.billingAddress?.emailAddress,
desc: cartShortDesc, desc: cartShortDesc,
shipping: address, shipping: billingDetails?.getShippingAddressStripe(),
customerDetails: billingDetails?.createStripeDetails(),
)); ));
}); });
@ -79,26 +72,41 @@ stripePay(context,
} }
await Stripe.instance.initPaymentSheet( await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters( paymentSheetParameters: SetupPaymentSheetParameters(
applePay: false, style: Theme.of(state.context).brightness == Brightness.light
googlePay: false, ? ThemeMode.light
style: Theme.of(state.context).brightness == Brightness.light : ThemeMode.dark,
? ThemeMode.light merchantDisplayName:
: ThemeMode.dark, envVal('APP_NAME', defaultValue: wooSignalApp?.appName),
testEnv: liveMode, customerId: rsp!['customer'],
merchantCountryCode: envVal('STRIPE_COUNTRY_CODE', paymentIntentClientSecret: rsp!['client_secret'],
defaultValue: wooSignalApp.stripeCountryCode), customerEphemeralKeySecret: rsp!['ephemeral_key'],
merchantDisplayName: setupIntentClientSecret: rsp!['setup_intent_secret']),
envVal('APP_NAME', defaultValue: wooSignalApp.appName), );
paymentIntentClientSecret: rsp['client_secret'],
));
await Stripe.instance.presentPaymentSheet(); await Stripe.instance.presentPaymentSheet();
PaymentIntent paymentIntent =
await Stripe.instance.retrievePaymentIntent(rsp!['client_secret']);
if (paymentIntent.status == PaymentIntentsStatus.Unknown) {
showToastNotification(
context,
title: trans("Oops!"),
description: trans("Something went wrong, please try again."),
icon: Icons.payment,
style: ToastNotificationStyleType.WARNING,
);
}
if (paymentIntent.status != PaymentIntentsStatus.Succeeded) {
return;
}
state.reloadState(showLoader: true); state.reloadState(showLoader: true);
OrderWC orderWC = await buildOrderWC(taxRate: taxRate); OrderWC orderWC = await buildOrderWC(taxRate: taxRate);
Order order = await appWooSignal((api) => api.createOrder(orderWC)); Order? order = await (appWooSignal((api) => api.createOrder(orderWC)));
if (order == null) { if (order == null) {
showToastNotification( showToastNotification(
@ -110,15 +118,15 @@ stripePay(context,
return; return;
} }
Navigator.pushNamed(context, "/checkout-status", arguments: order); routeTo('/checkout-status', navigationType: NavigationType.pushAndForgetAll, data: order);
} on StripeException catch (e) { } on StripeException catch (e) {
if (getEnv('APP_DEBUG', defaultValue: true)) { if (getEnv('APP_DEBUG', defaultValue: true)) {
NyLogger.error(e.error.message); NyLogger.error(e.error.message!);
} }
showToastNotification( showToastNotification(
context, context,
title: trans("Oops!"), title: trans("Oops!"),
description: e.error.localizedMessage, description: e.error.localizedMessage!,
icon: Icons.payment, icon: Icons.payment,
style: ToastNotificationStyleType.WARNING, style: ToastNotificationStyleType.WARNING,
); );

View File

@ -0,0 +1,20 @@
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/routes/router.dart';
import 'package:nylo_framework/nylo_framework.dart';
class RouteProvider implements NyProvider {
@override
boot(Nylo nylo) async {
nylo.addRouter(appRouter());
return nylo;
}
@override
afterBoot(Nylo nylo) async {
String initialRoute = AppHelper.instance.appConfig!.appStatus != null
? '/home'
: '/no-connection';
nylo.setInitialRoute(initialRoute);
}
}

View File

@ -1,42 +1,41 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/config/app_theme.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
// ignore: must_be_immutable // ignore: must_be_immutable
class AppBuild extends StatelessWidget { class AppBuild extends StatelessWidget {
String initialRoute; String? initialRoute;
ThemeData themeData; ThemeData? themeData;
ThemeData darkTheme; ThemeData? darkTheme;
ThemeData lightTheme; ThemeData? lightTheme;
Locale locale; Locale? locale;
String title; String? title;
bool debugShowCheckedModeBanner; bool debugShowCheckedModeBanner;
bool debugShowMaterialGrid; bool debugShowMaterialGrid;
bool showPerformanceOverlay; bool showPerformanceOverlay;
bool checkerboardRasterCacheImages; bool checkerboardRasterCacheImages;
bool checkerboardOffscreenLayers; bool checkerboardOffscreenLayers;
bool showSemanticsDebugger; bool showSemanticsDebugger;
Map<LogicalKeySet, Intent> shortcuts; Map<LogicalKeySet, Intent>? shortcuts;
Map<Type, Action<Intent>> actions; Map<Type, Action<Intent>>? actions;
List<Locale> supportedLocales; List<Locale> supportedLocales;
ThemeMode themeMode; ThemeMode themeMode;
Color color; Color? color;
GenerateAppTitle onGenerateTitle; GenerateAppTitle? onGenerateTitle;
TransitionBuilder builder; TransitionBuilder? builder;
List<NavigatorObserver> navigatorObservers; List<NavigatorObserver> navigatorObservers;
RouteFactory onUnknownRoute; RouteFactory? onUnknownRoute;
InitialRouteListFactory onGenerateInitialRoutes; InitialRouteListFactory? onGenerateInitialRoutes;
GlobalKey<NavigatorState> navigatorKey; GlobalKey<NavigatorState>? navigatorKey;
Route<dynamic> Function(RouteSettings settings) onGenerateRoute; Route<dynamic>? Function(RouteSettings settings) onGenerateRoute;
AppBuild({ AppBuild({
Key key, Key? key,
this.initialRoute, this.initialRoute,
this.title, this.title,
this.locale, this.locale,
this.themeData, this.themeData,
@required this.onGenerateRoute, required this.onGenerateRoute,
this.navigatorKey, this.navigatorKey,
this.onGenerateInitialRoutes, this.onGenerateInitialRoutes,
this.onUnknownRoute, this.onUnknownRoute,
@ -60,14 +59,12 @@ class AppBuild extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Nylo nylo = Backpack.instance.read('nylo');
List<AppTheme> appThemes =
nylo.appThemes.map((appTheme) => appTheme.toAppTheme()).toList();
return LocalizedApp( return LocalizedApp(
child: ThemeProvider( child: ThemeProvider(
themes: appThemes themes: appThemes,
.map((appTheme) => appTheme.toAppTheme(
defaultTheme: appTheme.theme.brightness == Brightness.light
? lightTheme
: darkTheme))
.toList(),
child: ThemeConsumer( child: ThemeConsumer(
child: Builder( child: Builder(
builder: (themeContext) => ValueListenableBuilder( builder: (themeContext) => ValueListenableBuilder(
@ -93,16 +90,20 @@ class AppBuild extends StatelessWidget {
title: title ?? "", title: title ?? "",
initialRoute: initialRoute, initialRoute: initialRoute,
onGenerateRoute: onGenerateRoute, onGenerateRoute: onGenerateRoute,
darkTheme: darkTheme ?? ThemeConfig.dark().theme, darkTheme: darkTheme ??
appThemes
.firstWhere(
(theme) => theme.id == getEnv('DARK_THEME_ID'),
orElse: () => appThemes.first)
.data,
theme: themeData ?? ThemeProvider.themeOf(context).data, theme: themeData ?? ThemeProvider.themeOf(context).data,
localeResolutionCallback: localeResolutionCallback:
(Locale locale, Iterable<Locale> supportedLocales) { (Locale? locale, Iterable<Locale> supportedLocales) {
return locale; return locale;
}, },
localizationsDelegates: NyLocalization.instance.delegates, localizationsDelegates: NyLocalization.instance.delegates,
locale: NyLocalization.instance.locale, locale: NyLocalization.instance.locale,
supportedLocales: supportedLocales: supportedLocales,
supportedLocales ?? NyLocalization.instance.locals(),
), ),
), ),
), ),

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -15,5 +15,5 @@ class AppHelper {
static final AppHelper instance = AppHelper._privateConstructor(); static final AppHelper instance = AppHelper._privateConstructor();
WooSignalApp appConfig; WooSignalApp? appConfig;
} }

View File

@ -1,24 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/resources/themes/styles/base_styles.dart';
import 'package:nylo_framework/nylo_framework.dart';
class BaseThemeConfig {
final String id;
final String description;
final ThemeData theme;
final BaseColorStyles colors;
final dynamic meta;
BaseThemeConfig(
{this.id,
this.description,
this.theme,
this.colors,
this.meta = const {}});
AppTheme toAppTheme({ThemeData defaultTheme}) => AppTheme(
id: id,
data: defaultTheme ?? theme,
description: description,
);
}

View File

@ -1,96 +1,8 @@
// import 'package:firebase_core/firebase_core.dart';
// import 'package:firebase_messaging/firebase_messaging.dart';
// import 'package:flutter_app/firebase_options.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/config/app_localization.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:woosignal/models/response/woosignal_app.dart';
import 'package:woosignal/woosignal.dart';
import 'package:wp_json_api/wp_json_api.dart';
/// boot application /// boot application
Future<void> boot() async { import 'package:flutter_app/config/providers.dart';
await SystemChrome.setPreferredOrientations([ import 'package:nylo_framework/nylo_framework.dart';
DeviceOrientation.portraitUp,
]);
await WooSignal.instance class Boot {
.init(appKey: getEnv('APP_KEY'), debugMode: getEnv('APP_DEBUG')); static Future<Nylo> nylo() async => await bootApplication(providers);
static Future<void> finished(Nylo nylo) async => await bootFinished(nylo, providers);
// Notifications
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
///
/// FirebaseMessaging messaging = FirebaseMessaging.instance;
///
/// NotificationSettings settings = await messaging.requestPermission(
/// alert: true,
/// announcement: false,
/// badge: true,
/// carPlay: false,
/// criticalAlert: false,
/// provisional: false,
/// sound: true,
/// );
///
/// if (settings.authorizationStatus == AuthorizationStatus.authorized) {
/// String token = await messaging.getToken();
/// WooSignal.instance.setFcmToken(token);
/// }
AppHelper?.instance?.appConfig = WooSignalApp();
AppHelper.instance.appConfig.themeFont = "Poppins";
AppHelper.instance.appConfig.themeColors = {
'light': {
'background': '0xFFFFFFFF',
'primary_text': '0xFF000000',
'button_background': '0xFF529cda',
'button_text': '0xFFFFFFFF',
'app_bar_background': '0xFFFFFFFF',
'app_bar_text': '0xFF3a3d40',
},
'dark': {
'background': '0xFF212121',
'primary_text': '0xFFE1E1E1',
'button_background': '0xFFFFFFFF',
'button_text': '0xFF232c33',
'app_bar_background': '0xFF2C2C2C',
'app_bar_text': '0xFFFFFFFF',
}
};
// WooSignal Setup
WooSignalApp wooSignalApp = await appWooSignal((api) => api.getApp());
Locale locale = Locale('en');
if (wooSignalApp != null) {
AppHelper.instance.appConfig = wooSignalApp;
if (wooSignalApp.wpLoginEnabled == 1) {
WPJsonAPI.instance.initWith(
baseUrl: wooSignalApp.wpLoginBaseUrl,
shouldDebug: getEnv('APP_DEBUG'),
wpJsonPath: wooSignalApp.wpLoginWpApiPath,
);
}
if (getEnv('DEFAULT_LOCALE', defaultValue: null) == null &&
wooSignalApp.locale != null) {
locale = Locale(wooSignalApp.locale);
} else {
locale = Locale(envVal('DEFAULT_LOCALE', defaultValue: 'en'));
}
}
/// NyLocalization
await NyLocalization.instance.init(
localeType: localeType,
languageCode: locale.languageCode,
languagesList: languagesList,
assetsDirectory: assetsDirectory,
valuesAsMap: valuesAsMap);
} }

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -15,17 +15,18 @@ import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/app/models/cart_line_item.dart'; import 'package:flutter_app/app/models/cart_line_item.dart';
import 'package:flutter_app/app/models/checkout_session.dart'; import 'package:flutter_app/app/models/checkout_session.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart'; import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
import 'package:woosignal/models/payload/order_wc.dart'; import 'package:woosignal/models/payload/order_wc.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async { Future<OrderWC> buildOrderWC({TaxRate? taxRate, bool markPaid = true}) async {
CheckoutSession checkoutSession = CheckoutSession.getInstance; CheckoutSession checkoutSession = CheckoutSession.getInstance;
OrderWC orderWC = OrderWC(); OrderWC orderWC = OrderWC();
WooSignalApp wooSignalApp = AppHelper.instance.appConfig; WooSignalApp wooSignalApp = AppHelper.instance.appConfig!;
String paymentMethodName = checkoutSession.paymentType.name ?? ""; String paymentMethodName = checkoutSession.paymentType!.name;
orderWC.paymentMethod = Platform.isAndroid orderWC.paymentMethod = Platform.isAndroid
? "$paymentMethodName - Android App" ? "$paymentMethodName - Android App"
@ -35,9 +36,10 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
orderWC.setPaid = markPaid; orderWC.setPaid = markPaid;
orderWC.status = "pending"; orderWC.status = "pending";
orderWC.currency = wooSignalApp.currencyMeta.code.toUpperCase(); orderWC.currency = wooSignalApp.currencyMeta!.code!.toUpperCase();
orderWC.customerId = orderWC.customerId = (wooSignalApp.wpLoginEnabled == 1)
(wooSignalApp.wpLoginEnabled == 1) ? int.parse(await readUserId()) : 0; ? int.parse(await (readUserId()) ?? "0")
: 0;
List<LineItems> lineItems = []; List<LineItems> lineItems = [];
List<CartLineItem> cartItems = await Cart.getInstance.getCart(); List<CartLineItem> cartItems = await Cart.getInstance.getCart();
@ -50,55 +52,56 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
tmpLineItem.variationId = cartItem.variationId; tmpLineItem.variationId = cartItem.variationId;
} }
tmpLineItem.subtotal = cartItem.subtotal; tmpLineItem.subtotal = (parseWcPrice(cartItem.subtotal) * parseWcPrice(cartItem.quantity.toString())).toString();
lineItems.add(tmpLineItem); lineItems.add(tmpLineItem);
} }
orderWC.lineItems = lineItems; orderWC.lineItems = lineItems;
BillingDetails billingDetails = checkoutSession.billingDetails; BillingDetails billingDetails = checkoutSession.billingDetails!;
Billing billing = Billing(); Billing billing = Billing();
billing.firstName = billingDetails.billingAddress.firstName; billing.firstName = billingDetails.billingAddress?.firstName;
billing.lastName = billingDetails.billingAddress.lastName; billing.lastName = billingDetails.billingAddress?.lastName;
billing.address1 = billingDetails.billingAddress.addressLine; billing.address1 = billingDetails.billingAddress?.addressLine;
billing.city = billingDetails.billingAddress.city; billing.city = billingDetails.billingAddress?.city;
billing.postcode = billingDetails.billingAddress.postalCode; billing.postcode = billingDetails.billingAddress?.postalCode;
billing.email = billingDetails.billingAddress.emailAddress; billing.email = billingDetails.billingAddress?.emailAddress;
if (billingDetails.billingAddress.phoneNumber != "") { if (billingDetails.billingAddress?.phoneNumber != "") {
billing.phone = billingDetails.billingAddress.phoneNumber; billing.phone = billingDetails.billingAddress?.phoneNumber;
} }
if (billingDetails.billingAddress.customerCountry.hasState()) { if (billingDetails.billingAddress?.customerCountry?.hasState() ?? false) {
billing.state = billingDetails.billingAddress.customerCountry.state.name; billing.state = billingDetails.billingAddress?.customerCountry!.state!.name;
} }
billing.country = billingDetails.billingAddress.customerCountry.name; billing.country = billingDetails.billingAddress?.customerCountry!.name;
orderWC.billing = billing; orderWC.billing = billing;
Shipping shipping = Shipping(); Shipping shipping = Shipping();
shipping.firstName = billingDetails.shippingAddress.firstName; shipping.firstName = billingDetails.shippingAddress!.firstName;
shipping.lastName = billingDetails.shippingAddress.lastName; shipping.lastName = billingDetails.shippingAddress!.lastName;
shipping.address1 = billingDetails.shippingAddress.addressLine; shipping.address1 = billingDetails.shippingAddress!.addressLine;
shipping.city = billingDetails.shippingAddress.city; shipping.city = billingDetails.shippingAddress!.city;
shipping.postcode = billingDetails.shippingAddress.postalCode; shipping.postcode = billingDetails.shippingAddress!.postalCode;
if (billingDetails.shippingAddress.customerCountry.hasState()) { if (billingDetails.shippingAddress!.customerCountry!.hasState()) {
billing.state = billingDetails.shippingAddress.customerCountry.state.name; billing.state =
billingDetails.shippingAddress!.customerCountry!.state!.name;
} }
billing.country = billingDetails.shippingAddress.customerCountry.name; billing.country = billingDetails.shippingAddress!.customerCountry!.name;
orderWC.shipping = shipping; orderWC.shipping = shipping;
orderWC.shippingLines = []; orderWC.shippingLines = [];
if (wooSignalApp.disableShipping != 1) { if (wooSignalApp.disableShipping != 1) {
Map<String, dynamic> shippingLineFeeObj = Map<String, dynamic>? shippingLineFeeObj =
checkoutSession.shippingType.toShippingLineFee(); checkoutSession.shippingType!.toShippingLineFee();
if (shippingLineFeeObj != null) { if (shippingLineFeeObj != null) {
ShippingLines shippingLine = ShippingLines(); ShippingLines shippingLine = ShippingLines();
shippingLine.methodId = shippingLineFeeObj['method_id']; shippingLine.methodId = shippingLineFeeObj['method_id'];
shippingLine.methodTitle = shippingLineFeeObj['method_title']; shippingLine.methodTitle = shippingLineFeeObj['method_title'];
shippingLine.total = shippingLineFeeObj['total']; shippingLine.total = shippingLineFeeObj['total'];
orderWC.shippingLines.add(shippingLine); orderWC.shippingLines!.add(shippingLine);
} }
} }
@ -109,13 +112,13 @@ Future<OrderWC> buildOrderWC({TaxRate taxRate, bool markPaid = true}) async {
feeLines.total = await Cart.getInstance.taxAmount(taxRate); feeLines.total = await Cart.getInstance.taxAmount(taxRate);
feeLines.taxClass = ""; feeLines.taxClass = "";
feeLines.taxStatus = "taxable"; feeLines.taxStatus = "taxable";
orderWC.feeLines.add(feeLines); orderWC.feeLines!.add(feeLines);
} }
if (checkoutSession.coupon != null) { if (checkoutSession.coupon != null) {
orderWC.couponLines = []; orderWC.couponLines = [];
CouponLines couponLine = CouponLines(code: checkoutSession.coupon.code); CouponLines couponLine = CouponLines(code: checkoutSession.coupon!.code);
orderWC.couponLines.add(couponLine); orderWC.couponLines!.add(couponLine);
} }
return orderWC; return orderWC;

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,15 +1,11 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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.
enum WishlistAction { add, remove }
enum WishlistAction {
add,
remove
}

View File

@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/themes/styles/color_styles.dart';
import 'package:nylo_framework/nylo_framework.dart';
extension NyText on Text {
/// Sets the color from your [ColorStyles] or [Color].
Text setColor(
BuildContext context, Color Function(ColorStyles color) newColor,
{String? themeId}) {
return copyWith(
style: TextStyle(
color: newColor(ThemeColor.get(context, themeId: themeId))));
}
}
/// Check if the [Product] is new.
extension DateTimeExtension on DateTime? {
bool? isAfterOrEqualTo(DateTime dateTime) {
final date = this;
if (date != null) {
final isAtSameMomentAs = dateTime.isAtSameMomentAs(date);
return isAtSameMomentAs | date.isAfter(dateTime);
}
return null;
}
bool? isBeforeOrEqualTo(DateTime dateTime) {
final date = this;
if (date != null) {
final isAtSameMomentAs = dateTime.isAtSameMomentAs(date);
return isAtSameMomentAs | date.isBefore(dateTime);
}
return null;
}
bool? isBetween(
DateTime fromDateTime,
DateTime toDateTime,
) {
final date = this;
if (date != null) {
final isAfter = date.isAfterOrEqualTo(fromDateTime) ?? false;
final isBefore = date.isBeforeOrEqualTo(toDateTime) ?? false;
return isAfter && isBefore;
}
return null;
}
}

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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,6 +9,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'dart:convert'; import 'dart:convert';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_app/app/models/billing_details.dart'; import 'package:flutter_app/app/models/billing_details.dart';
import 'package:flutter_app/app/models/cart.dart'; import 'package:flutter_app/app/models/cart.dart';
@ -19,11 +20,12 @@ import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/models/user.dart'; import 'package:flutter_app/app/models/user.dart';
import 'package:flutter_app/bootstrap/app_helper.dart'; import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart'; import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
import 'package:flutter_app/bootstrap/extensions.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart'; import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:flutter_app/config/app_currency.dart'; import 'package:flutter_app/config/currency.dart';
import 'package:flutter_app/config/app_payment_gateways.dart'; import 'package:flutter_app/config/decoders.dart';
import 'package:flutter_app/config/app_theme.dart'; import 'package:flutter_app/config/events.dart';
import 'package:flutter_app/resources/themes/styles/base_styles.dart'; import 'package:flutter_app/config/payment_gateways.dart';
import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart'; import 'package:flutter_app/resources/widgets/no_results_for_products_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
@ -34,65 +36,81 @@ import 'package:flutter_web_browser/flutter_web_browser.dart';
import 'package:math_expressions/math_expressions.dart'; import 'package:math_expressions/math_expressions.dart';
import 'package:money_formatter/money_formatter.dart'; import 'package:money_formatter/money_formatter.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:platform_alert_dialog/platform_alert_dialog.dart'; import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:status_alert/status_alert.dart'; import 'package:status_alert/status_alert.dart';
import 'package:woosignal/models/response/products.dart'; import 'package:woosignal/models/response/product.dart';
import 'package:woosignal/models/response/tax_rate.dart'; import 'package:woosignal/models/response/tax_rate.dart';
import 'package:woosignal/woosignal.dart'; import 'package:woosignal/woosignal.dart';
import 'package:wp_json_api/models/responses/wp_user_info_response.dart';
import '../resources/themes/styles/color_styles.dart';
import 'package:flutter/services.dart' show rootBundle;
Future<User> getUser() async => Future<User?> getUser() async =>
(await NyStorage.read<User>(SharedKey.authUser, model: User())); (await (NyStorage.read<User>(SharedKey.authUser)));
Future appWooSignal(Function(WooSignal) api) async { Future appWooSignal(Function(WooSignal api) api) async {
return await api(WooSignal.instance); return await api(WooSignal.instance);
} }
/// helper to find correct color from the [context]. /// helper to find correct color from the [context].
class ThemeColor { class ThemeColor {
static BaseColorStyles get(BuildContext context) { static ColorStyles get(BuildContext context, {String? themeId}) {
return ((Theme.of(context).brightness == Brightness.light) Nylo nylo = Backpack.instance.read('nylo');
? ThemeConfig.light().colors List<BaseThemeConfig<ColorStyles>> appThemes =
: ThemeConfig.dark().colors); nylo.appThemes as List<BaseThemeConfig<ColorStyles>>;
if (themeId == null) {
BaseThemeConfig<ColorStyles> themeFound = appThemes.firstWhere(
(theme) =>
theme.id ==
getEnv(Theme.of(context).brightness == Brightness.light
? 'LIGHT_THEME_ID'
: 'DARK_THEME_ID'),
orElse: () => appThemes.first);
return themeFound.colors;
}
BaseThemeConfig<ColorStyles> baseThemeConfig = appThemes.firstWhere(
(theme) => theme.id == themeId,
orElse: () => appThemes.first);
return baseThemeConfig.colors;
} }
} }
/// helper to set colors on TextStyle /// helper to set colors on TextStyle
extension ColorsHelper on TextStyle { extension ColorsHelper on TextStyle {
TextStyle setColor( TextStyle setColor(
BuildContext context, Color Function(BaseColorStyles color) newColor) { BuildContext context, Color Function(BaseColorStyles? color) newColor) {
return copyWith(color: newColor(ThemeColor.get(context))); return copyWith(color: newColor(ThemeColor.get(context)));
} }
} }
List<PaymentType> getPaymentTypes() { Future<List<PaymentType?>> getPaymentTypes() async {
List<PaymentType> paymentTypes = []; List<PaymentType?> paymentTypes = [];
for (var appPaymentGateway in app_payment_gateways) { for (var appPaymentGateway in appPaymentGateways) {
if (paymentTypes.firstWhere( if (paymentTypes.firstWhere(
(paymentType) => paymentType.name != appPaymentGateway, (paymentType) => paymentType!.name != appPaymentGateway,
orElse: () => null) == orElse: () => null) ==
null) { null) {
paymentTypes.add(paymentTypeList.firstWhere( paymentTypes.add(paymentTypeList.firstWhereOrNull(
(paymentTypeList) => paymentTypeList.name == appPaymentGateway, (paymentTypeList) => paymentTypeList.name == appPaymentGateway));
orElse: () => null));
} }
} }
if (!app_payment_gateways.contains('Stripe') && if (!appPaymentGateways.contains('Stripe') &&
AppHelper.instance.appConfig.stripeEnabled == true) { AppHelper.instance.appConfig!.stripeEnabled == true) {
paymentTypes.add(paymentTypeList paymentTypes.add(paymentTypeList
.firstWhere((element) => element.name == "Stripe", orElse: () => null)); .firstWhereOrNull((element) => element.name == "Stripe"));
} }
if (!app_payment_gateways.contains('PayPal') && if (!appPaymentGateways.contains('PayPal') &&
AppHelper.instance.appConfig.paypalEnabled == true) { AppHelper.instance.appConfig!.paypalEnabled == true) {
paymentTypes.add(paymentTypeList paymentTypes.add(paymentTypeList
.firstWhere((element) => element.name == "PayPal", orElse: () => null)); .firstWhereOrNull((element) => element.name == "PayPal"));
} }
if (!app_payment_gateways.contains('CashOnDelivery') && if (!appPaymentGateways.contains('CashOnDelivery') &&
AppHelper.instance.appConfig.codEnabled == true) { AppHelper.instance.appConfig!.codEnabled == true) {
paymentTypes.add(paymentTypeList.firstWhere( paymentTypes.add(paymentTypeList
(element) => element.name == "CashOnDelivery", .firstWhereOrNull((element) => element.name == "CashOnDelivery"));
orElse: () => null));
} }
return paymentTypes.where((v) => v != null).toList(); return paymentTypes.where((v) => v != null).toList();
@ -102,21 +120,24 @@ dynamic envVal(String envVal, {dynamic defaultValue}) =>
(getEnv(envVal) ?? defaultValue); (getEnv(envVal) ?? defaultValue);
PaymentType addPayment( PaymentType addPayment(
{@required int id, {required int id,
@required String name, required String name,
@required String desc, required String description,
@required String assetImage, required String assetImage,
@required Function pay}) => required Function pay}) =>
PaymentType( PaymentType(
id: id, id: id,
name: name, name: name,
desc: desc, desc: description,
assetImage: assetImage, assetImage: assetImage,
pay: pay, pay: pay,
); );
showStatusAlert(context, showStatusAlert(context,
{@required String title, String subtitle, IconData icon, int duration}) { {required String title,
required String subtitle,
IconData? icon,
int? duration}) {
StatusAlert.show( StatusAlert.show(
context, context,
duration: Duration(seconds: duration ?? 2), duration: Duration(seconds: duration ?? 2),
@ -126,31 +147,32 @@ showStatusAlert(context,
); );
} }
String parseHtmlString(String htmlString) { String parseHtmlString(String? htmlString) {
var document = parse(htmlString); var document = parse(htmlString);
return parse(document.body.text).documentElement.text; return parse(document.body!.text).documentElement!.text;
} }
String moneyFormatter(double amount) { String moneyFormatter(double amount) {
MoneyFormatter fmf = MoneyFormatter( MoneyFormatter fmf = MoneyFormatter(
amount: amount, amount: amount,
settings: MoneyFormatterSettings( settings: MoneyFormatterSettings(
symbol: AppHelper.instance.appConfig.currencyMeta.symbolNative, symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative,
symbolAndNumberSeparator: ""
), ),
); );
if (app_currency_symbol_position == SymbolPositionType.left) { if (appCurrencySymbolPosition == SymbolPositionType.left) {
return fmf.output.symbolOnLeft; return fmf.output.symbolOnLeft;
} else if (app_currency_symbol_position == SymbolPositionType.right) { } else if (appCurrencySymbolPosition == SymbolPositionType.right) {
return fmf.output.symbolOnRight; return fmf.output.symbolOnRight;
} }
return fmf.output.symbolOnLeft; return fmf.output.symbolOnLeft;
} }
String formatDoubleCurrency({@required double total}) { String formatDoubleCurrency({required double total}) {
return moneyFormatter(total); return moneyFormatter(total);
} }
String formatStringCurrency({@required String total}) { String formatStringCurrency({required String? total}) {
double tmpVal = 0; double tmpVal = 0;
if (total != null && total != "") { if (total != null && total != "") {
tmpVal = parseWcPrice(total); tmpVal = parseWcPrice(total);
@ -159,20 +181,24 @@ String formatStringCurrency({@required String total}) {
} }
String workoutSaleDiscount( String workoutSaleDiscount(
{@required String salePrice, @required String priceBefore}) { {required String? salePrice, required String? priceBefore}) {
double dSalePrice = parseWcPrice(salePrice); double dSalePrice = parseWcPrice(salePrice);
double dPriceBefore = parseWcPrice(priceBefore); double dPriceBefore = parseWcPrice(priceBefore);
return ((dPriceBefore - dSalePrice) * (100 / dPriceBefore)) return ((dPriceBefore - dSalePrice) * (100 / dPriceBefore))
.toStringAsFixed(0); .toStringAsFixed(0);
} }
openBrowserTab({@required String url}) async { openBrowserTab({required String url}) async {
await FlutterWebBrowser.openWebPage( await FlutterWebBrowser.openWebPage(
url: url, url: url,
customTabsOptions: CustomTabsOptions(toolbarColor: Colors.white70)); customTabsOptions: CustomTabsOptions(
defaultColorSchemeParams:
CustomTabsColorSchemeParams(toolbarColor: Colors.white70),
),
);
} }
bool isNumeric(String str) { bool isNumeric(String? str) {
if (str == null) { if (str == null) {
return false; return false;
} }
@ -180,18 +206,18 @@ bool isNumeric(String str) {
} }
checkout( checkout(
TaxRate taxRate, TaxRate? taxRate,
Function(String total, BillingDetails billingDetails, Cart cart) Function(String total, BillingDetails? billingDetails, Cart cart)
completeCheckout) async { completeCheckout) async {
String cartTotal = await CheckoutSession.getInstance String cartTotal = await CheckoutSession.getInstance
.total(withFormat: false, taxRate: taxRate); .total(withFormat: false, taxRate: taxRate);
BillingDetails billingDetails = CheckoutSession.getInstance.billingDetails; BillingDetails? billingDetails = CheckoutSession.getInstance.billingDetails;
Cart cart = Cart.getInstance; Cart cart = Cart.getInstance;
return await completeCheckout(cartTotal, billingDetails, cart); return await completeCheckout(cartTotal, billingDetails, cart);
} }
double strCal({@required String sum}) { double? strCal({required String sum}) {
if (sum == null || sum == "") { if (sum == "") {
return 0; return 0;
} }
Parser p = Parser(); Parser p = Parser();
@ -200,7 +226,7 @@ double strCal({@required String sum}) {
return exp.evaluate(EvaluationType.REAL, cm); return exp.evaluate(EvaluationType.REAL, cm);
} }
Future<double> workoutShippingCostWC({@required String sum}) async { Future<double?> workoutShippingCostWC({required String? sum}) async {
if (sum == null || sum == "") { if (sum == null || sum == "") {
return 0; return 0;
} }
@ -219,27 +245,27 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
if (replace.groupCount < 1) { if (replace.groupCount < 1) {
return "()"; return "()";
} }
String newSum = replace.group(1); String newSum = replace.group(1)!;
// PERCENT // PERCENT
String percentVal = newSum.replaceAllMapped( String percentVal = newSum.replaceAllMapped(
defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) { defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) {
if (replacePercent != null && replacePercent.groupCount >= 1) { if (replacePercent.groupCount >= 1) {
String strPercentage = "( (" + String strPercentage = "( (" +
orderTotal.toString() + orderTotal.toString() +
" * " + " * " +
replacePercent.group(1).toString() + replacePercent.group(1).toString() +
") / 100 )"; ") / 100 )";
double calPercentage = strCal(sum: strPercentage); double? calPercentage = strCal(sum: strPercentage);
// MIN // MIN
String strRegexMinFee = r'min_fee="([0-9\.]+)"'; String strRegexMinFee = r'min_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMinFee).hasMatch(newSum)) { if (defaultRegex(strRegexMinFee).hasMatch(newSum)) {
String strMinFee = String strMinFee =
defaultRegex(strRegexMinFee).firstMatch(newSum).group(1) ?? "0"; defaultRegex(strRegexMinFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMinFee = double.parse(strMinFee); double doubleMinFee = double.parse(strMinFee);
if (calPercentage < doubleMinFee) { if (calPercentage! < doubleMinFee) {
return "(" + doubleMinFee.toString() + ")"; return "(" + doubleMinFee.toString() + ")";
} }
newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), ""); newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), "");
@ -249,10 +275,10 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
String strRegexMaxFee = r'max_fee="([0-9\.]+)"'; String strRegexMaxFee = r'max_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) { if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) {
String strMaxFee = String strMaxFee =
defaultRegex(strRegexMaxFee).firstMatch(newSum).group(1) ?? "0"; defaultRegex(strRegexMaxFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMaxFee = double.parse(strMaxFee); double doubleMaxFee = double.parse(strMaxFee);
if (calPercentage > doubleMaxFee) { if (calPercentage! > doubleMaxFee) {
return "(" + doubleMaxFee.toString() + ")"; return "(" + doubleMaxFee.toString() + ")";
} }
newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), ""); newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), "");
@ -273,13 +299,13 @@ Future<double> workoutShippingCostWC({@required String sum}) async {
return strCal(sum: sum); return strCal(sum: sum);
} }
Future<double> workoutShippingClassCostWC( Future<double?> workoutShippingClassCostWC(
{@required String sum, List<CartLineItem> cartLineItem}) async { {required String? sum, List<CartLineItem>? cartLineItem}) async {
if (sum == null || sum == "") { if (sum == null || sum == "") {
return 0; return 0;
} }
sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) { sum = sum.replaceAllMapped(defaultRegex(r'\[qty\]', strict: true), (replace) {
return cartLineItem return cartLineItem!
.map((f) => f.quantity) .map((f) => f.quantity)
.toList() .toList()
.reduce((i, d) => i + d) .reduce((i, d) => i + d)
@ -292,27 +318,27 @@ Future<double> workoutShippingClassCostWC(
if (replace.groupCount < 1) { if (replace.groupCount < 1) {
return "()"; return "()";
} }
String newSum = replace.group(1); String newSum = replace.group(1)!;
// PERCENT // PERCENT
String percentVal = newSum.replaceAllMapped( String percentVal = newSum.replaceAllMapped(
defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) { defaultRegex(r'percent="([0-9\.]+)"'), (replacePercent) {
if (replacePercent != null && replacePercent.groupCount >= 1) { if (replacePercent.groupCount >= 1) {
String strPercentage = "( (" + String strPercentage = "( (" +
orderTotal.toString() + orderTotal.toString() +
" * " + " * " +
replacePercent.group(1).toString() + replacePercent.group(1).toString() +
") / 100 )"; ") / 100 )";
double calPercentage = strCal(sum: strPercentage); double? calPercentage = strCal(sum: strPercentage);
// MIN // MIN
String strRegexMinFee = r'min_fee="([0-9\.]+)"'; String strRegexMinFee = r'min_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMinFee).hasMatch(newSum)) { if (defaultRegex(strRegexMinFee).hasMatch(newSum)) {
String strMinFee = String strMinFee =
defaultRegex(strRegexMinFee).firstMatch(newSum).group(1) ?? "0"; defaultRegex(strRegexMinFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMinFee = double.parse(strMinFee); double doubleMinFee = double.parse(strMinFee);
if (calPercentage < doubleMinFee) { if (calPercentage! < doubleMinFee) {
return "(" + doubleMinFee.toString() + ")"; return "(" + doubleMinFee.toString() + ")";
} }
newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), ""); newSum = newSum.replaceAll(defaultRegex(strRegexMinFee), "");
@ -322,10 +348,10 @@ Future<double> workoutShippingClassCostWC(
String strRegexMaxFee = r'max_fee="([0-9\.]+)"'; String strRegexMaxFee = r'max_fee="([0-9\.]+)"';
if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) { if (defaultRegex(strRegexMaxFee).hasMatch(newSum)) {
String strMaxFee = String strMaxFee =
defaultRegex(strRegexMaxFee).firstMatch(newSum).group(1) ?? "0"; defaultRegex(strRegexMaxFee).firstMatch(newSum)!.group(1) ?? "0";
double doubleMaxFee = double.parse(strMaxFee); double doubleMaxFee = double.parse(strMaxFee);
if (calPercentage > doubleMaxFee) { if (calPercentage! > doubleMaxFee) {
return "(" + doubleMaxFee.toString() + ")"; return "(" + doubleMaxFee.toString() + ")";
} }
newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), ""); newSum = newSum.replaceAll(defaultRegex(strRegexMaxFee), "");
@ -348,7 +374,7 @@ Future<double> workoutShippingClassCostWC(
RegExp defaultRegex( RegExp defaultRegex(
String pattern, { String pattern, {
bool strict, bool? strict,
}) { }) {
return RegExp( return RegExp(
pattern, pattern,
@ -365,10 +391,10 @@ bool isEmail(String em) {
} }
navigatorPush(BuildContext context, navigatorPush(BuildContext context,
{@required String routeName, {required String routeName,
Object arguments, Object? arguments,
bool forgetAll = false, bool forgetAll = false,
int forgetLast}) { int? forgetLast}) {
if (forgetAll) { if (forgetAll) {
Navigator.of(context).pushNamedAndRemoveUntil( Navigator.of(context).pushNamedAndRemoveUntil(
routeName, (Route<dynamic> route) => false, routeName, (Route<dynamic> route) => false,
@ -383,51 +409,11 @@ navigatorPush(BuildContext context,
Navigator.of(context).pushNamed(routeName, arguments: arguments); Navigator.of(context).pushNamed(routeName, arguments: arguments);
} }
PlatformDialogAction dialogAction(BuildContext context,
{@required title, ActionType actionType, Function() action}) {
return PlatformDialogAction(
actionType: actionType ?? ActionType.Default,
child: Text(title ?? ""),
onPressed: action ??
() {
Navigator.of(context).pop();
},
);
}
showPlatformAlertDialog(BuildContext context,
{String title,
String subtitle,
List<PlatformDialogAction> actions,
bool showDoneAction = true}) {
if (showDoneAction) {
actions.add(dialogAction(context, title: trans("Done"), action: () {
Navigator.of(context).pop();
}));
}
showDialog<void>(
context: context,
builder: (BuildContext context) {
return PlatformAlertDialog(
title: Text(title ?? ""),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(subtitle ?? ""),
],
),
),
actions: actions,
);
},
);
}
DateTime parseDateTime(String strDate) => DateTime.parse(strDate); DateTime parseDateTime(String strDate) => DateTime.parse(strDate);
DateFormat formatDateTime(String format) => DateFormat(format); DateFormat formatDateTime(String format) => DateFormat(format);
String dateFormatted({@required String date, @required String formatType}) => String dateFormatted({required String date, required String formatType}) =>
formatDateTime(formatType).format(parseDateTime(date)); formatDateTime(formatType).format(parseDateTime(date));
enum FormatType { enum FormatType {
@ -457,20 +443,20 @@ String formatForDateTime(FormatType formatType) {
} }
} }
double parseWcPrice(String price) => (double.tryParse(price ?? "0") ?? 0); double parseWcPrice(String? price) => (double.tryParse(price ?? "0") ?? 0);
Widget refreshableScroll(context, Widget refreshableScroll(context,
{@required refreshController, {required refreshController,
@required VoidCallback onRefresh, required VoidCallback onRefresh,
@required VoidCallback onLoading, required VoidCallback onLoading,
@required List<Product> products, required List<Product> products,
@required onTap, required onTap,
key}) { key}) {
return SmartRefresher( return SmartRefresher(
enablePullDown: true, enablePullDown: true,
enablePullUp: true, enablePullUp: true,
footer: CustomFooter( footer: CustomFooter(
builder: (BuildContext context, LoadStatus mode) { builder: (BuildContext context, LoadStatus? mode) {
Widget body; Widget body;
if (mode == LoadStatus.idle) { if (mode == LoadStatus.idle) {
body = Text(trans("pull up load")); body = Text(trans("pull up load"));
@ -492,24 +478,24 @@ Widget refreshableScroll(context,
controller: refreshController, controller: refreshController,
onRefresh: onRefresh, onRefresh: onRefresh,
onLoading: onLoading, onLoading: onLoading,
child: (products.length != null && products.isNotEmpty child: products.isEmpty
? StaggeredGridView.countBuilder( ? NoResultsForProductsWidget()
: StaggeredGrid.count(
crossAxisCount: 2, crossAxisCount: 2,
itemCount: products.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 200,
child: ProductItemContainer(
product: products[index],
onTap: onTap,
),
);
},
staggeredTileBuilder: (int index) => StaggeredTile.fit(1),
mainAxisSpacing: 4.0, mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0, crossAxisSpacing: 4.0,
) children: products.map((product) {
: NoResultsForProductsWidget()), return StaggeredGridTile.fit(
crossAxisCellCount: 1,
child: Container(
height: 350,
child: ProductItemContainer(
product: product,
onTap: onTap,
),
),
);
}).toList()),
); );
} }
@ -520,9 +506,9 @@ class UserAuth {
String redirect = "/home"; String redirect = "/home";
} }
Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async { Future<List<DefaultShipping>> getDefaultShipping() async {
String data = await DefaultAssetBundle.of(context) String data =
.loadString("public/assets/json/default_shipping.json"); await rootBundle.loadString('public/assets/json/default_shipping.json');
dynamic dataJson = json.decode(data); dynamic dataJson = json.decode(data);
List<DefaultShipping> shipping = []; List<DefaultShipping> shipping = [];
@ -540,44 +526,157 @@ Future<List<DefaultShipping>> getDefaultShipping(BuildContext context) async {
return shipping; return shipping;
} }
Future<DefaultShipping?> findCountryMetaForShipping(String countryCode) async {
List<DefaultShipping> defaultShipping = await getDefaultShipping();
List<DefaultShipping> shippingByCountryCode =
defaultShipping.where((element) => element.code == countryCode).toList();
if (shippingByCountryCode.isNotEmpty) {
return shippingByCountryCode.first;
}
return null;
}
DefaultShippingState? findDefaultShippingStateByCode(
DefaultShipping defaultShipping, String code) {
List<DefaultShippingState> defaultShippingStates =
defaultShipping.states.where((state) => state.code == code).toList();
if (defaultShippingStates.isEmpty) {
return null;
}
DefaultShippingState defaultShippingState = defaultShippingStates.first;
return DefaultShippingState(
code: defaultShippingState.code, name: defaultShippingState.name);
}
bool hasKeyInMeta(WPUserInfoResponse wpUserInfoResponse, String key) {
return (wpUserInfoResponse.data!.metaData ?? [])
.where((meta) => meta.key == key)
.toList()
.isNotEmpty;
}
String fetchValueInMeta(WPUserInfoResponse wpUserInfoResponse, String key) {
String value = "";
List<dynamic>? metaDataValue = (wpUserInfoResponse.data!.metaData ?? [])
.where((meta) => meta.key == key)
.first
.value;
if (metaDataValue != null && metaDataValue.isNotEmpty) {
return metaDataValue.first ?? "";
}
return value;
}
String truncateString(String data, int length) { String truncateString(String data, int length) {
return (data.length >= length) ? '${data.substring(0, length)}...' : data; return (data.length >= length) ? '${data.substring(0, length)}...' : data;
} }
Future<List<dynamic>> getWishlistProducts() async { Future<List<dynamic>> getWishlistProducts() async {
List<dynamic> favouriteProducts = []; List<dynamic> favouriteProducts = [];
String currentProductsJSON = await NyStorage.read(SharedKey.wishlistProducts); String? currentProductsJSON =
await (NyStorage.read(SharedKey.wishlistProducts));
if (currentProductsJSON != null) { if (currentProductsJSON != null) {
favouriteProducts = favouriteProducts = (jsonDecode(currentProductsJSON)).toList();
(jsonDecode(currentProductsJSON) as List<dynamic>).toList();
} }
return favouriteProducts; return favouriteProducts;
} }
hasAddedWishlistProduct(int productId) async { hasAddedWishlistProduct(int? productId) async {
List<dynamic> favouriteProducts = await getWishlistProducts(); List<dynamic> favouriteProducts = await getWishlistProducts();
List<int> productIds = List<int> productIds =
favouriteProducts.map((e) => e['id']).cast<int>().toList(); favouriteProducts.map((e) => e['id']).cast<int>().toList();
if (productIds.isEmpty) { if (productIds.isEmpty) {
return false; return false;
} }
return productIds.contains(productId); return productIds.contains(productId);
} }
saveWishlistProduct({@required Product product}) async { saveWishlistProduct({required Product? product}) async {
List<dynamic> products = await getWishlistProducts(); List<dynamic> products = await getWishlistProducts();
if (products.any((wishListProduct) => wishListProduct['id'] == product.id) == if (products.any((wishListProduct) => wishListProduct['id'] == product!.id) ==
false) { false) {
products.add({"id": product.id}); products.add({"id": product!.id});
} }
String json = jsonEncode(products.map((i) => {"id": i['id']}).toList()); String json = jsonEncode(products.map((i) => {"id": i['id']}).toList());
await NyStorage.store(SharedKey.wishlistProducts, json); await NyStorage.store(SharedKey.wishlistProducts, json);
} }
removeWishlistProduct({@required Product product}) async { removeWishlistProduct({required Product? product}) async {
List<dynamic> products = await getWishlistProducts(); List<dynamic> products = await getWishlistProducts();
products.removeWhere((element) => element['id'] == product.id); products.removeWhere((element) => element['id'] == product!.id);
String json = jsonEncode(products.map((i) => {"id": i['id']}).toList()); String json = jsonEncode(products.map((i) => {"id": i['id']}).toList());
await NyStorage.store(SharedKey.wishlistProducts, json); await NyStorage.store(SharedKey.wishlistProducts, json);
} }
Future<BillingDetails> billingDetailsFromWpUserInfoResponse(
wpUserInfoResponse) async {
List<String> metaDataAddress = [
'billing_first_name',
'billing_last_name',
'billing_company',
'billing_address_1',
'billing_address_2',
'billing_city',
'billing_postcode',
'billing_country',
'billing_state',
'billing_phone',
'billing_email',
'shipping_first_name',
'shipping_last_name',
'shipping_company',
'shipping_address_1',
'shipping_address_2',
'shipping_city',
'shipping_postcode',
'shipping_country',
'shipping_state',
'shipping_phone',
];
Map<String, String> metaData = {};
for (var dataKey in metaDataAddress) {
if (hasKeyInMeta(wpUserInfoResponse, dataKey)) {
String value = fetchValueInMeta(wpUserInfoResponse, dataKey);
metaData.addAll({dataKey: value});
}
}
BillingDetails billingDetails = BillingDetails();
await billingDetails.fromWpMeta(metaData);
return billingDetails;
}
/// API helper
api<T>(dynamic Function(T) request, {BuildContext? context}) async =>
await nyApi<T>(
request: request, apiDecoders: apiDecoders, context: context);
/// Event helper
event<T>({Map? data}) async => nyEvent<T>(params: data, events: events);
/// Check if the [Product] is new.
bool isProductNew(Product? product) {
if (product?.dateCreatedGMT == null) false;
try {
DateTime dateTime = DateTime.parse(product!.dateCreatedGMT!);
return dateTime.isBetween(DateTime.now().subtract(Duration(days: 2)), DateTime.now()) ?? false;
} on Exception catch (e) {
NyLogger.error(e.toString());
}
return false;
}
bool shouldEncrypt() {
String? encryptKey = getEnv('ENCRYPT_KEY', defaultValue: "");
if (encryptKey == null || encryptKey == "") {
return false;
}
String? encryptSecret = getEnv('ENCRYPT_KEY', defaultValue: "");
if (encryptSecret == null || encryptSecret == "") {
return false;
}
return true;
}

View File

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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

@ -1,7 +1,7 @@
// Label StoreMax // Label StoreMax
// //
// Created by Anthony Gordon. // Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved. // 2023, WooSignal Ltd. 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
@ -12,13 +12,13 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter_app/app/models/cart.dart'; import 'package:flutter_app/app/models/cart.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart'; import 'package:flutter_app/bootstrap/shared_pref/shared_key.dart';
import 'package:nylo_support/helpers/helper.dart'; import 'package:nylo_framework/nylo_framework.dart';
Future<bool> authCheck() async => ((await getUser()) != null); Future<bool> authCheck() async => ((await getUser()) != null);
Future<String> readAuthToken() async => (await getUser()).token; Future<String?> readAuthToken() async => (await getUser())!.token;
Future<String> readUserId() async => (await getUser()).userId; Future<String?> readUserId() async => (await getUser())!.userId;
authLogout(BuildContext context) async { authLogout(BuildContext context) async {
await NyStorage.delete(SharedKey.authUser); await NyStorage.delete(SharedKey.authUser);

View File

@ -18,7 +18,7 @@ import 'package:flutter_app/bootstrap/enums/symbol_position_enums.dart';
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
const SymbolPositionType app_currency_symbol_position = SymbolPositionType.left; const SymbolPositionType appCurrencySymbolPosition = SymbolPositionType.left;
// currency_symbol_position example. // currency_symbol_position example.
// left: $15 // left: $15
// right: 15 // right: 15

View File

@ -0,0 +1,33 @@
import 'package:flutter_app/app/models/user.dart';
import 'package:flutter_app/app/networking/api_service.dart';
import 'package:flutter_app/app/networking/dio/base_api_service.dart';
/*
|--------------------------------------------------------------------------
| Model Decoders
| -------------------------------------------------------------------------
| Model decoders are used in 'app/networking/' for morphing json payloads
| into Models. Learn more https://nylo.dev/docs/5.x/decoders#model-decoders
|--------------------------------------------------------------------------
*/
final Map<Type, dynamic> modelDecoders = {
// ...
User: (data) => User.fromJson(data)
};
/*
|--------------------------------------------------------------------------
| API Decoders
| -------------------------------------------------------------------------
| API decoders are used when you need to access an API service using the
| 'api' helper. E.g. api<MyApiService>((request) => request.fetchData());
| Learn more https://nylo.dev/docs/5.x/decoders#api-decoders
|--------------------------------------------------------------------------
*/
final Map<Type, BaseApiService> apiDecoders = {
ApiService: ApiService(),
// ...
};

View File

@ -0,0 +1,32 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter_app/config/toast_notification.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/toast_notification_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart';
/*
|--------------------------------------------------------------------------
| Design
| Contains widgets used in the Nylo framework.
|
| Learn more: https://nylo.dev/docs/5.x/themes
|--------------------------------------------------------------------------
*/
Widget logo = StoreLogo();
// resources/widgets/woosignal_ui.dart
Widget loader = AppLoaderWidget();
// resources/widgets/app_loader_widget.dart
Widget getToastNotificationWidget({
required ToastNotificationStyleType style,
Function(ToastNotificationStyleMetaHelper helper)? toastNotificationStyleMeta, Function? onDismiss}) {
if (toastNotificationStyleMeta == null) return SizedBox.shrink();
ToastMeta toastMeta = toastNotificationStyleMeta(NyToastNotificationStyleMetaHelper(style));
return ToastNotification(toastMeta, onDismiss: onDismiss);
// resources/widgets/toast_notification.dart
}

View File

@ -0,0 +1,19 @@
import 'package:flutter_app/app/events/login_event.dart';
import 'package:flutter_app/app/events/logout_event.dart';
import 'package:nylo_framework/nylo_framework.dart';
/*
|--------------------------------------------------------------------------
| Events
| Add your "app/events" here.
| Events can be fired using: event<MyEvent>();
|
| Learn more: https://nylo.dev/docs/5.x/events
|--------------------------------------------------------------------------
*/
final Map<Type, NyEvent> events = {
LoginEvent: LoginEvent(),
LogoutEvent: LogoutEvent(),
AuthUserEvent: AuthUserEvent(),
};

View File

@ -18,7 +18,7 @@ final LocaleType localeType = LocaleType.asDefined; // device, asDefined
| The language code should match the name of the file i.e /lang/es.json | The language code should match the name of the file i.e /lang/es.json
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
final String languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en"); final String? languageCode = getEnv('DEFAULT_LOCALE', defaultValue: "en");
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------

View File

@ -1,8 +1,10 @@
import 'package:flutter_app/app/models/payment_type.dart'; import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/providers/cash_on_delivery.dart'; import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart';
import 'package:flutter_app/app/providers/paypal_pay.dart'; import 'package:flutter_app/app/providers/payments/paypal_pay.dart';
import 'package:flutter_app/app/providers/stripe_pay.dart'; import 'package:flutter_app/app/providers/payments/razorpay_pay.dart';
import 'package:flutter_app/app/providers/payments/stripe_pay.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:nylo_framework/nylo_framework.dart';
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -13,15 +15,15 @@ import 'package:flutter_app/bootstrap/helpers.dart';
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
const app_payment_gateways = []; const appPaymentGateways = ["CashOnDelivery"];
// Available: "Stripe", "CashOnDelivery", "PayPal" // Available: "Stripe", "CashOnDelivery", "PayPal", "RazorPay"
// e.g. app_payment_gateways = ["Stripe", "CashOnDelivery"]; will only use Stripe and Cash on Delivery. // e.g. app_payment_gateways = ["Stripe", "CashOnDelivery"]; will only use Stripe and Cash on Delivery.
List<PaymentType> paymentTypeList = [ List<PaymentType> paymentTypeList = [
addPayment( addPayment(
id: 1, id: 1,
name: "Stripe", name: "Stripe",
desc: "Debit or Credit Card", description: trans("Debit or Credit Card"),
assetImage: "dark_powered_by_stripe.png", assetImage: "dark_powered_by_stripe.png",
pay: stripePay, pay: stripePay,
), ),
@ -29,7 +31,7 @@ List<PaymentType> paymentTypeList = [
addPayment( addPayment(
id: 2, id: 2,
name: "CashOnDelivery", name: "CashOnDelivery",
desc: "Cash on delivery", description: trans("Cash on delivery"),
assetImage: "cash_on_delivery.jpeg", assetImage: "cash_on_delivery.jpeg",
pay: cashOnDeliveryPay, pay: cashOnDeliveryPay,
), ),
@ -37,17 +39,25 @@ List<PaymentType> paymentTypeList = [
addPayment( addPayment(
id: 4, id: 4,
name: "PayPal", name: "PayPal",
desc: "Debit or Credit Card", description: trans("Debit or Credit Card"),
assetImage: "paypal_logo.png", assetImage: "paypal_logo.png",
pay: payPalPay, pay: payPalPay,
), ),
addPayment(
id: 5,
name: "RazorPay",
description: trans("Debit or Credit Card"),
assetImage: "razorpay.png",
pay: razorPay,
),
// e.g. add more here // e.g. add more here
// addPayment( // addPayment(
// id: 5, // id: 6,
// name: "MyNewPaymentMethod", // name: "MyNewPaymentMethod",
// desc: "Debit or Credit Card", // description: "Debit or Credit Card",
// assetImage: "add icon image to public/assets/images/myimage.png", // assetImage: "add icon image to public/assets/images/myimage.png",
// pay: "myCustomPaymentFunction", // pay: "myCustomPaymentFunction",
// ), // ),

View File

@ -0,0 +1,24 @@
import '/app/providers/firebase_provider.dart';
import 'package:flutter_app/app/providers/app_provider.dart';
import 'package:flutter_app/app/providers/event_provider.dart';
import 'package:flutter_app/app/providers/route_provider.dart';
import 'package:nylo_framework/nylo_framework.dart';
/*
|--------------------------------------------------------------------------
| Providers
| Add your "app/providers" here.
| Providers are booted when your application start.
|
| Learn more: https://nylo.dev/docs/5.x/providers
|--------------------------------------------------------------------------
*/
final Map<Type, NyProvider> providers = {
AppProvider: AppProvider(),
RouteProvider: RouteProvider(),
EventProvider: EventProvider(),
FirebaseProvider: FirebaseProvider(),
};

View File

@ -0,0 +1,19 @@
/*
|--------------------------------------------------------------------------
| Storage Keys
| Add your storage keys here and then use them later to retrieve data.
| E.g. static String userCoins = "USER_COINS";
| String coins = NyStorage.read( StorageKey.userCoins );
|
| Learn more: https://nylo.dev/docs/5.x/storage#storage-keys
|--------------------------------------------------------------------------
*/
import 'package:nylo_framework/nylo_framework.dart';
class StorageKey {
static String userToken = "USER_TOKEN";
static String authUser = getEnv('AUTH_USER_KEY', defaultValue: 'AUTH_USER');
/// Add your storage keys here...
}

View File

@ -1,9 +1,9 @@
import 'package:flutter_app/bootstrap/base_theme_config.dart';
import 'package:flutter_app/resources/themes/dark_theme.dart'; import 'package:flutter_app/resources/themes/dark_theme.dart';
import 'package:flutter_app/resources/themes/light_theme.dart'; import 'package:flutter_app/resources/themes/light_theme.dart';
import 'package:flutter_app/resources/themes/styles/base_styles.dart'; import 'package:flutter_app/resources/themes/styles/color_styles.dart';
import 'package:flutter_app/resources/themes/styles/dark_theme_colors.dart'; import 'package:flutter_app/resources/themes/styles/dark_theme_colors.dart';
import 'package:flutter_app/resources/themes/styles/light_theme_colors.dart'; import 'package:flutter_app/resources/themes/styles/light_theme_colors.dart';
import 'package:nylo_framework/nylo_framework.dart';
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -12,7 +12,7 @@ import 'package:flutter_app/resources/themes/styles/light_theme_colors.dart';
*/ */
// App Themes // App Themes
final appThemes = [ final List<BaseThemeConfig<ColorStyles>> appThemes = [
ThemeConfig.light(), ThemeConfig.light(),
ThemeConfig.dark(), ThemeConfig.dark(),
]; ];
@ -24,10 +24,10 @@ final appThemes = [
*/ */
// Light Colors // Light Colors
BaseColorStyles lightColors = LightThemeColors(); ColorStyles lightColors = LightThemeColors();
// Dark Colors // Dark Colors
BaseColorStyles darkColors = DarkThemeColors(); ColorStyles darkColors = DarkThemeColors();
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
@ -38,7 +38,7 @@ BaseColorStyles darkColors = DarkThemeColors();
// Preset Themes // Preset Themes
class ThemeConfig { class ThemeConfig {
// LIGHT // LIGHT
static BaseThemeConfig light() => BaseThemeConfig( static BaseThemeConfig<ColorStyles> light() => BaseThemeConfig<ColorStyles>(
id: "default_light_theme", id: "default_light_theme",
description: "Light theme", description: "Light theme",
theme: lightTheme(lightColors), theme: lightTheme(lightColors),
@ -46,7 +46,7 @@ class ThemeConfig {
); );
// DARK // DARK
static BaseThemeConfig dark() => BaseThemeConfig( static BaseThemeConfig<ColorStyles> dark() => BaseThemeConfig<ColorStyles>(
id: "default_dark_theme", id: "default_dark_theme",
description: "Dark theme", description: "Dark theme",
theme: darkTheme(darkColors), theme: darkTheme(darkColors),
@ -60,10 +60,10 @@ class ThemeConfig {
// First add the colors which was created into the above section like the following: // First add the colors which was created into the above section like the following:
// Bright Colors // Bright Colors
/// BaseColorStyles brightColors = BrightThemeColors(); /// ColorStyles brightColors = BrightThemeColors();
// Next, uncomment the below: // Next, uncomment the below:
/// static BaseThemeConfig bright() => BaseThemeConfig( /// static BaseThemeConfig<ColorStyles> bright() => BaseThemeConfig<ColorStyles>(
/// id: "default_bright_theme", /// id: "default_bright_theme",
/// description: "Bright theme", /// description: "Bright theme",
/// theme: brightTheme(brightColors), /// theme: brightTheme(brightColors),

View File

@ -0,0 +1,34 @@
import 'package:nylo_framework/nylo_framework.dart';
/// ToastNotificationStyleMetaHelper is used to return
/// the correct value for the [ToastNotificationStyleType] toast style.
class NyToastNotificationStyleMetaHelper extends ToastNotificationStyleMetaHelper {
NyToastNotificationStyleMetaHelper(ToastNotificationStyleType? style) : super(style);
onSuccess() {
return ToastMeta.success();
}
onWarning() {
return ToastMeta.warning();
}
onInfo() {
return ToastMeta.info();
}
onDanger() {
return ToastMeta.danger();
}
// Example customizing a notification
// onSuccess() {
// return ToastMeta.success(
// title: "Hello",
// description: "World",
// action: () {},
// backgroundColor: Colors.Yellow
// );
// }
}

View File

@ -0,0 +1,36 @@
/*
|--------------------------------------------------------------------------
| Validation Rules
| -------------------------------------------------------------------------
| Add custom validation rules for your project in this file.
| Learn more https://nylo.dev/docs/5.x/validation#custom-validation-rules
|--------------------------------------------------------------------------
*/
final Map<String, dynamic> validationRules = {
/// Example
// "simple_password": (attribute) => SimplePassword(attribute)
};
/// Example validation class
// class SimplePassword extends ValidationRule {
// SimplePassword(String attribute)
// : super(
// attribute: attribute,
// signature: "simple_password", // Use this signature for the validator
// description: "The $attribute field must be between 4 and 8 digits long and include at least one numeric digit", // Toast description when an error occurs
// textFieldMessage: "Must be between 4 and 8 digits long with one numeric digit"); // TextField description when an error occurs
//
// @override
// handle(Map<String, dynamic> info) {
// super.handle(info);
//
// /// info['rule'] = Validation rule i.e "min".
// /// info['data'] = Data the user has passed into the validation.
// /// info['message'] = Overriding message to be displayed for validation (optional).
//
// RegExp regExp = RegExp(r'^(?=.*\d).{4,8}$');
// return regExp.hasMatch(info['data']);
// }
// }

View File

@ -0,0 +1,66 @@
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
import 'package:flutter_app/bootstrap/app_helper.dart';
/// Default [FirebaseOptions] for use with your Firebase apps.
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for web - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
if (AppHelper.instance.appConfig?.firebaseOptionsAndroid == null) {
throw UnsupportedError(
'Add a valid Firebase json config on https://woosignal.com for your WooCommerce store',
);
}
return FirebaseOptions(
apiKey: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['apiKey'],
appId: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['appId'],
messagingSenderId: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['messagingSenderId'],
projectId: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['projectId'],
storageBucket: AppHelper.instance.appConfig!.firebaseOptionsAndroid!['storageBucket'],
);
case TargetPlatform.iOS:
if (AppHelper.instance.appConfig?.firebaseOptionsIos == null) {
throw UnsupportedError(
'Add a valid Firebase plist config on https://woosignal.com for your WooCommerce store',
);
}
return FirebaseOptions(
apiKey: AppHelper.instance.appConfig!.firebaseOptionsIos!['apiKey'],
appId: AppHelper.instance.appConfig!.firebaseOptionsIos!['appId'],
messagingSenderId: AppHelper.instance.appConfig!.firebaseOptionsIos!['messagingSenderId'],
projectId: AppHelper.instance.appConfig!.firebaseOptionsIos!['projectId'],
storageBucket: AppHelper.instance.appConfig!.firebaseOptionsIos!['storageBucket'],
iosClientId: AppHelper.instance.appConfig!.firebaseOptionsIos!['iosClientId'],
iosBundleId: AppHelper.instance.appConfig!.firebaseOptionsIos!['iosBundleId'],
);
case TargetPlatform.macOS:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for macos - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
}

View File

@ -1,20 +0,0 @@
//
// Generated file. Do not edit.
//
// ignore_for_file: directives_ordering
// ignore_for_file: lines_longer_than_80_chars
import 'package:flutter_secure_storage_web/flutter_secure_storage_web.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart';
import 'package:url_launcher_web/url_launcher_web.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
// ignore: public_member_api_docs
void registerPlugins(Registrar registrar) {
FlutterSecureStorageWeb.registerWith(registrar);
SharedPreferencesPlugin.registerWith(registrar);
UrlLauncherPlugin.registerWith(registrar);
registrar.registerMessageHandler();
}

View File

@ -1,24 +1,18 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/app.dart'; import 'package:flutter_app/bootstrap/app.dart';
import 'package:flutter_app/bootstrap/app_helper.dart';
import 'package:flutter_app/bootstrap/boot.dart'; import 'package:flutter_app/bootstrap/boot.dart';
import 'package:flutter_app/routes/router.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
Nylo nylo = await Nylo.init(router: appRouter(), setup: boot); Nylo nylo = await Nylo.init(setup: Boot.nylo, setupFinished: Boot.finished);
String initialRoute = AppHelper.instance.appConfig.appStatus != null
? '/home'
: '/no-connection';
runApp( runApp(
AppBuild( AppBuild(
navigatorKey: nylo.router.navigatorKey, navigatorKey: NyNavigator.instance.router.navigatorKey,
onGenerateRoute: nylo.router.generator(), onGenerateRoute: nylo.router!.generator(),
initialRoute: initialRoute, initialRoute: nylo.getInitialRoute(),
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
), ),
); );
} }

View File

@ -1,234 +0,0 @@
// Label StoreMax
//
// Created by Anthony Gordon.
// 2022, WooSignal Ltd. All rights reserved.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:wp_json_api/models/responses/wc_customer_info_response.dart';
import 'package:wp_json_api/models/responses/wc_customer_updated_response.dart';
import 'package:wp_json_api/wp_json_api.dart';
class AccountBillingDetailsPage extends StatefulWidget {
AccountBillingDetailsPage();
@override
_AccountBillingDetailsPageState createState() =>
_AccountBillingDetailsPageState();
}
class _AccountBillingDetailsPageState extends State<AccountBillingDetailsPage> {
_AccountBillingDetailsPageState();
// BILLING TEXT CONTROLLERS
final TextEditingController _txtShippingFirstName = TextEditingController(),
_txtShippingLastName = TextEditingController(),
_txtShippingAddressLine = TextEditingController(),
_txtShippingCity = TextEditingController(),
_txtShippingState = TextEditingController(),
_txtShippingPostalCode = TextEditingController(),
_txtShippingCountry = TextEditingController();
bool _isLoading = true, _isUpdating = false;
@override
void initState() {
super.initState();
_fetchUserDetails();
}
_fetchUserDetails() async {
WCCustomerInfoResponse wcCustomerInfoResponse =
await WPJsonAPI.instance.api((request) async {
return request.wcCustomerInfo(await readAuthToken());
});
Billing billing = wcCustomerInfoResponse.data.billing;
_txtShippingFirstName.text = billing.firstName;
_txtShippingLastName.text = billing.lastName;
_txtShippingAddressLine.text = billing.address1;
_txtShippingCity.text = billing.city;
_txtShippingState.text = billing.state;
_txtShippingPostalCode.text = billing.postcode;
_txtShippingCountry.text = billing.country;
setState(() {
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: Text(trans("Billing Details")),
centerTitle: true,
),
body: SafeAreaWidget(
child: GestureDetector(
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
child: _isLoading
? AppLoaderWidget()
: LayoutBuilder(
builder: (context, constraints) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
SizedBox(
child: Container(
margin: EdgeInsets.only(top: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: TextEditingRow(
heading: trans("First Name"),
controller: _txtShippingFirstName,
shouldAutoFocus: true,
),
),
Flexible(
child: TextEditingRow(
heading: trans("Last Name"),
controller: _txtShippingLastName,
),
),
],
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
),
TextEditingRow(
heading: trans("Address Line"),
controller: _txtShippingAddressLine,
),
Row(children: <Widget>[
Flexible(
child: TextEditingRow(
heading: trans("City"),
controller: _txtShippingCity,
),
),
Flexible(
child: TextEditingRow(
heading: trans("State"),
keyboardType: TextInputType.emailAddress,
controller: _txtShippingState),
),
]),
Row(
children: <Widget>[
Flexible(
child: TextEditingRow(
heading: trans("Postal code"),
controller: _txtShippingPostalCode,
),
),
Flexible(
child: TextEditingRow(
heading: trans("Country"),
keyboardType: TextInputType.emailAddress,
controller: _txtShippingCountry,
),
),
],
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
)
],
),
decoration: BoxDecoration(
color: ThemeColor.get(context).surfaceBackground,
borderRadius: BorderRadius.circular(10),
boxShadow: (Theme.of(context).brightness ==
Brightness.light)
? wsBoxShadow()
: null,
),
padding: EdgeInsets.all(8),
),
height:
(constraints.maxHeight - constraints.minHeight) *
0.6,
),
Column(
children: <Widget>[
PrimaryButton(
title: trans("UPDATE DETAILS"),
isLoading: _isUpdating,
action: _updateBillingDetails,
),
],
),
],
),
),
),
),
);
}
_updateBillingDetails() async {
String firstName = _txtShippingFirstName.text;
String lastName = _txtShippingLastName.text;
String addressLine = _txtShippingAddressLine.text;
String city = _txtShippingCity.text;
String state = _txtShippingState.text;
String postalCode = _txtShippingPostalCode.text;
String country = _txtShippingCountry.text;
String userToken = await readAuthToken();
setState(() {
_isUpdating = true;
});
WCCustomerUpdatedResponse wcCustomerUpdatedResponse;
try {
wcCustomerUpdatedResponse = await WPJsonAPI.instance.api((request) =>
request.wcUpdateCustomerInfo(userToken,
billingFirstName: firstName,
billingLastName: lastName,
billingAddress1: addressLine,
billingCity: city,
billingState: state,
billingPostcode: postalCode,
billingCountry: country));
} on Exception catch (_) {
showToastNotification(context,
title: trans("Oops!"),
description: trans("Something went wrong"),
style: ToastNotificationStyleType.DANGER);
} finally {
setState(() {
_isUpdating = false;
});
}
if (wcCustomerUpdatedResponse != null &&
wcCustomerUpdatedResponse.status == 200) {
showToastNotification(context,
title: trans("Success"),
description: trans("Account updated"),
style: ToastNotificationStyleType.SUCCESS);
Navigator.pop(context);
}
}
}

View File

@ -0,0 +1,105 @@
// Label StoreMax
//
// Created by Anthony Gordon.
// 2023, WooSignal Ltd. All rights reserved.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
import 'package:flutter_app/resources/widgets/buttons.dart';
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:wp_json_api/models/responses/wp_user_delete_response.dart';
import 'package:wp_json_api/wp_json_api.dart';
class AccountDeletePage extends StatefulWidget {
AccountDeletePage({Key? key}) : super(key: key);
@override
_AccountDeletePageState createState() => _AccountDeletePageState();
}
class _AccountDeletePageState extends NyState<AccountDeletePage> {
@override
init() async {}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(trans("Delete Account")),
),
body: SafeAreaWidget(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.no_accounts_rounded, size: 50),
Text(
trans("Delete your account"),
style: textTheme.displaySmall,
),
Padding(
padding: const EdgeInsets.only(top: 18),
child: Text(trans("Are you sure?")),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
PrimaryButton(
title: trans("Yes, delete my account"),
isLoading: isLocked('delete_account'),
action: _deleteAccount,
),
LinkButton(title: trans("Back"), action: pop)
],
)
],
)),
);
}
_deleteAccount() async {
await lockRelease('delete_account', perform: () async {
String? userToken = await readAuthToken();
WPUserDeleteResponse? wpUserDeleteResponse;
try {
wpUserDeleteResponse = await WPJsonAPI.instance
.api((request) => request.wpUserDelete(userToken));
} on Exception catch (e) {
NyLogger.error(e.toString());
showToastNotification(
context,
title: trans("Oops!"),
description: trans("Something went wrong"),
style: ToastNotificationStyleType.DANGER,
);
}
if (wpUserDeleteResponse != null) {
showToast(
title: trans("Success"), description: trans("Account deleted"));
await authLogout(context);
}
});
}
}

Some files were not shown because too many files have changed in this diff Show More