v6.6.0 updates

This commit is contained in:
Anthony 2023-05-18 19:46:04 +01:00
parent 004c146967
commit da2301a2af
38 changed files with 269 additions and 1523 deletions

View File

@ -50,3 +50,5 @@ RAZORPAY_API_KEY=""
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"

View File

@ -1,3 +1,9 @@
## [6.6.0] - 2023-05-18
* Nylo v5.0.0 migration
* Refactor project
* Flutter v3.10.0 compatibility
## [6.5.1] - 2023-03-04 ## [6.5.1] - 2023-03-04
* New translation added. * New translation added.

View File

@ -4,7 +4,7 @@
# WooCommerce App: Label StoreMax # WooCommerce App: Label StoreMax
### Label StoreMax - v6.5.1 ### Label StoreMax - v6.6.0
[Official WooSignal WooCommerce App](https://woosignal.com) [Official WooSignal WooCommerce App](https://woosignal.com)
@ -44,7 +44,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, RazorPay - Stripe, Cash On Delivery, PayPal
- 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

@ -204,6 +204,7 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (

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>
@ -16,12 +18,8 @@
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string> <string>$(FLUTTER_BUILD_NAME)</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>
@ -39,11 +37,17 @@
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</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>
@ -61,9 +65,5 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@ -10,18 +10,16 @@
import 'package:nylo_framework/nylo_framework.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 fromJson(dynamic data) {
fromStorage(dynamic data) {
token = data['token']; token = data['token'];
userId = data['user_id']; userId = data['user_id'];
} }

View File

@ -8,7 +8,7 @@ import 'package:nylo_framework/nylo_framework.dart';
| ApiService | ApiService
| ------------------------------------------------------------------------- | -------------------------------------------------------------------------
| Define your API endpoints | Define your API endpoints
| Learn more https://nylo.dev/docs/4.x/networking | Learn more https://nylo.dev/docs/5.x/networking
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */

View File

@ -4,8 +4,10 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.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/config/decoders.dart';
import 'package:flutter_app/config/design.dart'; import 'package:flutter_app/config/design.dart';
import 'package:flutter_app/config/theme.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:nylo_framework/nylo_framework.dart';
import 'package:flutter_app/config/localization.dart'; import 'package:flutter_app/config/localization.dart';
import 'package:woosignal/models/response/woosignal_app.dart'; import 'package:woosignal/models/response/woosignal_app.dart';
@ -112,12 +114,14 @@ class AppProvider implements NyProvider {
nylo.appLoader = loader; nylo.appLoader = loader;
nylo.appLogo = logo; nylo.appLogo = logo;
String initialRoute = AppHelper.instance.appConfig!.appStatus != null nylo.addModelDecoders(modelDecoders);
? '/home' nylo.addValidationRules(validationRules);
: '/no-connection';
nylo.initialRoute = initialRoute;
return nylo; return nylo;
} }
@override
afterBoot(Nylo nylo) async {
}
} }

View File

@ -8,4 +8,9 @@ class EventProvider implements NyProvider {
return nylo; return nylo;
} }
@override
afterBoot(Nylo nylo) async {
}
} }

View File

@ -1,81 +0,0 @@
//
// 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) {
Cart.getInstance.clear();
Navigator.pushNamed(context, "/checkout-status", arguments: order);
} else {
showToastNotification(
context,
title: "Error".tr(),
description: trans("Something went wrong, please contact our store"),
);
state.reloadState(showLoader: false);
}
});
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

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

View File

@ -1,12 +1,8 @@
// import 'package:firebase_core/firebase_core.dart';
// import 'package:firebase_messaging/firebase_messaging.dart';
// import 'package:flutter_app/firebase_options.dart';
/// boot application /// boot application
import 'package:flutter_app/config/providers.dart'; import 'package:flutter_app/config/providers.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
class Boot { class Boot {
static Future<Nylo> nylo() async => await bootApplication(providers); static Future<Nylo> nylo() async => await bootApplication(providers);
static Future<void> finished(Nylo nylo) async => await bootFinished(nylo); static Future<void> finished(Nylo nylo) async => await bootFinished(nylo, providers);
} }

View File

@ -138,3 +138,37 @@ extension NyText on Text {
style: style != null ? this.style?.merge(style) ?? style : this.style); style: style != null ? this.style?.merge(style) ?? style : this.style);
} }
} }
/// 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

@ -20,6 +20,7 @@ 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/currency.dart'; import 'package:flutter_app/config/currency.dart';
import 'package:flutter_app/config/decoders.dart'; import 'package:flutter_app/config/decoders.dart';
@ -45,7 +46,7 @@ import '../resources/themes/styles/color_styles.dart';
import 'package:flutter/services.dart' show rootBundle; 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) async {
return await api(WooSignal.instance); return await api(WooSignal.instance);
@ -156,6 +157,7 @@ String moneyFormatter(double amount) {
amount: amount, amount: amount,
settings: MoneyFormatterSettings( settings: MoneyFormatterSettings(
symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative, symbol: AppHelper.instance.appConfig!.currencyMeta!.symbolNative,
symbolAndNumberSeparator: ""
), ),
); );
if (appCurrencySymbolPosition == SymbolPositionType.left) { if (appCurrencySymbolPosition == SymbolPositionType.left) {
@ -486,7 +488,7 @@ Widget refreshableScroll(context,
return StaggeredGridTile.fit( return StaggeredGridTile.fit(
crossAxisCellCount: 1, crossAxisCellCount: 1,
child: Container( child: Container(
height: 200, height: 350,
child: ProductItemContainer( child: ProductItemContainer(
product: product, product: product,
onTap: onTap, onTap: onTap,
@ -654,3 +656,15 @@ api<T>(dynamic Function(T) request, {BuildContext? context}) async =>
/// Event helper /// Event helper
event<T>({Map? data}) async => nyEvent<T>(params: data, events: events); 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;
}

View File

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

View File

@ -7,7 +7,7 @@ import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
| Design | Design
| Contains widgets used in the Nylo framework. | Contains widgets used in the Nylo framework.
| |
| Learn more: https://nylo.dev/docs/4.x/themes | Learn more: https://nylo.dev/docs/5.x/themes
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */

View File

@ -8,7 +8,7 @@ import 'package:nylo_framework/nylo_framework.dart';
| Add your "app/events" here. | Add your "app/events" here.
| Events can be fired using: event<MyEvent>(); | Events can be fired using: event<MyEvent>();
| |
| Learn more: https://nylo.dev/docs/4.x/events | Learn more: https://nylo.dev/docs/5.x/events
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */

View File

@ -1,7 +1,6 @@
import 'package:flutter_app/app/models/payment_type.dart'; import 'package:flutter_app/app/models/payment_type.dart';
import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart'; import 'package:flutter_app/app/providers/payments/cash_on_delivery.dart';
import 'package:flutter_app/app/providers/payments/paypal_pay.dart'; import 'package:flutter_app/app/providers/payments/paypal_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/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'; import 'package:nylo_framework/nylo_framework.dart';
@ -44,14 +43,6 @@ List<PaymentType> paymentTypeList = [
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(

View File

@ -9,7 +9,7 @@ import 'package:nylo_framework/nylo_framework.dart';
| Add your "app/providers" here. | Add your "app/providers" here.
| Providers are booted when your application start. | Providers are booted when your application start.
| |
| Learn more: https://nylo.dev/docs/4.x/providers | Learn more: https://nylo.dev/docs/5.x/providers
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */

View File

@ -5,12 +5,15 @@
| E.g. static String userCoins = "USER_COINS"; | E.g. static String userCoins = "USER_COINS";
| String coins = NyStorage.read( StorageKey.userCoins ); | String coins = NyStorage.read( StorageKey.userCoins );
| |
| Learn more: https://nylo.dev/docs/4.x/storage#storage-keys | Learn more: https://nylo.dev/docs/5.x/storage#storage-keys
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
*/ */
import 'package:nylo_framework/nylo_framework.dart';
class StorageKey { class StorageKey {
static String userToken = "USER_TOKEN"; static String userToken = "USER_TOKEN";
static String authUser = getEnv('AUTH_USER_KEY', defaultValue: 'AUTH_USER');
/// Add your storage keys here... /// Add your storage keys here...
} }

View File

@ -0,0 +1,37 @@
import 'package:nylo_framework/nylo_framework.dart';
/*
|--------------------------------------------------------------------------
| 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<Type, dynamic> validationRules = {
/// Example
// SimplePassword: (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

@ -11,7 +11,7 @@ void main() async {
AppBuild( AppBuild(
navigatorKey: NyNavigator.instance.router.navigatorKey, navigatorKey: NyNavigator.instance.router.navigatorKey,
onGenerateRoute: nylo.router!.generator(), onGenerateRoute: nylo.router!.generator(),
initialRoute: nylo.initialRoute, initialRoute: nylo.getInitialRoute(),
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
), ),
); );

View File

@ -35,11 +35,6 @@ class _AccountLandingPageState extends NyState<AccountLandingPage> {
final TextEditingController _tfEmailController = TextEditingController(), final TextEditingController _tfEmailController = TextEditingController(),
_tfPasswordController = TextEditingController(); _tfPasswordController = TextEditingController();
@override
void initState() {
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -231,7 +226,7 @@ class _AccountLandingPageState extends NyState<AccountLandingPage> {
String? token = wpUserLoginResponse.data!.userToken; String? token = wpUserLoginResponse.data!.userToken;
String userId = wpUserLoginResponse.data!.userId.toString(); String userId = wpUserLoginResponse.data!.userId.toString();
User user = User.fromUserAuthResponse(token: token, userId: userId); User user = User.fromUserAuthResponse(token: token, userId: userId);
await user.save(SharedKey.authUser); await Auth.set(user, key: SharedKey.authUser);
showToastNotification(context, showToastNotification(context,
title: trans("Hello"), title: trans("Hello"),

View File

@ -48,11 +48,6 @@ class _AccountRegistrationPageState extends NyState<AccountRegistrationPage> {
final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig; final WooSignalApp? _wooSignalApp = AppHelper.instance.appConfig;
@override
void initState() {
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -241,7 +236,7 @@ class _AccountRegistrationPageState extends NyState<AccountRegistrationPage> {
String? token = wpUserRegisterResponse.data!.userToken; String? token = wpUserRegisterResponse.data!.userToken;
String userId = wpUserRegisterResponse.data!.userId.toString(); String userId = wpUserRegisterResponse.data!.userId.toString();
User user = User.fromUserAuthResponse(token: token, userId: userId); User user = User.fromUserAuthResponse(token: token, userId: userId);
await user.save(SharedKey.authUser); await Auth.set(user, key: SharedKey.authUser);
await WPJsonAPI.instance.api((request) => request.wpUpdateUserInfo(token, await WPJsonAPI.instance.api((request) => request.wpUpdateUserInfo(token,
firstName: firstName, lastName: lastName)); firstName: firstName, lastName: lastName));

View File

@ -85,7 +85,8 @@ class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
onRefresh: _onRefresh, onRefresh: _onRefresh,
onLoading: _onLoading, onLoading: _onLoading,
products: _productCategorySearchLoaderController.getResults(), products: _productCategorySearchLoaderController.getResults(),
onTap: _showProduct), onTap: _showProduct,
),
), ),
); );
} }

View File

@ -135,9 +135,10 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
return; return;
} }
try { await validate(
validator(rules: {"review": "min:5"}, data: {"review": review}); rules: {"review": "min:5"},
data: {"review": review},
onSuccess: () async {
ProductReview? productReview = ProductReview? productReview =
await (appWooSignal((api) => api.createProductReview( await (appWooSignal((api) => api.createProductReview(
productId: _lineItem!.productId, productId: _lineItem!.productId,
@ -164,14 +165,12 @@ class _LeaveReviewPageState extends NyState<LeaveReviewPage> {
description: trans("Your review has been submitted"), description: trans("Your review has been submitted"),
style: ToastNotificationStyleType.SUCCESS); style: ToastNotificationStyleType.SUCCESS);
pop(result: _lineItem); pop(result: _lineItem);
} on ValidationException catch (e) { });
NyLogger.error(e.toString());
} finally {
setState(() { setState(() {
_isLoading = false; _isLoading = false;
}); });
} }
}
Future<wc_customer_info.Data?> _fetchWpUserData() async { Future<wc_customer_info.Data?> _fetchWpUserData() async {
String? userToken = await readAuthToken(); String? userToken = await readAuthToken();

View File

@ -17,7 +17,6 @@ import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.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/buttons.dart';
import 'package:flutter_app/resources/widgets/cart_icon_widget.dart'; import 'package:flutter_app/resources/widgets/cart_icon_widget.dart';
import 'package:flutter_app/resources/widgets/future_build_widget.dart';
import 'package:flutter_app/resources/widgets/product_detail_body_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_body_widget.dart';
import 'package:flutter_app/resources/widgets/product_detail_footer_actions_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_footer_actions_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
@ -232,9 +231,9 @@ class _ProductDetailState extends NyState<ProductDetailPage> {
appBar: AppBar( appBar: AppBar(
actions: <Widget>[ actions: <Widget>[
if (_wooSignalApp!.wishlistEnabled!) if (_wooSignalApp!.wishlistEnabled!)
FutureBuildWidget( NyFutureBuilder(
asyncFuture: hasAddedWishlistProduct(_product!.id), future: hasAddedWishlistProduct(_product!.id),
onValue: (dynamic isInFavourites) { child: (context, dynamic isInFavourites) {
return isInFavourites return isInFavourites
? IconButton( ? IconButton(
onPressed: () => widget.controller.toggleWishList( onPressed: () => widget.controller.toggleWishList(

View File

@ -29,6 +29,7 @@ ThemeData lightTheme(ColorStyles lightColors) {
getAppTextTheme(appFont, defaultTextTheme.merge(_textTheme(lightColors))); getAppTextTheme(appFont, defaultTextTheme.merge(_textTheme(lightColors)));
return ThemeData( return ThemeData(
useMaterial3: true,
primaryColor: lightColors.primaryContent, primaryColor: lightColors.primaryContent,
primaryColorLight: lightColors.primaryAccent, primaryColorLight: lightColors.primaryAccent,
focusColor: lightColors.primaryContent, focusColor: lightColors.primaryContent,

View File

@ -10,7 +10,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info_plus/package_info_plus.dart';
class AppVersionWidget extends StatelessWidget { class AppVersionWidget extends StatelessWidget {
const AppVersionWidget({Key? key}) : super(key: key); const AppVersionWidget({Key? key}) : super(key: key);

View File

@ -23,7 +23,9 @@ class CartIconWidget extends StatefulWidget {
class _CartIconWidgetState extends State<CartIconWidget> { class _CartIconWidgetState extends State<CartIconWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return IconButton( return Container(
width: 70,
child: IconButton(
icon: Stack( icon: Stack(
children: <Widget>[ children: <Widget>[
Positioned.fill( Positioned.fill(
@ -62,6 +64,7 @@ class _CartIconWidgetState extends State<CartIconWidget> {
), ),
onPressed: () => Navigator.pushNamed(context, "/cart") onPressed: () => Navigator.pushNamed(context, "/cart")
.then((value) => setState(() {})), .then((value) => setState(() {})),
),
); );
} }
} }

View File

@ -1,43 +0,0 @@
// 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';
class FutureBuildWidget<T> extends StatelessWidget {
const FutureBuildWidget(
{Key? key,
required this.asyncFuture,
required this.onValue,
this.onLoading})
: super(key: key);
final Widget Function(T? value) onValue;
final Widget? onLoading;
final Future asyncFuture;
@override
Widget build(BuildContext context) {
return FutureBuilder<T>(
future: asyncFuture.then((value) => value as T),
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return onLoading ?? Container();
default:
if (snapshot.hasError) {
return SizedBox.shrink();
} else {
return onValue(snapshot.data);
}
}
},
);
}
}

View File

@ -10,8 +10,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
import 'package:flutter_app/resources/widgets/future_build_widget.dart';
import 'package:flutter_app/resources/widgets/woosignal_ui.dart'; import 'package:flutter_app/resources/widgets/woosignal_ui.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/products.dart';
@ -53,10 +51,10 @@ class ProductDetailRelatedProductsWidget extends StatelessWidget {
), ),
), ),
Container( Container(
height: 200, height: 300,
child: FutureBuildWidget<List<Product>>( child: NyFutureBuilder<List<Product>>(
asyncFuture: fetchRelated(), future: fetchRelated(),
onValue: (relatedProducts) { child: (context, relatedProducts) {
if (relatedProducts == null) { if (relatedProducts == null) {
return SizedBox.shrink(); return SizedBox.shrink();
} }
@ -70,7 +68,6 @@ class ProductDetailRelatedProductsWidget extends StatelessWidget {
.toList(), .toList(),
); );
}, },
onLoading: AppLoaderWidget(),
), ),
), ),
], ],

View File

@ -12,7 +12,6 @@ import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/bootstrap/helpers.dart'; import 'package:flutter_app/bootstrap/helpers.dart';
import 'package:flutter_app/resources/widgets/future_build_widget.dart';
import 'package:flutter_app/resources/widgets/product_detail_review_tile_widget.dart'; import 'package:flutter_app/resources/widgets/product_detail_review_tile_widget.dart';
import 'package:flutter_rating_bar/flutter_rating_bar.dart'; import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:nylo_framework/nylo_framework.dart'; import 'package:nylo_framework/nylo_framework.dart';
@ -91,12 +90,9 @@ class _ProductDetailReviewsWidgetState
initiallyExpanded: false, initiallyExpanded: false,
children: [ children: [
if (_ratingExpanded == true) if (_ratingExpanded == true)
FutureBuildWidget<List<ProductReview>>( NyFutureBuilder<List<ProductReview>>(
asyncFuture: fetchReviews(), future: fetchReviews(),
onValue: (reviews) { child: (context, reviews) {
if (reviews == null) {
return SizedBox.shrink();
}
int reviewsCount = reviews.length; int reviewsCount = reviews.length;
List<Widget> childrenWidgets = []; List<Widget> childrenWidgets = [];
List<ProductDetailReviewTileWidget> children = reviews List<ProductDetailReviewTileWidget> children = reviews
@ -137,7 +133,7 @@ class _ProductDetailReviewsWidgetState
: childrenWidgets, : childrenWidgets,
); );
}, },
onLoading: Padding( loading: Padding(
padding: const EdgeInsets.symmetric(vertical: 8), padding: const EdgeInsets.symmetric(vertical: 8),
child: CupertinoActivityIndicator(), child: CupertinoActivityIndicator(),
), ),
@ -149,9 +145,9 @@ class _ProductDetailReviewsWidgetState
} }
Future<List<ProductReview>> fetchReviews() async { Future<List<ProductReview>> fetchReviews() async {
return await (appWooSignal( return await appWooSignal(
(api) => api.getProductReviews( (api) => api.getProductReviews(
perPage: 5, product: [widget.product!.id!], status: "approved"), perPage: 5, product: [widget.product!.id!], status: "approved"),
)); );
} }
} }

View File

@ -75,7 +75,7 @@ class _ProductDetailUpsellWidgetState extends State<ProductDetailUpsellWidget> {
), ),
), ),
Container( Container(
height: 200, height: 300,
child: ListView( child: ListView(
shrinkWrap: true, shrinkWrap: true,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,

View File

@ -315,6 +315,7 @@ class ProductItemContainer extends StatelessWidget {
if (product == null) { if (product == null) {
return SizedBox.shrink(); return SizedBox.shrink();
} }
return LayoutBuilder( return LayoutBuilder(
builder: (cxt, constraints) => InkWell( builder: (cxt, constraints) => InkWell(
child: Container( child: Container(
@ -324,7 +325,7 @@ class ProductItemContainer extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[ children: <Widget>[
Container( Container(
height: constraints.maxHeight / 2, height: constraints.maxHeight / 1.6,
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(3.0), borderRadius: BorderRadius.circular(3.0),
child: Stack( child: Stack(
@ -338,10 +339,12 @@ class ProductItemContainer extends StatelessWidget {
image: (product!.images.isNotEmpty image: (product!.images.isNotEmpty
? product!.images.first.src ? product!.images.first.src
: getEnv("PRODUCT_PLACEHOLDER_IMAGE")), : getEnv("PRODUCT_PLACEHOLDER_IMAGE")),
fit: BoxFit.contain, fit: BoxFit.cover,
height: constraints.maxHeight / 2, height: constraints.maxHeight / 1.6,
width: double.infinity, width: double.infinity,
), ),
if (isProductNew(product))
Container(padding: EdgeInsets.all(4), child: Text("New", style: TextStyle(color: Colors.white),), decoration: BoxDecoration(color: Colors.black),),
if (product!.onSale! && product!.type != "variable") if (product!.onSale! && product!.type != "variable")
Positioned( Positioned(
bottom: 0, bottom: 0,
@ -351,7 +354,7 @@ class ProductItemContainer extends StatelessWidget {
padding: EdgeInsets.all(3), padding: EdgeInsets.all(3),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white70, color: Colors.white70,
borderRadius: BorderRadius.circular(4), // borderRadius: BorderRadius.circular(4),
), ),
child: RichText( child: RichText(
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -366,8 +369,8 @@ class ProductItemContainer extends StatelessWidget {
.textTheme .textTheme
.bodyLarge! .bodyLarge!
.copyWith( .copyWith(
color: Colors.black87, color: Colors.black,
fontSize: 11, fontSize: 13,
), ),
), ),
], ],
@ -393,16 +396,17 @@ class ProductItemContainer extends StatelessWidget {
), ),
Flexible( Flexible(
child: Container( child: Container(
padding: EdgeInsets.only(top: 4),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
AutoSizeText( AutoSizeText(
"${formatStringCurrency(total: product!.price)} ", "${formatStringCurrency(total: product!.price)} ",
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodyMedium! .bodyLarge!
.copyWith(fontWeight: FontWeight.w600), .copyWith(fontWeight: FontWeight.w800),
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
if (product!.onSale! && product!.type != "variable") if (product!.onSale! && product!.type != "variable")

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
# Official WooSignal App Template for WooCommerce # Official WooSignal App Template for WooCommerce
# Label StoreMax # Label StoreMax
# Version: 6.5.1 # Version: 6.6.0
# Author: Anthony Gordon # Author: Anthony Gordon
# Homepage: https://woosignal.com # Homepage: https://woosignal.com
# Documentation: https://woosignal.com/docs/app/label-storemax # Documentation: https://woosignal.com/docs/app/label-storemax
@ -22,27 +22,29 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: '>=2.19.0 <3.0.0' sdk: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"
dependencies: dependencies:
google_fonts: ^4.0.3 google_fonts: ^4.0.3
analyzer: ^4.2.0 analyzer: ^5.12.0
intl: ^0.17.0 intl: ^0.18.0
nylo_framework: ^4.1.4 nylo_framework: ^5.0.0
woosignal: ^3.3.0 # woosignal: ^3.3.0
flutter_stripe: ^8.0.0+1 woosignal:
path: /Users/anthony/StudioProjects/woosignal-api
# flutter_stripe: ^9.2.0
wp_json_api: ^3.3.2 wp_json_api: ^3.3.2
cached_network_image: ^3.2.3 cached_network_image: ^3.2.3
package_info: ^2.0.2 package_info_plus: ^4.0.0
money_formatter: ^0.0.3 money_formatter: ^0.0.3
flutter_web_browser: ^0.17.1 flutter_web_browser: ^0.17.1
webview_flutter: ^3.0.4 webview_flutter: ^3.0.4
pull_to_refresh_flutter3: 2.0.1 pull_to_refresh_flutter3: 2.0.1
url_launcher: ^6.1.6 url_launcher: ^6.1.6
bubble_tab_indicator: ^0.1.5 bubble_tab_indicator: ^0.1.5
razorpay_flutter: ^1.3.4
status_alert: ^1.0.1 status_alert: ^1.0.1
math_expressions: ^2.3.1 math_expressions: ^2.4.0
validated: ^2.0.0 validated: ^2.0.0
flutter_spinkit: ^5.1.0 flutter_spinkit: ^5.1.0
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
@ -51,8 +53,8 @@ dependencies:
flutter_rating_bar: ^4.0.1 flutter_rating_bar: ^4.0.1
flutter_staggered_grid_view: ^0.6.2 flutter_staggered_grid_view: ^0.6.2
flutter_swiper_view: ^1.1.8 flutter_swiper_view: ^1.1.8
firebase_messaging: ^14.2.5 firebase_messaging: ^14.4.1
firebase_core: ^2.7.0 firebase_core: ^2.10.0
flutter: flutter:
sdk: flutter sdk: flutter
flutter_localizations: flutter_localizations:
@ -62,15 +64,16 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.5 cupertino_icons: ^1.0.5
collection: ^1.15.0 collection: ^1.15.0
flutter_stripe: ^9.1.1
dev_dependencies: dev_dependencies:
flutter_launcher_icons: ^0.12.0 flutter_launcher_icons: ^0.13.1
lints: ^2.0.0 lints: ^2.0.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter
# APP ICON # APP ICON
flutter_icons: flutter_launcher_icons:
android: true android: true
ios: true ios: true
image_path: "public/assets/app_icon/appicon.png" image_path: "public/assets/app_icon/appicon.png"

View File

@ -4,7 +4,7 @@
# WooCommerce App: Label StoreMax # WooCommerce App: Label StoreMax
### Label StoreMax - v6.5.1 ### Label StoreMax - v6.6.0
[Official WooSignal WooCommerce App](https://woosignal.com) [Official WooSignal WooCommerce App](https://woosignal.com)
@ -45,7 +45,7 @@ Full documentation this available [here](https://woosignal.com/docs/app/ios/labe
- 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
- Theme customization - Theme customization
- Stripe, Cash On Delivery, PayPal and RazorPay - Stripe, Cash On Delivery, PayPal
- Localized for en, es, pt, it, hi, fr, zh, tr, nl - Localized for en, es, pt, it, hi, fr, zh, tr, nl
- Orders show as normal in WooCommerce - Orders show as normal in WooCommerce