This commit is contained in:
2026-07-12 04:33:48 +08:00
parent f8a90ad305
commit e7ce0f7bae
151 changed files with 2765 additions and 2947 deletions

View File

@@ -6,15 +6,11 @@ import 'dart:ui' as ui;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:dio/dio.dart';
// import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:hive/hive.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:stripe_payment/stripe_payment.dart';
import '../constants.dart';
@@ -42,174 +38,17 @@ class Util {
}
Util._internal();
// final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
static bool notificationTapped = false;
init() {
// initLocalNotification();
// initFirebaseMessaging();
// ePmqRwRUTmKuFNfbHA-6zq:APA91bEFEQx1YgJqfx0V0VYo86uRDGjG6SP1SPCAZW4OvQ7gMOeKWDQ47bfuEM00YavtKq7ZGpsWfFL7B3ypm00ZA6crjJJLK_-j_H8bS_dnQbLFwyRcW67IXCs5sRkro71bRZv7L1WM
// eventBus.on<SubscribeToTopic>().listen((event) {
// if (firebaseMessaging != null) {
// firebaseMessaging.subscribeToTopic(event.topic);
// }
// });
// eventBus.on<UnSubscribeToTopic>().listen((event) {
// if (firebaseMessaging != null) {
// firebaseMessaging.unsubscribeFromTopic(event.topic);
// }
// });
}
initLocalNotification() async {
var initializationSettingsAndroid = new AndroidInitializationSettings('ic_launcher');
var initializationSettingsIOS = new IOSInitializationSettings(
onDidReceiveLocalNotification: onDidReceiveLocalNotification);
var initializationSettings = new InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
}
Future onSelectNotification(String payload, {bool replace=false}) async {
print('payload: $payload');
if (payload != null && payload.isNotEmpty) {
Routes.router.navigateTo(store.state.context, payload, replace: replace);
}
}
// initFirebaseMessaging() {
// if (Platform.isIOS) {
// iosPermission();
// }
// firebaseMessaging.getToken().then((token) {
// print('FCM token: $token');
// store.dispatch(UpdateFcmToken(token));
// });
// firebaseMessaging.configure(
// onMessage: (Map<String, dynamic> message) {
// print('FCM onMessage: $message');
// // eventBus.fire(OnFcmReceived(message));
// showNotificationWithDefaultSound(message);
// return;
// },
// onBackgroundMessage: Platform.isIOS ? null : backgroundMessageHandler,
// onResume: (Map<String, dynamic> message) {
// print('FCM onResume: $message');
// if (Platform.isAndroid) {
// if (message != null && message['data'] != null && message['data']['route'] != null) {
// notificationTapped = true;
// onSelectNotification(message['data']['route']);
// }
// } else {
// if (message != null && message['route'] != null) {
// notificationTapped = true;
// onSelectNotification(message['route']);
// }
// }
// return;
// },
// onLaunch: (Map<String, dynamic> message) {
// print('FCM onLaunch: $message');
// if (Platform.isAndroid) {
// if (message != null && message['data'] != null && message['data']['route'] != null) {
// notificationTapped = true;
// onSelectNotification(message['data']['route'], replace: true);
// }
// } else {
// if (message != null && message['route'] != null) {
// notificationTapped = true;
// onSelectNotification(message['route'], replace: true);
// }
// }
// return;
// },
// );
// }
Future onDidReceiveLocalNotification(int id, String title, String body, String payload) async {
showDialog(
context: store.state.context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text(title),
content: Text(body),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: Text(S.of(context).ok),
onPressed: () async {
Navigator.of(context, rootNavigator: true).pop();
if (payload != null && payload.isNotEmpty) {
Routes.router.navigateTo(context, payload);
}
},
)
],
),
);
}
Future showNotificationWithDefaultSound(Map<String, dynamic> message) async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
'channelId',
'channelName',
'channelDescription',
importance: Importance.max,
priority: Priority.high,
);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails(presentSound: true, badgeNumber: 1);
var platformChannelSpecifics = new NotificationDetails(
android: androidPlatformChannelSpecifics,
iOS: iOSPlatformChannelSpecifics,
);
await flutterLocalNotificationsPlugin.show(
0,
Platform.isAndroid ? message['notification']['title'] : message['title'],
Platform.isAndroid ? message['notification']['body'] : message['body'],
platformChannelSpecifics,
payload: Platform.isAndroid ? message['data']['route'] : message['route'],
);
}
// iosPermission() {
// firebaseMessaging.requestNotificationPermissions(
// const IosNotificationSettings(
// sound: true,
// badge: true,
// alert: true,
// )
// );
// firebaseMessaging.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
// print('IOS settings registered: $settings');
// });
// }
static Future<dynamic> backgroundMessageHandler(Map<String, dynamic> message) {
print('FCM background message handler: $message');
return Future<void>.value();
}
static Future<Box> getBox() async {
final dir = await getApplicationDocumentsDirectory();
Hive.init(dir.path);
Box box = await Hive.openBox('app_data');
return box;
}
static Widget showImage(String imageUrl, {double width, double height,
BoxFit fit, Widget Function(BuildContext, String, dynamic) errorWidget}) {
if (imageUrl != null && imageUrl.isNotEmpty && imageUrl.startsWith('https:')) {
static Widget showImage(String imageUrl, {double? width, double? height,
BoxFit? fit, Widget Function(BuildContext, String, dynamic)? errorWidget}) {
if (imageUrl.isNotEmpty && imageUrl.startsWith('https:')) {
return CachedNetworkImage(
imageUrl: imageUrl,
width: width,
height: width,
fit: fit,
placeholder: (context, url) => Utils.imageLoadingIndicator(width: width, height: height),
placeholder: (context, url) => Utils.imageLoadingIndicator(width: width ?? 30, height: height ?? 30),
errorWidget: errorWidget != null ? errorWidget : (context, url, error) {
return Image.asset(
'assets/images/not_found.png',
@@ -219,13 +58,13 @@ class Util {
);
},
);
} else if (imageUrl != null && imageUrl.isNotEmpty) {
} else if (imageUrl.isNotEmpty) {
return Image.file(
File(imageUrl),
width: width,
height: height,
fit: fit,
errorBuilder: (BuildContext context, Object object, StackTrace stackTrace) {
errorBuilder: (BuildContext context, Object object, StackTrace? stackTrace) {
return Image.asset(
'assets/images/not_found.png',
width: width,
@@ -319,14 +158,14 @@ class Util {
final picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
Navigator.of(context).pop();
uploadPicture(context, File(image.path), user, commentId: commentId, orderId: orderId);
uploadPicture(context, File(image!.path), user, commentId: commentId, orderId: orderId);
}
void getPictureFromCamera(BuildContext context, User user, {int commentId = -1, int orderId = 0}) async {
final picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.camera);
Navigator.of(context).pop();
uploadPicture(context, File(image.path), user, commentId: commentId, orderId: orderId);
uploadPicture(context, File(image!.path), user, commentId: commentId, orderId: orderId);
}
void uploadPicture(BuildContext context, File image, User user, {int commentId = -1, int orderId = 0}) async {
@@ -456,18 +295,18 @@ class Util {
ImagePicker picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.gallery);
Navigator.of(context).pop();
onGotFile(imageId, image.path);
onGotFile(imageId, image!.path);
}
void getPictureFromCamera2(BuildContext context, int imageId, OnGotFile onGotFile) async {
ImagePicker picker = ImagePicker();
var image = await picker.pickImage(source: ImageSource.camera);
Navigator.of(context).pop();
onGotFile(imageId, image.path);
onGotFile(imageId, image!.path);
}
Future<void> createTicket(BuildContext context, String msg, List<Map<String, dynamic>> images,
OnSuccess onSuccess, OnError onError, {int id}) {
OnSuccess onSuccess, OnError onError, {int? id}) async {
var formData = FormData();
formData.fields.add(MapEntry("msg", msg));
formData.fields.add(MapEntry('id', id == null ? '0' : id.toString()));
@@ -562,7 +401,7 @@ class Util {
PaymentPlatform paymentPlatform, {
bool googlePay=false,
bool applePay=false,
StripePaymentMethod stripePaymentMethod,
StripePaymentMethod? stripePaymentMethod,
}) {
switch(paymentPlatform.code) {
case Constants.PAYMENT_METHOD_CODE_SQUARE:
@@ -587,7 +426,7 @@ class Util {
StripePayment.setOptions(
StripeOptions(publishableKey: paymentPlatform.publishableKey,
merchantId: paymentPlatform.merchantId,
androidPayMode: paymentPlatform.publishableKey.contains('_test_')
androidPayMode: paymentPlatform.publishableKey!.contains('_test_')
? 'test'
: 'production'
)
@@ -595,14 +434,14 @@ class Util {
StripePayment.paymentRequestWithNativePay(
androidPayOptions: AndroidPayPaymentRequest(
totalPrice: order.totalPrice.toStringAsFixed(2),
currencyCode: order.businessInfo.currency,
currencyCode: order.businessInfo!.currency,
),
applePayOptions: ApplePayPaymentOptions(
currencyCode: order.businessInfo.currency,
countryCode: order.businessInfo.address.country,
currencyCode: order.businessInfo!.currency,
countryCode: order.businessInfo!.address.country,
items: [
ApplePayItem(
label: order.businessInfo.name,
label: order.businessInfo!.name,
amount: order.totalPrice.toStringAsFixed(2),
),
],
@@ -633,7 +472,7 @@ class Util {
),
);
if (paymentMethod != null) {
Utils.stripePaymentIntent(order, null, paymentMethod.id, paymentMethod.type, (response) {
Utils.stripePaymentIntent(order, null, paymentMethod.id!, paymentMethod.type!, (response) {
if (response.data['status'] == Constants.STRIPE_STATUS_REQUIRES_CONFIRMATION) {
StripePayment.confirmPaymentIntent(
PaymentIntent(
@@ -643,8 +482,8 @@ class Util {
).then((paymentIntentResult) {
if (paymentIntentResult.status == Constants.STRIPE_STATUS_SUCCEDED) {
Utils.stripeChargedSuccess(order,
paymentMethod.id,
paymentIntentResult.paymentIntentId,
paymentMethod.id!,
paymentIntentResult.paymentIntentId!,
(response) {
StripePayment.completeNativePayRequest().then((_) {
eventBus.fire(OnOrderUpdated());
@@ -680,10 +519,10 @@ class Util {
}
}
static Future<Uint8List> getBytesFromAsset(String path, int width) async {
static Future<Uint8List?> getBytesFromAsset(String path, int width) async {
ByteData data = await rootBundle.load(path);
ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
ui.FrameInfo fi = await codec.getNextFrame();
return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
return (await fi.image.toByteData(format: ui.ImageByteFormat.png))?.buffer.asUint8List();
}
}