diff --git a/marking_app/lib/components/PictureOverview.dart b/marking_app/lib/components/PictureOverview.dart index 447df53..e7cc533 100644 --- a/marking_app/lib/components/PictureOverview.dart +++ b/marking_app/lib/components/PictureOverview.dart @@ -46,7 +46,8 @@ import 'dart:ui' as ui; import 'package:uuid/uuid.dart'; import 'package:zoom_widget/zoom_widget.dart'; -// import 'package:zoom_widget/zoom_widget.dart'; + +import '../pages/marking/provider/draw_marking_provider.dart'; part 'PictureOverview.g.dart'; typedef PageChanged = void Function(int index); @@ -100,6 +101,10 @@ class PictureOverviewState extends ConsumerState with CommonMix late RemoveListener _annotationsListener; // 批注关闭监听 File? temFile; // 批注临时数据 + // 用于记录绘图结果的变量 + Offset? globalPosition; // 是否正在绘制 + MarkingHistoryZoomInfo? zoomInfo; + @override void initState() { super.initState(); @@ -108,7 +113,7 @@ class PictureOverviewState extends ConsumerState with CommonMix bool flag = value.questionNum == widget.questionNum && value.markingUserId == widget.markingUserId; if (flag) { if (value.positionX != 0 && value.positionY != 0) { - zoomOffset = Offset(value.positionX, value.positionY); + // zoomOffset = Offset(value.positionX, value.positionY); } if (value.scale < 1) { initScale = value.scale; @@ -127,7 +132,6 @@ class PictureOverviewState extends ConsumerState with CommonMix @override void dispose() { - super.dispose(); _annotationsListener(); try { _imageStream?.removeListener(_imageStreamListener!); @@ -135,7 +139,9 @@ class PictureOverviewState extends ConsumerState with CommonMix bool flieExist = temFile!.existsSync(); if (flieExist) temFile!.delete(); } + if (zoomOffset != null) saveZoomPosition(); } catch (e) {} + super.dispose(); } Future saveImage() async { @@ -208,21 +214,51 @@ class PictureOverviewState extends ConsumerState with CommonMix FastData.getInstance().setMarkingZoomInfo(info); } + void saveZoomPosition() async { + MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); + if (historyZoomInfo != null) { + FastData.getInstance().setMarkingZoomInfo(MarkingHistoryZoomInfo( + scale: historyZoomInfo.scale, + positionX: zoomOffset!.dx, + positionY: zoomOffset!.dy, + questionNum: historyZoomInfo.questionNum, + markingUserId: historyZoomInfo.markingUserId, + )); + } + } + + void onPanUpPosition(Offset val) async { + print('**************** 正在移动位置 YYY:${val.dy}'); + print('**************** 正在移动位置 XXX:${val.dx}'); + zoomOffset = val; + } + // 缩放组件 ==> 缩放监听 - void onScaleUpdate(double scale, double scale1) async { - print('这是第一个scale:$scale'); - print('这是第二个noScale:$scale1'); + void onScaleUpdate(double scale, double zoom) async { + print('zoom:$zoom'); + print('scale:${scale}'); // MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); MarkingHistoryZoomInfo? historyZoomInfo = await FastData.getInstance().getMarkingZoomInfo(); double positionX = historyZoomInfo?.positionX ?? 0; double positionY = historyZoomInfo?.positionY ?? 0; MarkingHistoryZoomInfo info = MarkingHistoryZoomInfo( - scale: scale1, + scale: zoom, positionX: positionX, positionY: positionY, questionNum: widget.questionNum, markingUserId: widget.markingUserId, ); + zoomInfo = info; + if (imagInfoModel != null) { + imagInfoModel = TestQuestionsImageInfo( + // 获取图片的宽高 + boxHeight: imagInfoModel!.boxHeight, + boxWidth: imagInfoModel!.boxWidth, + url: imagInfoModel!.url, + height: imagInfoModel!.height * zoom, + width: imagInfoModel!.width * zoom, + ); + } FastData.getInstance().setMarkingZoomInfo(info); } @@ -237,6 +273,7 @@ class PictureOverviewState extends ConsumerState with CommonMix double containerWidth = constraints.maxWidth; double containerHeight = constraints.maxHeight; + print('LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL'); return $LocalAndNetworkSwitch( zoomGlobalKey: zoomGlobalKey, containerWidth: containerWidth, @@ -254,7 +291,8 @@ class PictureOverviewState extends ConsumerState with CommonMix temFile = file; print('更新需要上传的文件'); }, - imageBuilder: (context, imageProvider) { + imageBuilder: (imageBuilderContext, imageProvider) { + print('PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP'); Image imageWidget = Image(image: imageProvider, fit: BoxFit.fitWidth); if (imagInfoModel == null || (imagInfoModel?.boxHeight != containerHeight || imagInfoModel?.boxWidth != containerWidth)) { if (_imageStreamListener != null) _imageStream?.removeListener(_imageStreamListener!); @@ -276,19 +314,83 @@ class PictureOverviewState extends ConsumerState with CommonMix } // return imageWidget; - return Zoom( - // initTotalZoomOut: true, - child: imageWidget, - maxZoomWidth: containerWidth, - canvasColor: Colors.transparent, - backgroundColor: Colors.transparent, - maxZoomHeight: imagInfoModel?.scaleHeight, - initScale: initScale ?? 1, - initPosition: zoomOffset, - // initPosition: , - // onPositionUpdate: onPositionUpdate, - onScaleUpdate: onScaleUpdate, - // zoomSensibility: 0.5, + return Listener( + behavior: HitTestBehavior.opaque, + onPointerMove: (PointerMoveEvent details) { + return; + if (globalPosition != null) { + // 预防双指同时作用于屏幕 + double dx = globalPosition!.dx; + double dy = globalPosition!.dy; + + double dxNew = details.localPosition.dx; + double dyNew = details.localPosition.dy; + if ((dxNew - dx).abs() > 22 || (dyNew - dy).abs() > 22) return; + } + globalPosition = details.localPosition; + // Offset localPosition = (context.findRenderObject() as RenderBox).globalToLocal(details.localPosition); + // if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { + + Offset localPosition = globalPosition!; + // if (imagInfoModel?.scaleHeight != null) { + // localPosition = Offset(localPosition.dx, localPosition.dy - imagInfoModel!.scaleHeight!); + // } + + double remainingHeight = imagInfoModel!.imageHeightOffsetStart!; // 剩余高度 + var _scaleY = (zoomInfo?.scale ?? 1); + if (remainingHeight > 1) { + localPosition = Offset(localPosition.dx, localPosition.dy - remainingHeight); + } + + if (zoomOffset != null) { + // localPosition = Offset(localPosition.dx - (zoomOffset?.dx ?? 0), localPosition.dy); + } + + print('移动位置 zoomOffset==>dx:${zoomOffset?.dx}'); + print('移动位置 zoomOffset==>dy:${zoomOffset?.dy}'); + + print('缩放的比例:${_scaleY}'); + print('原本的dy:${globalPosition?.dy}'); + print('原本的dx:${globalPosition?.dx}'); + print('本来的Y轴:${localPosition.dy}'); + print('还原后的Y轴:${localPosition.dy * _scaleY}'); + + var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser, data: localPosition)); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal)); + }, + onPointerDown: (PointerDownEvent event) { + print('手指按下....${event.pointer}'); + }, + onPointerUp: (PointerUpEvent details) { + print('离开.............'); + return; + globalPosition = null; + // if (graffitiSwitch.openBrush || graffitiSwitch.openEraser) { + // var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); + // ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal)); + // } + + var newVal = ref.read(drawMarkingProvider).data..add(GestureRecording(eraser: graffitiSwitch.openEraser)); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(newVal)); + }, + child: Zoom( + // initTotalZoomOut: true, + child: ExamPaperDrawing( + key: examPaperDrawingKey, + globalKey: theglobalKey, + child: imageWidget, + graffitiSwitch: graffitiSwitch, + decoration: const BoxDecoration(color: const Color.fromRGBO(249, 250, 254, 1)), + ), + maxZoomWidth: containerWidth, + canvasColor: Colors.transparent, + backgroundColor: Colors.transparent, + maxZoomHeight: imagInfoModel?.scaleHeight, + initScale: initScale ?? 1, + initPosition: zoomOffset, + onScaleUpdate: onScaleUpdate, + onPositionUpdate: onPanUpPosition, + ), ); }, ); @@ -300,24 +402,16 @@ class PictureOverviewState extends ConsumerState with CommonMix // 试卷绘制 class ExamPaperDrawing extends StatefulHookConsumerWidget { // String imgUrl; - bool homework; + Widget child; BoxDecoration? decoration; AnnotationGraffitiSwitch graffitiSwitch; - List? points; - List? pointsPureData; - ValueNotifier> imageLoaded; - Widget child; GlobalKey globalKey; // Function(String) imageCall; ExamPaperDrawing({ // required this.imgUrl, - required this.homework, - required this.points, - required this.pointsPureData, + required this.child, required this.graffitiSwitch, required this.globalKey, - required this.imageLoaded, - required this.child, this.decoration, Key? key, }) : super(key: key); @@ -328,19 +422,19 @@ class ExamPaperDrawing extends StatefulHookConsumerWidget { class _ExamPaperDrawingState extends ConsumerState with EventBusMixin { // 用于记录手指位置的变量 - late List points; - late List pointsPureData; - // 用于记录绘图结果的变量 - Offset? globalPosition; // 是否正在绘制 + late RemoveListener removeListener; + late ValueNotifier> _vnHandWritings; + late List pointsPureData = []; @override void initState() { - points = widget.points ?? []; - pointsPureData = widget.pointsPureData ?? []; + _vnHandWritings = ValueNotifier>([]); + removeListener = ref.read(drawMarkingProvider.notifier).addListener((state) => _vnHandWritings.value = [...state.data], fireImmediately: false); + // 事件总线监听 eventOn(callback: (BottomAnnotationSwitchCleanall item) { if (item.previousStep) { - if (points.isEmpty) { + if (_vnHandWritings.value.isEmpty) { ToastUtils.showInfo('批注已清空'); return; } @@ -348,14 +442,15 @@ class _ExamPaperDrawingState extends ConsumerState with EventB if (index != -1) { if (index + 1 == pointsPureData.length) { pointsPureData = pointsPureData.sublist(0, index); - points.sublist(0, index); + + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index))); index = pointsPureData.toList().lastIndexOf(null); index == -1 ? -1 : index + 1; } if (index != -1) { pointsPureData = pointsPureData.sublist(0, index); - points = points.sublist(0, index); - toUpState(setState, () {}, mounted); + _vnHandWritings.value = _vnHandWritings.value.sublist(0, index); + ref.read(drawMarkingProvider.notifier).setState(DrawMarkingVal(ref.read(drawMarkingProvider).data.sublist(0, index))); } else { item.cleanAll = true; } @@ -366,8 +461,7 @@ class _ExamPaperDrawingState extends ConsumerState with EventB if (item.cleanAll) { pointsPureData.clear(); - points.clear(); - toUpState(setState, () {}, mounted); + _vnHandWritings.value.clear(); } if (item.uploadImage) { @@ -388,75 +482,47 @@ class _ExamPaperDrawingState extends ConsumerState with EventB @override void dispose() { - super.dispose(); eventCancel(); + removeListener(); + _vnHandWritings.dispose(); + super.dispose(); } @override Widget build(BuildContext context) { - return Listener( - behavior: HitTestBehavior.opaque, - onPointerMove: (PointerMoveEvent details) { - if (globalPosition != null) { - // 预防双指同时作用于屏幕 - double dx = globalPosition!.dx; - double dy = globalPosition!.dy; + print('_ExamPaperDrawingState的build....'); - double dxNew = details.localPosition.dx; - double dyNew = details.localPosition.dy; - if ((dxNew - dx).abs() > 22 || (dyNew - dy).abs() > 22) { - return; - } - } - globalPosition = details.localPosition; - try { - // if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { - RenderBox renderBox = context.findRenderObject() as RenderBox; - Offset localPosition = renderBox.globalToLocal(details.localPosition); - pointsPureData = List.from(pointsPureData)..add(localPosition); - points = List.from(points)..add(GestureRecording(eraser: widget.graffitiSwitch.openEraser, data: localPosition)); - setState(() {}); - // } - } catch (e) { - toPrint(val: '进入报错'); - } - }, - onPointerUp: (PointerUpEvent details) { - print('离开.............'); - globalPosition = null; - if (widget.graffitiSwitch.openBrush || widget.graffitiSwitch.openEraser) { - pointsPureData.add(null); // 增加空点以分隔不同的线段 - points.add(GestureRecording(eraser: widget.graffitiSwitch.openEraser)); - } - }, - child: RepaintBoundary( - key: widget.globalKey, - child: CustomPaint( - foregroundPainter: DrawingPainter(points: points), - child: widget.child, - ), + return RepaintBoundary( + key: widget.globalKey, + child: CustomPaint( + isComplex: true, + willChange: true, + foregroundPainter: DrawingPainter(ctrl: _vnHandWritings), + child: RepaintBoundary(child: widget.child), ), ); } } class DrawingPainter extends CustomPainter { - final List points; - DrawingPainter({required this.points}) : super(); - - final Paint paintBrush = Paint() - ..color = Colors.red - ..strokeCap = StrokeCap.round - ..strokeWidth = 1.5.r; + final ValueNotifier> ctrl; + final Paint paintBrush = Paint(); + DrawingPainter({required this.ctrl}) : super(repaint: ctrl) { + paintBrush + ..color = Colors.red + ..strokeCap = StrokeCap.round + ..strokeWidth = 1.5.r; + } @override void paint(Canvas canvas, Size size) { - print('数据.....................'); - for (int i = 0; i < points.length; i++) { + var points = ctrl.value; + var pointsLength = points.length; + print('数据.....................[[[[[${points.length}]]]]]'); + for (int i = 0; i < pointsLength; i++) { GestureRecording item = points[i]; - GestureRecording nextItem = points[i + 1]; Offset? offsetData = item.data; - Offset? nextOffsetData = nextItem.data; + Offset? nextOffsetData = pointsLength - 1 == i ? null : points[i + 1].data; if (offsetData != null && nextOffsetData != null) { canvas.drawLine(offsetData, nextOffsetData, paintBrush); } @@ -464,8 +530,16 @@ class DrawingPainter extends CustomPainter { } @override - bool shouldRepaint(DrawingPainter oldDelegate) { - return oldDelegate.points.length != points.length || oldDelegate.points != points; + bool shouldRepaint(covariant CustomPainter oldDelegate) { + print('FFFFFF55555555555555'); + // if (oldDelegate is DrawingPainter) { + // var repaint = ctrl.value.length != oldDelegate.ctrl.value.length || oldDelegate.ctrl.value != ctrl.value; + // print('调用是否绘制:$repaint'); + + // return repaint; + // } + + return false; } } @@ -525,51 +599,6 @@ Widget $myCachedNetworkImage({ ); }, ); - - // return Container( - // width: width, - // height: height, - // color: Colors.red, - // alignment: Alignment.center, - // child: tempFile != null - // ? Image.file( - // tempFile, - // fit: BoxFit.contain, - // width: double.infinity, - // height: double.infinity, - // ) - // : CachedNetworkImage( - // key: _useImgRefsh.imageKey.value, - // fit: BoxFit.contain, - // width: double.infinity, - // // height: double.infinity, - // imageUrl: imageUrl, - // placeholder: (context, url) => - // Center(child: SpinKitWave(color: Theme.of(context).primaryColor, size: 50.r)), - // // imageBuilder: (context, imageProvider) => Container( - // // decoration: BoxDecoration( - // // image: DecorationImage( - // // image: imageProvider, - // // fit: BoxFit.fitWidth, - // // // colorFilter: ColorFilter.mode(Colors.red, BlendMode.colorBurn), - // // ), - // // ), - // // ), - // errorWidget: (context, url, error) { - // return GestureDetector( - // onTap: () => (_useImgRefsh.imageKey.value = UniqueKey()), - // child: Column( - // mainAxisSize: MainAxisSize.min, - // crossAxisAlignment: CrossAxisAlignment.center, - // children: [ - // Image.asset('assets/images/test_paper_loading_failed.png'), - // quickText('加载失败,点击重试', color: Color.fromRGBO(148, 163, 182, 1), size: 12.sp), - // ], - // ), - // ); - // }, - // ), - // ); } class CacheNetImageView extends ConsumerWidget { @@ -679,22 +708,12 @@ Widget $localAndNetworkSwitch( }, []); print('是否更新视图.... ${_useZoomHistory.initPosition.value}'); - return ExamPaperDrawing( - graffitiSwitch: graffitiSwitch, - points: _useSwitch.points.value, - pointsPureData: _useSwitch.pointsPureData.value, - decoration: const BoxDecoration(color: const Color.fromRGBO(249, 250, 254, 1)), - globalKey: theglobalKey, - key: examGlobalKey, - imageLoaded: _useSwitch.imageLoaded, - homework: homework, - child: $MyCachedNetworkImage( - imageUrl: imageUrl, - tempFile: _useSwitch.temFile.value, - width: containerWidth, - height: containerHeight, - imageBuilder: imageBuilder, - ), + return $MyCachedNetworkImage( + imageUrl: imageUrl, + tempFile: _useSwitch.temFile.value, + width: containerWidth, + height: containerHeight, + imageBuilder: imageBuilder, ); } @@ -758,7 +777,7 @@ class UseLocalAndNetworkSwitch { temFile.value?.delete(); temFile.value = file; // 保存临时文件 - points.value = examGlobalKey.currentState?.points; + points.value = examGlobalKey.currentState?._vnHandWritings.value; pointsPureData.value = examGlobalKey.currentState?.pointsPureData; toPrint(val: '图片保存成功:'); return temFile.value; diff --git a/marking_app/lib/pages/marking/do_papers.dart b/marking_app/lib/pages/marking/do_papers.dart index 335bdf4..f1738e2 100644 --- a/marking_app/lib/pages/marking/do_papers.dart +++ b/marking_app/lib/pages/marking/do_papers.dart @@ -1916,7 +1916,7 @@ class _MarkingPapersState extends ConsumerState children: [ // 试卷 Container( - margin: EdgeInsets.only(top: 6.h), + // margin: EdgeInsets.only(top: 6.h), padding: EdgeInsets.symmetric(horizontal: 1.w), child: PictureOverview( questionNum: data.questionNum, diff --git a/marking_app/lib/pages/marking/provider/draw_marking_provider.dart b/marking_app/lib/pages/marking/provider/draw_marking_provider.dart new file mode 100644 index 0000000..e1f8239 --- /dev/null +++ b/marking_app/lib/pages/marking/provider/draw_marking_provider.dart @@ -0,0 +1,29 @@ +/* + * @Author: wangyang 1147192855@qq.com + * @Date: 2022-07-14 18:16:06 + * @LastEditors: wangyang 1147192855@qq.com + * @LastEditTime: 2022-08-01 16:17:33 + * @FilePath: \marking_app\lib\provider\user_provider.dart + * @Description: APP上传文件状态 + */ + +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import '../../../components/PictureOverview.dart'; + +// 评分进度还是批阅进度 +final drawMarkingProvider = StateNotifierProvider((ref) => DrawMarkingProviderHandle(DrawMarkingVal([]))); + +class DrawMarkingProviderHandle extends StateNotifier { + DrawMarkingProviderHandle(DrawMarkingVal val) : super(val); + + void setState(DrawMarkingVal val) { + state = val; + } +} + +class DrawMarkingVal { + List data; + + DrawMarkingVal(this.data); +}