Files
flutter_wisetronic/lib/utils/utils.dart
peima 7e8182259f phase3: utils.dart null-safe (cart logic + dio5 error handling)
- cart event handlers rewritten with local list + nullable model fields
- getCartInfo*/addCart/removeCart helpers: nullable List<CartInfo>? params
- addSubproductToCard/addSubproductQty/removeSubproduct: null-safe nested access
- showMessageDialog: DioException + promoted response local
- newCartLineItem params nullable; getWeekDayName default return
- launchURL->launch; RuntimeError code nullable
2026-07-24 20:13:07 +08:00

1024 lines
32 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_wisetronic/models/product.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hive/hive.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as path;
import 'package:universal_io/io.dart';
import 'package:url_launcher/url_launcher.dart';
import '../constants.dart';
import '../events/eventbus.dart';
import '../events/events.dart';
import '../generated/l10n.dart';
import '../models/business.dart';
import '../models/cart_info.dart';
import '../models/cart_line_item.dart';
import '../models/order.dart';
import '../models/user.dart';
import '../routes.dart';
import '../store/actions.dart';
import '../store/store.dart';
import 'http_util.dart';
import 'util_web.dart' if (dart.library.io) 'util_io.dart';
typedef void OnSuccess(Response response);
typedef void OnError(dynamic error);
typedef void OnComplete(dynamic data);
typedef void OnOk();
typedef void OnLoadImageError();
class Utils {
static StreamSubscription? onProductWillAddToCartSubscription;
static StreamSubscription? onProductWillRemoveFromCartSubscription;
init() async {
onProductWillAddToCartSubscription =
eventBus.on<OnProductWillAddToCart>().listen((event) {
CartInfo? found = getCartInfoByBusiness(store.state.cartInfos, event.business);
final List<CartLineItem> existing =
(found != null && found.productList != null && found.productList!.isNotEmpty)
? found.productList! : <CartLineItem>[];
CartInfo cartInfo = found ?? CartInfo();
if (existing.isEmpty) {
cartInfo.id = 0;
cartInfo.amountPaid = 0.0;
cartInfo.businessInfo = event.business;
cartInfo.extraFeeList = [];
cartInfo.discountList = [];
CartLineItem lineItem = newCartLineItem(
id: 0, price: event.price, product: event.product,
name: event.product.name, description: event.description, quantity: 1.0);
cartInfo.productList = [lineItem];
addSubproductToCard(cartInfo, lineItem);
store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList(store.state.cartInfos, cartInfo)));
eventBus.fire(OnCartInfoUpdated());
} else {
if ((event.product.productAttributes?.length ?? 0) > 0) {
CartLineItem lineItem = newCartLineItem(
id: 0, price: event.price, product: event.product,
name: event.product.name, description: event.description, quantity: 1.0);
existing.add(lineItem);
addSubproductToCard(cartInfo, lineItem);
store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList(store.state.cartInfos, cartInfo)));
eventBus.fire(OnCartInfoUpdated());
} else {
int foundIndex = -1;
for (var i = 0; i < existing.length; i++) {
if (existing[i].product?.id == event.product.id) { foundIndex = i; break; }
}
if (foundIndex == -1) {
CartLineItem lineItem = newCartLineItem(
id: 0, price: event.price, product: event.product,
name: event.product.name, description: event.description, quantity: 1.0);
existing.add(lineItem);
addSubproductToCard(cartInfo, lineItem);
store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList(store.state.cartInfos, cartInfo)));
eventBus.fire(OnCartInfoUpdated());
} else {
if ((existing[foundIndex].quantity ?? 0) + 1.0 > (event.product.leftNum ?? double.infinity)) {
// insufficient stock
} else {
existing[foundIndex].quantity = (existing[foundIndex].quantity ?? 0) + 1;
addSubproductQty(cartInfo, existing[foundIndex]);
store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList(store.state.cartInfos, cartInfo)));
eventBus.fire(OnCartInfoUpdated());
}
}
}
}
});
onProductWillRemoveFromCartSubscription =
eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
CartInfo? found = getCartInfoByBusiness(store.state.cartInfos, event.business);
if (found != null && found.productList != null) {
final existing = found.productList!;
if (existing.isNotEmpty) {
if (event.productListIndex != -1) {
if ((existing[event.productListIndex].quantity ?? 0) <= 1) {
String uuid = existing[event.productListIndex].uuid ?? '';
existing.removeAt(event.productListIndex);
removeSubproduct(found, uuid);
} else {
existing[event.productListIndex].quantity = (existing[event.productListIndex].quantity ?? 0) - 1;
addSubproductQty(found, existing[event.productListIndex], remove: true);
}
} else {
int idx = -1;
for (var i = 0; i < existing.length; i++) {
if (existing[i].product?.id == event.product.id) { idx = i; break; }
}
if (idx != -1) {
if ((existing[idx].quantity ?? 0) <= 1) {
String uuid = existing[idx].uuid ?? '';
existing.removeAt(idx);
removeSubproduct(found, uuid);
} else {
existing[idx].quantity = (existing[idx].quantity ?? 0) - 1;
addSubproductQty(found, existing[idx], remove: true);
}
}
}
}
if (existing.isEmpty) {
store.dispatch(UpdateCartInfo(removeCartInfoFromCartInfoList(store.state.cartInfos, found)));
} else {
store.dispatch(UpdateCartInfo(addCartInfoToCartInfoList(store.state.cartInfos, found)));
}
eventBus.fire(OnCartInfoUpdated());
}
});
}
static bool equalsIgnoreCase(String a, String b) =>
(a == null && b == null) ||
(a != null && b != null && a.toLowerCase() == b.toLowerCase());
static int selectionsContains(
Map<String, dynamic> selections, String key, String name) {
if (selections.containsKey(key.toUpperCase())) {
for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) {
Map<String, dynamic> item = (selections[key.toUpperCase()] as List)[i];
if (Utils.equalsIgnoreCase(item['name'], name)) {
return i;
}
}
}
return -1;
}
static List<String> getSelectedAttributeValue(
Map<String, dynamic> selections, String key) {
List<String> valueArr = [];
if (selections.containsKey(key.toUpperCase())) {
for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) {
valueArr.add(
(selections[key.toUpperCase()][i]['name'] as String).toLowerCase());
}
}
return valueArr;
}
static bool selectionsNotEmptyAt(
Map<String, dynamic> selections, String key) {
if (selections.containsKey(key.toUpperCase()) &&
(selections[key.toUpperCase()] as List).length > 0) {
return true;
}
return false;
}
static Map<String, dynamic>? stringToJson(String string) {
if (string == null || string.isEmpty) {
return null;
}
return json.decode(string);
}
static void jsonPrettyPrint(Map<String, dynamic> map) {
JsonEncoder encoder = new JsonEncoder.withIndent(' ');
String prettyPrint = encoder.convert(map);
debugPrint(prettyPrint);
}
static launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
static String getPlatformName() {
String platformName = '';
if (kIsWeb) {
platformName = 'web';
} else if (Platform.isAndroid) {
platformName = 'android';
} else if (Platform.isIOS) {
platformName = 'ios';
}
return platformName;
}
static Future<Box> getBox() async {
return Util.getBox();
}
static Widget imageLoadingIndicator(
{double width = 30.0, double height = 30.0}) {
return SizedBox(
width: width,
height: height,
child: Center(
child: Container(
width: 30.0,
height: 30.0,
child: CupertinoActivityIndicator(),
color: Colors.transparent,
),
),
);
}
static String safePhoneNumber(String phone) {
if (phone.length < 8) {
return phone;
}
String start = phone.substring(0, 3);
String end = phone.substring(phone.length - 3);
return '${start}****${end}';
}
static String safeString(String string) {
if (string == null || string.length == 0) {
return '';
}
String start = string.substring(0, 1);
String end = string.substring(string.length - 1);
return '${start}****${end}';
}
static String smartRound(double amount, int decimalPlace) {
double a = double.parse(amount.toStringAsFixed(decimalPlace));
double b = double.parse(amount.toStringAsFixed(0));
if (a - b == 0) {
return amount.toStringAsFixed(0);
}
return amount.toStringAsFixed(decimalPlace);
}
static showSubmitDialog(BuildContext context) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
content: WillPopScope(
child: Container(
width: 300.0,
height: 150.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SpinKitThreeBounce(
color: Colors.lightBlueAccent,
size: 30.0,
),
Text(
S.of(context).submitting,
),
],
),
),
),
onWillPop: () async {
Fluttertoast.showToast(
msg: S.of(context).submitting_please_wait,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white);
return false;
}),
);
},
);
}
static showLoadingDialog(BuildContext context, {String? message}) {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
content: WillPopScope(
child: Container(
width: 80.0,
height: 80.0,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SpinKitThreeBounce(
color: Colors.lightBlueAccent,
size: 30.0,
),
Text(
message != null ? message : S.of(context).recalculating,
),
],
),
),
),
onWillPop: () async {
Fluttertoast.showToast(
msg: S.of(context).loading_please_wait,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
backgroundColor: Colors.red,
textColor: Colors.white);
return false;
}),
);
},
);
}
static getTitleFromBody(String body) {
if (body.length <= 30) {
return body;
}
return body.substring(0, 29);
}
static void getMiniLink(
String realLink, OnSuccess onSuccess, OnError onError) {
HttpUtil.httpPost(
'get-minilink/',
(response) {
onSuccess(response);
},
body: {'link': realLink},
isFormData: true,
).catchError((error) {
onError(error);
});
}
static String getOs({bool checkWeb = false}) {
if (checkWeb && kIsWeb) {
return 'web';
}
if (Platform.isAndroid) {
return 'android';
}
if (Platform.isIOS) {
return 'ios';
}
if (Platform.isLinux) {
return 'ubuntu';
}
if (Platform.isMacOS) {
return 'mac';
}
if (Platform.isWindows) {
return 'windows';
}
return 'web';
}
static int getOsFontHex(String os) {
if (os == 'mac') {
return Constants.FONT_APPLE;
}
if (os == 'windows') {
return Constants.FONT_WINDOWS;
}
if (os == 'ubuntu') {
return Constants.FONT_UBUNTU;
}
if (os == 'android') {
return Constants.FONT_ANDROID;
}
if (os == 'ios') {
return Constants.FONT_IOS;
}
return Constants.FONT_TOPTONS;
}
static void getCurrentUser() {
getBox().then((box) {
int userId = box.get(Constants.KEY_USER_ID, defaultValue: 0);
String accessToken =
box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
if (userId == 0 || accessToken.isEmpty) {
eventBus.fire(new OnGetCurrentUserFailed(Error()));
} else {
HttpUtil.httpGet(
'v1/users/$userId',
queryParameters: {},
businessId: Constants.BUSINESS_ID,
).then((value) {
User user = User.fromJson(value);
store.dispatch(UpdateCurrentUser(user));
eventBus.fire(OnCurrentUserUpdated());
}).catchError((err) {
eventBus.fire(new OnGetCurrentUserFailed(err));
});
}
}).catchError((err) {
eventBus.fire(new OnGetCurrentUserFailed(err));
});
}
static void showMessageDialog(BuildContext context, dynamic error,
{String? title, List<Widget>? actions, OnOk? onOk}) {
String message = '';
print('error $error');
if (error is DioException) {
final resp = error.response;
if (resp != null) {
if (resp.data['message'] != null) {
message = resp.data['message'];
} else if (resp.data['error'] != null) {
if (resp.data['error'] is String) {
message = resp.data['error'];
} else if (resp.data['error']['errmsg'] != null) {
message = resp.data['error']['errmsg'];
} else if (resp.data['error']['message'] != null) {
message = resp.data['error']['message'];
} else {
message = resp.data.toString();
}
}
}
} else if (error is String) {
message = '$error';
} else if (error.message != null) {
message = error.message;
} else {
message = '$error';
}
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(title != null ? title : S.of(context).error),
content: Text(message),
actions: actions == null
? <Widget>[
TextButton(
child: Text(S.of(context).ok),
onPressed: onOk == null
? () {
Navigator.of(context).pop();
}
: onOk,
),
]
: actions,
);
});
}
static Future<List<int>> getLastVisit() async {
Box box = await getBox();
List<dynamic> lastVisit =
json.decode(box.get(Constants.KEY_LAST_VISIT, defaultValue: '[]'));
List<int> lv = lastVisit.map((e) => e as int).toList();
store.dispatch(UpdateLastVisit(lv));
return lv;
}
static void saveLastVisit(List<int> lastVisit) {
getBox().then((box) {
box.put(Constants.KEY_LAST_VISIT, lastVisit.toString());
}).catchError((error) {
print('Error occurred: $error');
});
}
static String utcDatetimeStringToLocalDatetimeString(
BuildContext context, String utcDatetimeString,
{bool withTime = false}) {
var utcDatetime;
try {
utcDatetime = DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.parse(utcDatetimeString, true);
} catch (error) {
utcDatetime = DateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
.parse(utcDatetimeString, true);
}
var localDatetime = utcDatetime.toLocal();
return datetimeFormat(context, localDatetime, withTime: withTime);
}
static String datetimeFormat(BuildContext context, DateTime date,
{bool withTime = false}) {
final theDate = DateTime(date.year, date.month, date.day);
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final yesterday = DateTime(now.year, now.month, now.day - 1);
final tomorrow = DateTime(now.year, now.month, now.day + 1);
DateFormat formatter = DateFormat('yyyy/MM/dd');
DateFormat timeFormatter = DateFormat('HH:mm');
if (withTime != null && withTime) {
formatter = DateFormat('yyyy/MM/dd HH:mm:ss');
}
if (theDate == today) {
return S.of(context).today_with_time(timeFormatter.format(date));
}
if (theDate == tomorrow) {
return S.of(context).tomorrow_with_time(timeFormatter.format(date));
}
return formatter.format(date);
}
void uploadPicture(
BuildContext context,
File image,
Map<String, dynamic> product,
int imageId,
String currentImageUrl,
OnSuccess onSuccess,
{int originalImageId = 0}) async {
if (image != null && await image.exists()) {
print('image: ${image.path}');
String imageName = path.basename(image.path);
MultipartFile imageFile =
await MultipartFile.fromFile(image.path, filename: imageName);
Map<String, dynamic> formMap = {
'id': product['id'],
'image': imageFile,
'original_image_id': originalImageId
};
if (imageId == -1) {
HttpUtil.httpPost(
'upload-product-image/',
(response) {
if (onSuccess != null) {
onSuccess(response);
}
},
isFormData: true,
body: formMap,
sendProgress: (int sent, int total) {
if (sent == total) {
eventBus.fire(OnUploadImageProgressEvent(imageId, false, 1.0));
} else {
eventBus.fire(
OnUploadImageProgressEvent(imageId, true, sent / total));
}
},
).catchError((error) {
Utils.showMessageDialog(context, error);
});
} else {
HttpUtil.httpPost(
'upload-product-gallery-image/',
(response) {
if (onSuccess != null) {
onSuccess(response);
}
},
isFormData: true,
body: formMap,
sendProgress: (int sent, int total) {
if (sent == total) {
eventBus.fire(OnUploadImageProgressEvent(imageId, false, 0.0));
} else {
eventBus.fire(
OnUploadImageProgressEvent(imageId, true, sent / total));
}
},
).catchError((error) {
Utils.showMessageDialog(context, error);
});
}
}
}
static CartInfo? getCartInfoByBusiness(
List<CartInfo>? cartInfos, Business business) {
if (cartInfos == null || cartInfos.length <= 0) {
return null;
}
for (var i = 0; i < cartInfos.length; i++) {
if (cartInfos[i].businessInfo?.id == business.id) {
return cartInfos[i];
}
}
return null;
}
static CartInfo? getCartInfoByBusinessId(
List<CartInfo>? cartInfos, int businessId) {
if (cartInfos == null || cartInfos.length <= 0) {
return null;
}
for (var i = 0; i < cartInfos.length; i++) {
if (cartInfos[i].businessInfo?.id == businessId) {
return cartInfos[i];
}
}
return null;
}
static List<CartInfo> addCartInfoToCartInfoList(
List<CartInfo>? cartInfos, CartInfo cartInfo) {
if (cartInfos == null || cartInfos.length <= 0) {
cartInfos = [cartInfo];
} else {
bool found = false;
for (var i = 0; i < cartInfos.length; i++) {
if (cartInfos[i].businessInfo?.id == cartInfo.businessInfo?.id) {
cartInfos[i] = cartInfo;
found = true;
break;
}
}
if (!found) {
cartInfos.add(cartInfo);
}
}
Utils.getBox().then((box) {
box.put(Constants.KEY_CARTINFOS, cartInfos.toString());
}).catchError((error) {
print('Error occurred: $error');
});
return cartInfos;
}
static List<CartInfo> removeCartInfoFromCartInfoList(
List<CartInfo>? cartInfos, CartInfo? cartInfo) {
if (cartInfos == null || cartInfos.length <= 0 || cartInfo == null) {
return [];
}
int removeIndex = -1;
for (var i = 0; i < cartInfos.length; i++) {
if (cartInfo.businessInfo?.id == cartInfos[i].businessInfo?.id) {
removeIndex = i;
break;
}
}
if (removeIndex != -1) {
cartInfos.removeAt(removeIndex);
}
getBox().then((box) {
box.put(Constants.KEY_CARTINFOS, cartInfos.toString());
}).catchError((error) {
print('Error occurred: $error');
});
return cartInfos;
}
static void clearCart(BuildContext context, CartInfo? cartInfo,
{OnComplete? onComplete}) {
if (cartInfo != null && cartInfo.productList != null && cartInfo.productList!.length > 0) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(S.of(context).warning),
content: Text(S.of(context).are_you_sure_to_empty_basket),
actions: <Widget>[
TextButton(
child: Text(S.of(context).cancel),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text(S.of(context).yes_i_am_sure),
onPressed: () {
store.dispatch(new UpdateCartInfo(
Utils.removeCartInfoFromCartInfoList(
store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
Navigator.of(context).pop();
if (onComplete != null) {
onComplete(null);
}
},
)
],
);
});
}
}
static void requireLogin(BuildContext context,
{String? returnUrl, bool replace = true, int delayMilliseconds = 400}) {
Future.delayed(Duration(milliseconds: delayMilliseconds), () {
if (returnUrl != null) {
store.dispatch(UpdateRedirectRoute(returnUrl));
}
Routes.router.navigateTo(context, '/login', replace: replace);
});
}
static String getFirstNumberFromString(String numString) {
final intInStr = RegExp(r'\d+');
return intInStr.firstMatch(numString)?.group(0) ?? '';
}
static void loadProducts(int businessId, int categoryId, int page, bool more,
OnComplete onComplete, OnError onError, {int featuredCount=4, int hotSaleCount=4, String keyword=''}) {
print('feature $featuredCount');
HttpUtil.httpGet(
more ? 'v1/service-category-products-more' : 'v1/service-category-products',
businessId: businessId,
queryParameters: {
// 'lat': store.state.position.latitude.toString(),
// 'lng': store.state.position.longitude.toString(),
'category_id': categoryId,
'preview': Constants.isPreview,
'page': page,
'num_per_page': Constants.ORDERS_PER_PAGE,
'featured_count': featuredCount,
'hot_sale_count': hotSaleCount,
'keyword': Uri.encodeComponent(keyword),
},
).then((value) {
if (onComplete != null) {
onComplete(value);
}
}).catchError((error) {
if (onError != null) {
onError(error);
}
});
}
static String timestampToString(BuildContext context, int timestamp, {bool withTime=false}) {
DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
if (timestamp == 0) {
return '';
}
return datetimeFormat(context, date, withTime: withTime);
}
static String errorMsg2(BuildContext context, String code, String defaultString) {
switch (code) {
case 'no_delivery':
return S.of(context).checkout_no_deliver;
case 'no_shipping_address':
return S.of(context).please_provide_shipping_address;
case 'over_delivery_distance':
return S.of(context).over_delivery_distance;
case 'amount_not_meet':
return S.of(context).amount_not_meet;
case 'select_canada_post_shipping_rate':
return S.of(context).select_canada_post_shipping_rate;
case 'store_close':
return S.of(context).store_closed;
}
return defaultString;
}
static String knownName(BuildContext context, String name) {
switch (name) {
case 'pickup-discount':
return S.of(context).pickup_discount;
case 'collect-tips':
return S.of(context).service_fee;
default:
return name;
}
}
static String getWeekDayName(BuildContext context, int timestamp, bool shortName) {
DateTime date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
switch(date.weekday) {
case 1:
if (shortName) {
return S.of(context).mon;
} else {
return S.of(context).monday;
}
break;
case 2:
if (shortName) {
return S.of(context).tue;
} else {
return S.of(context).tuesday;
}
break;
case 3:
if (shortName) {
return S.of(context).wed;
} else {
return S.of(context).wednesday;
}
break;
case 4:
if (shortName) {
return S.of(context).thu;
} else {
return S.of(context).thursday;
}
break;
case 5:
if (shortName) {
return S.of(context).fri;
} else {
return S.of(context).friday;
}
break;
case 6:
if (shortName) {
return S.of(context).sat;
} else {
return S.of(context).saturday;
}
break;
case 7:
if (shortName) {
return S.of(context).sun;
} else {
return S.of(context).sunday;
}
break;
default:
return '';
}
return '';
}
static int getProductLineInOrder(CartInfo cartInfo) {
int qty = 0;
for (CartLineItem lineItem in (cartInfo.productList ?? <CartLineItem>[])) {
if (lineItem.product?.id != null) {
qty += 1;
}
}
return qty;
}
static void orderAgain(BuildContext context, CartInfo cartInfo) {
cartInfo.productList?.removeWhere((element) => element.product == null || element.product?.id == null);
store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList(store.state.cartInfos, cartInfo)));
eventBus.fire(new OnCartInfoUpdated());
Routes.router.navigateTo(context, '/checkout/${cartInfo.businessInfo?.id}');
}
static String getOrderStatus(BuildContext context, int statusCode) {
switch(statusCode) {
case Constants.STATUS_PENDING:
return S.of(context).pending;
case Constants.STATUS_ACCEPT:
return S.of(context).order_acceipt;
case Constants.STATUS_PROCESSING:
return S.of(context).order_processing;
case Constants.STATUS_COMPLETE:
return S.of(context).order_complete;
case Constants.STATUS_CANCELLED:
return S.of(context).order_cancelled;
default:
return S.of(context).pending;
}
}
static CartLineItem newCartLineItem(
{int? id,
double? price,
Product? product,
String? name,
String? description,
double? quantity,
String? parentUuid,
}) {
CartLineItem lineItem = CartLineItem();
lineItem.unitPrice = price;
lineItem.product = product;
lineItem.name = product?.name;
lineItem.description = description;
lineItem.quantity = quantity;
lineItem.parentUuid = parentUuid;
return lineItem;
}
static void addSubproductToCard(CartInfo cartInfo, CartLineItem lineItem) {
final product = lineItem.product;
final subs = product?.subproducts;
if (subs == null || subs.isEmpty) return;
for (int j = 0; j < subs.length; j++) {
final sp = subs[j].product;
cartInfo.productList?.add(newCartLineItem(
id: 0,
price: 0.0,
product: Product(
sp?.id ?? 0,
product?.businessId ?? 0,
sp?.name ?? '',
sp?.price ?? 0.0,
sp?.description ?? '',
sp?.image ?? '',
sp?.productAttributes ?? []
),
name: sp?.name ?? '',
description: sp?.description ?? '',
quantity: 1.0,
parentUuid: lineItem.uuid
));
}
}
static void addSubproductQty(CartInfo cartInfo, CartLineItem lineItem,
{bool remove = false}) {
final product = lineItem.product;
final subs = product?.subproducts;
if (subs == null || subs.isEmpty) return;
for (var i = 0; i < (cartInfo.productList?.length ?? 0); i++) {
CartLineItem lineItem1 = cartInfo.productList![i];
if (lineItem1.parentUuid == lineItem.uuid) {
for (var j = 0; j < subs.length; j++) {
if (subs[j].product?.id == lineItem1.product?.id) {
if (remove) {
lineItem1.quantity = (lineItem1.quantity ?? 0) - (subs[j].quantity ?? 0);
} else {
lineItem1.quantity = (lineItem1.quantity ?? 0) + (subs[j].quantity ?? 0);
}
break;
}
}
}
}
}
static void removeSubproduct(CartInfo cartInfo, String uuid) {
cartInfo.productList?.removeWhere((element) => element.parentUuid == uuid);
}
static void openEmail(String email) async {
final Uri params = Uri(
scheme: 'mailto',
path: '$email',
);
String url = params.toString();
if (await canLaunch(url)) {
await launch(url);
} else {
print('Could not launch $url');
}
}
static void callPhone(String phone) async {
String callNo = 'tel://$phone';
if (await canLaunch(callNo)) {
await launch(callNo);
} else {
print('Could not call $phone');
}
}
static Widget buildLine(String name, dynamic value, {double? nameSize, double? valueSize}) {
Row row = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
row.children.add(
Container(
width: 150,
padding: EdgeInsets.only(),
child: Text(
name,
style: TextStyle(
color: Colors.black38,
fontSize: nameSize,
),
),
),
);
if (value is String) {
row.children.add(
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: Text(
value,
style: TextStyle(
fontSize: valueSize,
),
),
),
),
);
} else {
row.children.add(
Expanded(child: value),
);
}
return Container(
padding: EdgeInsets.only(top: 8, bottom: 8),
child: row,
);
}
static int getBusinessId() {
return Constants.BUSINESS_ID;
}
}
class RuntimeError extends Error {
final int? code;
final String message;
RuntimeError(this.message, {this.code});
String toString() => "Runtime Error: $message";
}