From 9ba152b3c34b7b50c2437a851217b8328fa10a74 Mon Sep 17 00:00:00 2001 From: userGyl Date: Mon, 22 Dec 2025 16:15:32 +0800 Subject: [PATCH] =?UTF-8?q?v1.2.1=20=E5=BE=85=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ln_jq_app/ios/Podfile.lock | 17 +- ln_jq_app/lib/pages/qr_code/controller.dart | 219 +++++++------- ln_jq_app/lib/pages/qr_code/view.dart | 313 ++++++++++++-------- ln_jq_app/pubspec.lock | 32 +- ln_jq_app/pubspec.yaml | 3 +- 5 files changed, 312 insertions(+), 272 deletions(-) diff --git a/ln_jq_app/ios/Podfile.lock b/ln_jq_app/ios/Podfile.lock index 799a4c7..bded35d 100644 --- a/ln_jq_app/ios/Podfile.lock +++ b/ln_jq_app/ios/Podfile.lock @@ -20,7 +20,9 @@ PODS: - FlutterMacOS - image_picker_ios (0.0.1): - Flutter - - MTBBarcodeScanner (5.0.11) + - mobile_scanner (7.0.0): + - Flutter + - FlutterMacOS - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter @@ -29,9 +31,6 @@ PODS: - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - - qr_code_scanner_plus (0.2.6): - - Flutter - - MTBBarcodeScanner - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS @@ -47,16 +46,15 @@ DEPENDENCIES: - flutter_pdfview (from `.symlinks/plugins/flutter_pdfview/ios`) - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - mobile_scanner (from `.symlinks/plugins/mobile_scanner/darwin`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - qr_code_scanner_plus (from `.symlinks/plugins/qr_code_scanner_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) SPEC REPOS: trunk: - - MTBBarcodeScanner - OrderedSet EXTERNAL SOURCES: @@ -76,14 +74,14 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/geolocator_apple/darwin" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + mobile_scanner: + :path: ".symlinks/plugins/mobile_scanner/darwin" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" - qr_code_scanner_plus: - :path: ".symlinks/plugins/qr_code_scanner_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" url_launcher_ios: @@ -98,12 +96,11 @@ SPEC CHECKSUMS: flutter_pdfview: 32bf27bda6fd85b9dd2c09628a824df5081246cf geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326 - MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb + mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d - qr_code_scanner_plus: 7e087021bc69873140e0754750eb87d867bed755 shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b diff --git a/ln_jq_app/lib/pages/qr_code/controller.dart b/ln_jq_app/lib/pages/qr_code/controller.dart index 29b8013..f43f9ac 100644 --- a/ln_jq_app/lib/pages/qr_code/controller.dart +++ b/ln_jq_app/lib/pages/qr_code/controller.dart @@ -1,17 +1,13 @@ import 'dart:io'; -import 'dart:typed_data'; - import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:getx_scaffold/getx_scaffold.dart'; -import 'package:image/image.dart' as img; import 'package:image_picker/image_picker.dart'; import 'package:ln_jq_app/common/model/base_model.dart'; import 'package:ln_jq_app/common/model/vehicle_info.dart'; import 'package:ln_jq_app/storage_service.dart'; -import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; -import 'package:zxing_lib/common.dart'; -import 'package:zxing_lib/qrcode.dart'; -import 'package:zxing_lib/zxing.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:permission_handler/permission_handler.dart'; class QrCodeController extends GetxController with BaseControllerMixin, GetSingleTickerProviderStateMixin { @@ -22,11 +18,11 @@ class QrCodeController extends GetxController late final AnimationController animationController; late final Animation scanAnimation; - // --- QR Scanning --- - final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); - QRViewController? qrViewController; - final Rx result = Rx(null); + // --- 使用 MobileScanner 的控制器 --- + final MobileScannerController scannerController = MobileScannerController(); + final RxBool isFlashOn = false.obs; + final RxBool isProcessingResult = false.obs; @override void onInit() { @@ -37,140 +33,114 @@ class QrCodeController extends GetxController duration: const Duration(milliseconds: 2500), vsync: this, ); - scanAnimation = Tween(begin: 0, end: 1).animate(animationController); + scanAnimation = + Tween(begin: 0, end: 1).animate(animationController); animationController.repeat(reverse: false); } - /// 当 QRView 创建时调用 - void onQRViewCreated(QRViewController controller) { - this.qrViewController = controller; - // 监听扫描到的数据 - controller.scannedDataStream.listen((scanData) { - if (scanData.code != null && result.value?.code != scanData.code) { - result.value = scanData; - qrViewController?.pauseCamera(); + /// MobileScanner 的 onDetect 回调方法 + void onDetect(BarcodeCapture capture) { + if (isProcessingResult.value) return; - animationController.stop(); - - renderResult(scanData.code!); - } - }); + final Barcode? barcode = capture.barcodes.firstOrNull; + if (barcode?.rawValue != null && barcode!.rawValue!.isNotEmpty) { + isProcessingResult.value = true; + scannerController.stop(); + animationController.stop(); + print("相机识别到的内容: ${barcode.rawValue!}"); + renderResult(barcode.rawValue!); + } } + /// 恢复扫描状态 void resumeScanner() { - result.value = null; - qrViewController?.resumeCamera(); + isProcessingResult.value = false; + try { + scannerController.start(); + } catch (e) { + print("无法重启相机: $e"); + } animationController.repeat(reverse: false); } /// 从相册选择图片并扫描二维码 void scanFromGallery() async { try { - final XFile? imageFile = await ImagePicker().pickImage(source: ImageSource.gallery); - if (imageFile == null) return; // 用户取消了选择 - - qrViewController?.pauseCamera(); - animationController.stop(); - - String? scanResult; - try { - final image = img.decodeImage(await File(imageFile.path).readAsBytes()); - if (image != null) { - //扫描图片 - final pixels = Int32List.fromList( - image.map((pixel) { - return (pixel.a.toInt() << 24) | - (pixel.r.toInt() << 16) | - (pixel.g.toInt() << 8) | - pixel.b.toInt(); - }).toList(), - ); - - final source = RGBLuminanceSource(image.width, image.height, pixels); - - final bitmap = BinaryBitmap(HybridBinarizer(source)); - final reader = QRCodeReader(); - final result = reader.decode(bitmap); - scanResult = result.text; - } - } on NotFoundException { - scanResult = null; - } catch (e) { - //异常 - scanResult = null; + final XFile? imageFile = + await ImagePicker().pickImage(source: ImageSource.gallery); + if (imageFile == null) { + return; } - if (scanResult != null) { + scannerController.stop(); + animationController.stop(); + showLoading("正在识别..."); + + final BarcodeCapture? capture = + await scannerController.analyzeImage(imageFile.path); + + dismissLoading(); + + final Barcode? firstBarcode = capture?.barcodes.firstOrNull; + + if (firstBarcode?.rawValue != null && + firstBarcode!.rawValue!.isNotEmpty) { + final String scanResult = firstBarcode.rawValue!; + print("相册识别到的内容: $scanResult"); renderResult(scanResult); } else { showErrorToast('未识别到二维码'); resumeScanner(); } - } catch (e) { - showErrorToast('从相册选择失败'); + } catch (e, stackTrace) { + dismissLoading(); + showErrorToast('从相册选择失败,请稍后重试'); + print("scanFromGallery Error: $e\n$stackTrace"); resumeScanner(); } } /// 切换闪光灯 void toggleFlash() async { - await qrViewController?.toggleFlash(); - isFlashOn.value = (await qrViewController?.getFlashStatus()) ?? false; + try { + await scannerController.toggleTorch(); + final currentTorchState = scannerController.value.torchState; + isFlashOn.value = currentTorchState == TorchState.on; + } catch (e) { + print("切换闪光灯失败: $e"); + showErrorToast("无法打开闪光灯"); + } } /// 翻转相机 void flipCamera() async { - await qrViewController?.flipCamera(); + await scannerController.switchCamera(); } + /// 请求相机权限 void requestPermission() async { - if (Platform.isIOS) { - var status = await Permission.camera.request(); - if (status.isGranted) { - } else if (status.isPermanentlyDenied) { - openAppSettings(); - } else { - showErrorToast('需要相机权限才能扫描二维码'); - } - return; - } - - final bool results = await requestCameraPermission(); - if (!results) { - showErrorToast('相机权限未被授予,请到权限管理中打开'); + var status = await Permission.camera.request(); + if (!status.isGranted) { + showErrorToast('请授予相机权限以使用扫描功能'); + Get.back(); } } void requestPhotoPermission() async { - if (Platform.isAndroid) { - final bool results = await requestPhotosPermission(); - if (!results) { - showErrorToast('相册权限未被授予,请到权限管理中打开'); - } else { - scanFromGallery(); - } - } - if (Platform.isIOS) { - var status = await Permission.photos.request(); - print("权限状态: $status"); // 在控制台看这个输出 - if (status.isGranted) { - scanFromGallery(); - } else if (status.isPermanentlyDenied) { - openAppSettings(); - } else { - showErrorToast('需要相册权限才能从相册中选择图片'); - } + var status = await Permission.photos.request(); + if (status.isGranted) { + scanFromGallery(); + } else if (status.isPermanentlyDenied) { + openAppSettings(); + } else { + showErrorToast('需要相册权限才能从相册中选择图片'); } } - //扫码结果处理 //如果绑定接口返回的data为null 需要手动编辑车牌 + /// 处理扫描结果 void renderResult(String resultStr, {plateNumber}) async { showLoading("正在获取车辆信息..."); try { - /*var responseData = await HttpService.to.get( - "appointment/truck/base-info?vin=$resultStr", - );*/ - final Map requestData = { "code": resultStr, "phone": StorageService.to.phone, @@ -184,6 +154,7 @@ class QrCodeController extends GetxController ); if (responseData == null) { + dismissLoading(); showToast('无法获取车辆信息,请检查网络或稍后重试'); resumeScanner(); return; @@ -192,62 +163,76 @@ class QrCodeController extends GetxController if (result.code != 0) { showToast(result.error); + dismissLoading(); + resumeScanner(); // 绑定失败也要恢复扫描 return; } if (result.data == null) { + dismissLoading(); showBindDialog(resultStr); return; } final vehicle = VehicleInfo.fromJson(result.data as Map); - //保存使用 await StorageService.to.saveVehicleInfo(vehicle); - + dismissLoading(); Get.back(result: true); - } on DioException catch (e) { + + } on DioException catch (_) { showErrorToast("网络请求失败,请稍后重试"); resumeScanner(); - } catch (e, stackTrace) { - showErrorToast("处理失败,请稍后重试"); - resumeScanner(); // 未知异常,恢复扫描 + } catch (e, _) { + showErrorToast("处理失败,请稍后重舍"); + resumeScanner(); } finally { - dismissLoading(); + if (Get.isDialogOpen ?? false) { + dismissLoading(); + } } } + /// 显示绑定确认对话框 void showBindDialog(String resultStr) { final TextEditingController plateNumberController = TextEditingController(); - DialogX.to.showNoticeDialog( - icon: DialogIcon.info, + // 使用 showConfirmDialog,它有 onCancel 回调 + DialogX.to.showConfirmDialog( title: '请输入车牌号', barrierDismissible: false, content: TextField( - controller: plateNumberController, // 绑定 controller - autofocus: false, // 弹窗出现时自动获取焦点,方便用户直接输入 + controller: plateNumberController, + autofocus: false, decoration: const InputDecoration( hintText: '请输入完整的车牌号', border: OutlineInputBorder(), contentPadding: EdgeInsets.symmetric(horizontal: 12.0), ), ), - confirmText: '确认', + confirmText: '确认绑定', + cancelText: '取消', // showConfirmDialog 有 cancelText onConfirm: () { final String plateNumber = plateNumberController.text.trim(); if (plateNumber.isEmpty) { - resumeScanner(); showToast("请输入车牌号"); - return; + // 返回 false 可以阻止弹窗关闭,让用户继续输入 + return false; } renderResult(resultStr, plateNumber: plateNumber); + //关闭弹窗 + return true; + }, + onCancel: () { + // 如果用户点击取消,恢复扫描 + resumeScanner(); }, ); } @override void onClose() { - qrViewController?.dispose(); + scannerController.dispose(); animationController.dispose(); super.onClose(); } } + diff --git a/ln_jq_app/lib/pages/qr_code/view.dart b/ln_jq_app/lib/pages/qr_code/view.dart index df58a84..2fe4d59 100644 --- a/ln_jq_app/lib/pages/qr_code/view.dart +++ b/ln_jq_app/lib/pages/qr_code/view.dart @@ -1,148 +1,155 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:getx_scaffold/getx_scaffold.dart'; -import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; +import 'package:ln_jq_app/common/styles/theme.dart'; +import 'package:mobile_scanner/mobile_scanner.dart'; import 'controller.dart'; class QrCodePage extends GetView { - const QrCodePage({Key? key}) : super(key: key); + const QrCodePage({super.key}); @override Widget build(BuildContext context) { - return GetBuilder( - init: QrCodeController(), - id: 'qrcode', - builder: (_) { - return Scaffold( - extendBodyBehindAppBar: true, - appBar: AppBar( - title: const Text('扫码', style: TextStyle(color: Colors.white)), - centerTitle: true, - backgroundColor: Colors.transparent, - elevation: 0, - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios, color: Colors.white), - onPressed: () => Get.back(), + Get.put(QrCodeController()); + return Scaffold( + extendBodyBehindAppBar: true, + appBar: AppBar( + title: const Text('扫码', style: TextStyle(color: Colors.white)), + centerTitle: true, + backgroundColor: Colors.transparent, + elevation: 0, + leading: IconButton( + icon: const Icon(Icons.arrow_back_ios, color: Colors.white), + onPressed: () => Get.back(), + ), + actions: [ + TextButton( + onPressed: controller.requestPhotoPermission, + child: const Text('相册', style: TextStyle(color: Colors.white, fontSize: 16)), + ), + ], + ), + body: Stack( + alignment: Alignment.center, + children: [ + // 1. 使用 MobileScanner 作为扫描视图 + MobileScanner( + controller: controller.scannerController, + onDetect: controller.onDetect, + // 您可以自定义扫描框的样式 + scanWindow: Rect.fromCenter( + center: Offset( + MediaQuery.of(context).size.width / 2, + MediaQuery.of(context).size.height / 2 - 50, + ), + width: 250, + height: 250, ), - actions: [ - TextButton( - onPressed: controller.requestPhotoPermission, - child: const Text( - '相册', - style: TextStyle(color: Colors.white, fontSize: 16), - ), - ), - ], ), - body: Stack( - children: [ - _buildQrView(context), - Positioned( - bottom: 80.h, - left: 0, - right: 0, - child: _buildControlButtons(), - ), - ], - ), - ); - }, + // 扫描动画和覆盖层 + _buildScannerOverlay(context), + // 底部的功能按钮 + Positioned(bottom: 80, left: 0, right: 0, child: _buildActionButtons()), + ], + ), ); } - /// 构建二维码扫描视图(带动画) - Widget _buildQrView(BuildContext context) { - // 定义扫描区域的大小 - var scanArea = (MediaQuery.of(context).size.width < 400 || - MediaQuery.of(context).size.height < 400) - ? 250.0 - : 300.0; - + /// 构建扫描区域的覆盖层和动画 + Widget _buildScannerOverlay(BuildContext context) { + // 模拟扫描框的位置和大小 + const double scanAreaSize = 250.0; return Stack( - alignment: Alignment.center, - children: [ - // 底层是相机视图和半透明遮罩 - QRView( - key: controller.qrKey, - onQRViewCreated: controller.onQRViewCreated, - overlay: QrScannerOverlayShape( - borderColor: Colors.blueAccent, - borderRadius: 10, - borderLength: 30, - borderWidth: 10, - cutOutSize: scanArea, - ), - ), - // 上层是扫描动画 - AnimatedBuilder( - animation: controller.scanAnimation, - builder: (context, child) { - return Positioned( - // 计算扫描框的顶部位置,以便动画从顶部开始 - top: (MediaQuery.of(context).size.height - scanArea) / 2, - child: Transform.translate( - offset: Offset(0, controller.scanAnimation.value * scanArea), + children: [ + // 半透明的覆盖层 + ColorFiltered( + colorFilter: ColorFilter.mode(Colors.black.withOpacity(0.5), BlendMode.srcOut), + child: Stack( + children: [ + Container(decoration: const BoxDecoration(color: Colors.transparent)), + Align( + alignment: Alignment.center, child: Container( - width: scanArea, - height: 2, // 扫描线的高度 + margin: const EdgeInsets.only(bottom: 100), // 微调位置 + width: scanAreaSize, + height: scanAreaSize, decoration: BoxDecoration( - color: Colors.blueAccent, - boxShadow: [ - BoxShadow( - color: Colors.blueAccent.withOpacity(0.7), - blurRadius: 8, - spreadRadius: 2, - ), - ], + color: Colors.black, + borderRadius: BorderRadius.circular(12), ), ), ), - ); - }, + ], + ), + ), + // 扫描动画 + Align( + alignment: Alignment.center, + child: Container( + margin: const EdgeInsets.only(bottom: 100), + width: scanAreaSize, + height: scanAreaSize, + child: AnimatedBuilder( + animation: controller.scanAnimation, + builder: (context, child) { + return CustomPaint( + painter: ScannerAnimationPainter( + controller.scanAnimation.value, + AppTheme.themeColor, + ), + ); + }, + ), + ), ), ], ); } - /// 构建底部的控制按钮 - Widget _buildControlButtons() { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - '将二维码/条形码放入框内,即可自动扫描', - style: TextStyle(color: Colors.white, fontSize: 14), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - // 闪光灯按钮 - _buildIconButton( - onPressed: controller.toggleFlash, - //闪光灯状态的变化 - child: Obx(() => Icon( - controller.isFlashOn.value ? Icons.flash_on : Icons.flash_off, - color: Colors.white, - size: 28, - )), - ), - // 翻转相机按钮 - _buildIconButton( - onPressed: controller.flipCamera, - child: const Icon( - Icons.flip_camera_ios, - color: Colors.white, - size: 28, + /// 构建底部的功能按钮(闪光灯、相册) + Widget _buildActionButtons() { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + '将二维码/条形码放入框内,即可自动扫描', + style: TextStyle(color: Colors.white, fontSize: 14), + ), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // 闪光灯按钮 + _buildIconButton( + onPressed: controller.toggleFlash, + //闪光灯状态的变化 + child: Obx( + () => IconButton( + icon: Icon( + controller.isFlashOn.value ? Icons.flash_on : Icons.flash_off, + color: Colors.white, + size: 28, + ), + onPressed: controller.toggleFlash, + ), + ), ), - ), - ], - ), - ], - ); - } + // 翻转相机按钮 + _buildIconButton( + onPressed: controller.flipCamera, + child: const Icon( + Icons.flip_camera_ios, + color: Colors.white, + size: 28, + ), + ), + ], + ), + ], + ); + } + Widget _buildIconButton({required VoidCallback onPressed, required Widget child}) { return Container( @@ -158,3 +165,71 @@ class QrCodePage extends GetView { ); } } + +/// 扫描动画的绘制器 +class ScannerAnimationPainter extends CustomPainter { + final double value; + final Color borderColor; + + ScannerAnimationPainter(this.value, this.borderColor); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = borderColor + ..strokeWidth = 3 + ..style = PaintingStyle.stroke; + + final cornerLength = 20.0; + // 绘制四个角的边框 + // Top-left + canvas.drawPath( + Path() + ..moveTo(0, cornerLength) + ..lineTo(0, 0) + ..lineTo(cornerLength, 0), + paint, + ); + // Top-right + canvas.drawPath( + Path() + ..moveTo(size.width - cornerLength, 0) + ..lineTo(size.width, 0) + ..lineTo(size.width, cornerLength), + paint, + ); + // Bottom-left + canvas.drawPath( + Path() + ..moveTo(0, size.height - cornerLength) + ..lineTo(0, size.height) + ..lineTo(cornerLength, size.height), + paint, + ); + // Bottom-right + canvas.drawPath( + Path() + ..moveTo(size.width - cornerLength, size.height) + ..lineTo(size.width, size.height) + ..lineTo(size.width, size.height - cornerLength), + paint, + ); + + // 绘制扫描线 + final linePaint = Paint() + ..color = borderColor.withOpacity(0.8) + ..strokeWidth = 2 + ..shader = LinearGradient( + colors: [borderColor.withOpacity(0), borderColor, borderColor.withOpacity(0)], + stops: const [0.0, 0.5, 1.0], + ).createShader(Rect.fromLTWH(0, 0, size.width, size.height)); + + final y = size.height * value; + canvas.drawLine(Offset(0, y), Offset(size.width, y), linePaint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/ln_jq_app/pubspec.lock b/ln_jq_app/pubspec.lock index 018266c..c978e01 100644 --- a/ln_jq_app/pubspec.lock +++ b/ln_jq_app/pubspec.lock @@ -65,14 +65,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.4.0" - charset: - dependency: transitive - description: - name: charset - sha256: "27802032a581e01ac565904ece8c8962564b1070690794f0072f6865958ce8b9" - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.1" clock: dependency: transitive description: @@ -733,6 +725,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.0" + mobile_scanner: + dependency: "direct main" + description: + name: mobile_scanner + sha256: c6184bf2913dd66be244108c9c27ca04b01caf726321c44b0e7a7a1e32d41044 + url: "https://pub.flutter-io.cn" + source: hosted + version: "7.1.4" modal_bottom_sheet: dependency: transitive description: @@ -925,14 +925,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "6.0.3" - qr_code_scanner_plus: - dependency: "direct main" - description: - name: qr_code_scanner_plus - sha256: b764e5004251c58d9dee0c295e6006e05bd8d249e78ac3383abdb5afe0a996cd - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.14" rational: dependency: transitive description: @@ -1234,14 +1226,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.1.3" - zxing_lib: - dependency: "direct main" - description: - name: zxing_lib - sha256: f9170470b6bc947d21a6783486f88ef48aad66fc1380c8acd02b118418ec0ce0 - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.4" sdks: dart: ">=3.9.0 <4.0.0" flutter: ">=3.35.0" diff --git a/ln_jq_app/pubspec.yaml b/ln_jq_app/pubspec.yaml index 93d5242..9acd578 100644 --- a/ln_jq_app/pubspec.yaml +++ b/ln_jq_app/pubspec.yaml @@ -43,10 +43,9 @@ dependencies: flutter_native_splash: ^2.4.7 dropdown_button2: ^2.3.8 - qr_code_scanner_plus: ^2.0.14 image_picker: ^1.2.1 # 用于从相册选择图片 image: ^4.5.4 - zxing_lib: ^1.1.4 + mobile_scanner: ^7.1.4 flutter_pdfview: 1.4.3 #显示pdf photo_view: ^0.15.0 #操作图片 flutter_inappwebview: ^6.1.5 # WebView插件